Update Mr Wizard's answer gives pixel-perfect results, but it is Windows-only and destroys the clipboard contents. My answer should work on any platform, but it's less precise: e.g. it omits In/Out labels. It does allow setting the rasterization width though.
This problem came up when I was trying to make a preview window for an image uploader (see the end of that answer).
I would like to create a palette button that will upload the current notebook selection as an image. Before uploading, I would like to show a preview of the image, to reduce the chance of something going awry before contacting the server.
This is what I have so far (includes only the preview code, not the uploader):
button = Button[
"Preview",
Module[
{expr = NotebookRead#InputNotebook[]},
If[expr =!= {},
With[{img = Rasterize[expr]},
MessageDialog[
Column[{"Would you like to perform the action?", img}],
{"Do it!" :> doIt[img], "Cancel" :> Null}
]
]
]
]
]
In case you are wondering why I used a nested With inside the Module instead of making img a module-variable too: it's because by the time doIt[img] is evaluated, the local module variables will have been cleared, so I need to substitute the rasterized expression directly into the doIt function,
This button works (more or less). You can try it by creating a graphic in the same notebook (e.g. Graphics[Circle[]]), selecting it using a single click, then clicking the Preview button.
However, if I put it in a palette using CreatePalette[button], then the rasterization will happen for the window-width of the palette, and I get something like this:
How can I control the width of rasterization, or more generally, how can I create a preview dialog for the uploader that avoids this issue?
For an additional improvement, it would be nice to be able to size the message window so it fits the preview image (and still shows the button: the button disappears with WindowSize -> All).
Answers
Mr. Wizard's suggestion:
button = Button[
"Preview", (FrontEndExecute[
FrontEndToken[FrontEnd`SelectedNotebook[], "CopySpecial", "MGF"]];
MessageDialog[
First#Cases[NotebookGet#ClipboardNotebook[],
RasterBox[data_, ___] :>
Image[data, "Byte", ColorSpace -> "RGB", Magnification -> 1],
Infinity]])]
CreatePalette[button]
Problems: It (probably) only works on Windows, and it destroys the clipboard contents.
If it is practical to use the clipboard in this operation you might use: FrontEnd`CopySpecial["MGF"] (copy as bitmap).
I managed to do this by copying the selection to a new notebook, rasterizing the full notebook, then closing it.
CreatePalette#Button["Preview",
Module[{target},
target =
CreateDocument[{}, WindowSelected -> False, Visible -> False];
NotebookWrite[target, NotebookRead[SelectedNotebook[]]];
CreateDialog[{Rasterize[target], DefaultButton[]}];
NotebookClose[target]
]
]
The WindowSize -> 500 option can be added to CreateDocument to set the rasterization width to 500 pixels.
Note some disadvantages (advantages in some cases) of this method compared to copying as bitmap:
Custom styles are lost
In/Out labels are lost
Notebook magnification value is lost
If there's a need, some of these can be remedied by explicitly transferring some notebook options from the SelectedNotebook to the newly created one.
I think this should work without you needing to make a new notebook:
button = Button["Preview",
Module[{expr = NotebookRead#InputNotebook[]},
If[expr =!= {},
With[{img =
Rasterize[expr,
ImageFormattingWidth ->
First#(WindowSize /.
AbsoluteOptions[InputNotebook[], WindowSize])]},
MessageDialog[
Column[{"Would you like to perform the action?",
img}], {"Do it!" :> doIt[img], "Cancel" :> Null},
WindowSize -> {First#ImageDimensions#img, All}]]]]];
CreateDialog[button,
WindowFloating -> True,
WindowClickSelect -> False,
Selectable -> False
]
I used a little option searcher to find ImageFormattingWidth and by passing the image width as the window width you can make the dialog fit the picture nicely and still display the button.
Here's a demo of its results:
Rasterizing a cell from a pallete
Have you tried using ExportString[] to create the graphic into memory? (technically into a temp file, but what do you care:] )
ExportString[your_mathematica_stuff_here,"PNG",Background->None]
See the output on a colored background to verify transparent BG:
Framed[ImportString[ExportString[x^2,"PNG",Background->None]
,"PNG"]
,Background->Yellow]
For images with many color variations (like 3D plots), I recommend JPEG2000 format, and for solid-colored images where transparency is not necessary, use GIF to preserve color detail.
Yes, you can control ImageSize when you export string of the image.
Related
I realize win32 toolbar icon questions are common here, but none are relevant to my particular problem (most concern image lists, or associating with a bitmap handle).
I am trying to associate a toolbar button with an icon resource within my application. Since I am adding it to a toolbar that already has default images using TB_ADDBITMAP (new, open, save, etc), I cannot use an image list, as the article on MSDN says here:
The TB_SETIMAGELIST message cannot be combined with TB_ADDBITMAP. It also cannot be used with toolbars created with CreateToolbarEx, which calls TB_ADDBITMAP internally. When you create a toolbar with CreateToolbarEx or use TB_ADDBITMAP to add images, the toolbar manages the image list internally. Attempting to modify it with TB_SETIMAGELIST has unpredictable consequences.
MSDN says I should be able to use a resource directly with TB_ADDBITMAP, under the TBADDBITMAP::nID field:
If hInst is NULL, set this member to the bitmap handle of the bitmap with the button images. Otherwise, set it to the resource identifier of the bitmap with the button images.
The VS2008 resource editor shows a single 16x16 icon resource with the id IDI_ARROWLEFT. (I had a screenshot, but since I do not have enough "reputation" to post images you'll have to take my word for it)
This is clearly a valid icon as the following code makes the icon appear on the titlebar of the main window:
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ARROWLEFT));
The problem is the resource icon is not appearing on the toolbar button within the window. Below is the sample code that is loading the resource and applying it to the toolbar button:
void populateToolbarTest()
{
int index = -1;
TBADDBITMAP tbab;
TBBUTTON tbb;
ZeroMemory(&tbab, sizeof(TBADDBITMAP));
ZeroMemory(&tbb, sizeof(TBBUTTON));
SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
tbab.hInst = hInst;
tbab.nID = IDI_ARROWLEFT;
// SendMessage returns 0 when testing
index = SendMessage(hWndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab);
if (index == -1) return;
tbb.iBitmap = index;
tbb.fsState = TBSTATE_ENABLED;
tbb.fsStyle = TBSTYLE_BUTTON;
// result is set to 1 when testing
LRESULT result = SendMessage(hWndToolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbb);
}
This code successfully produces a button. However, there is no icon displayed, unlike with the defaults that I used in IDB_STD_SMALL_COLOR
I finally got it working. Turns out, it had nothing to do with the code.
Microsoft is EXTREMELY picky about the EXACT format of the image being referenced. It you use TB_ADDBITMAP with a custom image, it MUST be 256 colors, it MUST have the MS-Specific index format, and the only color I've gotten to register as transparent is black. I spent an hour in Photoshop messing with different formats and colors before figuring this out.
The clue was the CreateMappedBitmap function in the example on MSDN. The page on CreateMappedBitmap had this statement:
This function is fully supported only for images with color maps; that is, images with 256 or fewer colors.
What it doesn't mention is that this is true regardless of whether you use this function or not. I have tried each scenario with and without this helper function, as well as tried every other 256-color BMP index format. Some other formats managed to show up, but they were mangled.
Theoretically, you can use the CreateMappedBitmap COLORMAP to specify a transparency color other than black, but I'm not familiar enough with the "6 level RGB" format to know how to specify an exact color.
(ref: http://en.wikipedia.org/wiki/List_of_software_palettes#6_level_RGB)
Unless you're mixing custom icons with default ones, I would recommend sticking with TB_SETIMAGELIST. From what I've read, it's much more flexible (for example, it accepts more than 256 colors.)
(ref: Win32 Toolbars and 24bit Images)
How do you make Mathematica export a Row of graphics. I do not like how GraphicsRow handles the graphics, all the aspect ratios and paddings in the figures get messed up. What I like to do is work with each individual figure and then use a simple Row,Column or Grid to combine my figures. Take the following for instance:
g1 = Plot[Sin[x], {x, -Pi, Pi},
Frame -> True, FrameLabel -> {"x", "y"}, ImageSize -> 2.6*72
]
This creates the Sin plot. What I want to do now is create the following Figure:
Fig = Row[{g1, g1, g1}]
Then you can use Export
Export["TestFig.pdf", Fig]
This is the pdf I obtain in MMA8:
I just tried this code in MMA7 and it works fine. It had been a while since I wanted to create this type of figures and I never bothered to check if it worked in MMA8. Does any one have a fix for this in MMA8?
The desired output is the one I obtained in MMA7:
It is worth bearing in mind that GraphicsGrid assumes equal-width columns so using Grid is sometimes more useful. The same syntax as in belisarius' answer applies. It might be worth exploring the ImageSize option to Export (see documentation and tutorial).
Also, note the exporting in PDF format uses the PrintingStyleEnvironment, which is not how things look on screen. You might get better results if you change your page setup in Printing Settings.
Export["c:\\TestFig.pdf", GraphicsGrid[{{g1, g1, g1}}]]
I would like to insert the output of a web page into a notebook (essentially a text or html "screen capture"). No need for it to be "live", it is just there for reference.
Ideally it would appear much like it does on a web-browser. I want it to be non-evaluatable and I don't want the front end to be trying to format it as a very error ridden Mathematica expression
(EDIT to add: creating a cell and doing "Cell->Convert To->Text Display" is a good-enough way of getting text displayed without the front end reformatting things. I am wondering if this is the "right" way to do this or if there is a better way, especially if I'd like to have html formatting or graphics too)
As far as I know Mathematica isn't able to render HTML pages. Using Import you can get all kinds of things out of html based sites and files. One option is to get a text based version of the site like this:
Import["http://reference.wolfram.com/mathematica/guide/Mathematica.html", "Plaintext"]
If you are on Windows (with .NET), then you could use Mathematica's NETLink functionality in conjunction with the WebBrowser class to capture a screenshot of a web page:
Needs["NETLink`"]
LoadNETType["System.Drawing.Imaging.ImageFormat", AllowShortContext -> False]
LoadNETType["System.Windows.Forms.WebBrowserReadyState", AllowShortContext -> False]
Options[dotNetBrowserScreenshot] = {Width -> 1024, Height -> Automatic};
dotNetBrowserScreenshot[uri_, OptionsPattern[]] :=
NETBlock # Module[{browser, bitmap, tempFile, image, bounds}
, browser = NETNew["System.Windows.Forms.WebBrowser"]
; browser#Width = OptionValue[Width]
; browser#ScrollBarsEnabled = False
; browser#Navigate[uri]
; tempFile = Close#OpenWrite[]
; While[browser#ReadyState =!= System`Windows`Forms`WebBrowserReadyState`Complete
, Pause[0.05]
]
; bounds = browser#Document#Body#ClientRectangle
; browser#Height = OptionValue[Height] /. Automatic -> bounds#Height
; bitmap = NETNew["System.Drawing.Bitmap", browser#Width, browser#Height]
; browser#DrawToBitmap[bitmap, bounds]
; browser#Dispose[]
; bitmap#Save[tempFile, System`Drawing`Imaging`ImageFormat`Png]
; bitmap#Dispose[]
; image = Import[tempFile, "PNG"]
; DeleteFile[tempFile]
; image
]
Sample use:
The complete web page can be captured by using Height -> Automatic (which is the default). Note that the screenshot is being displayed at reduced magnification.
If you just want the text (possibly with styles), select the text on the web page, create a Text cell in Mathematica (cmd-7 on Mac), then paste.
One possibility is to convert the web-page to PDF and then Import this PDF file. This method should give a vector image of the original page that looks similar to what you see in the browser.
Another possibility is to make a screenshot of that web-page in a browser and insert it in the Notebook. It is also possible to make a "screenshot" with higher resolution than your monitor has by printing the web-page on some virtual printer which supports conversion to raster formats (LEADTOOLS ePrint is one of the best).
EDIT
An interesting alternative to making screenshots by hands is to use Google Web page thumbnails service. I do not know much on this but you can get encoded into JavaScript JPEG thumbnail of any web-page with an URL like
http://www.google.com/webpagethumbnail?r=2&f=2&s=300:585&query=wolfram&hl=ru&gl=us&c=11&d=http%3A%2F%2Fintegrals.wolfram.com%2F&b=1&j=google.vs.r&a=D57
This URL gives a file with the following element:
["data:image/jpeg;base64,"]
(<data> here is an acronym for encoded JPEG image data).
We can extract data in Mathematica in the following way:
data = Import[
"http://www.google.com/webpagethumbnail?r=2&f=2&s=300:585&query=\
wolfram&hl=ru&gl=us&c=11&d=http%3A%2F%2Fintegrals.wolfram.com%2F&b=1&\
j=google.vs.r&a=D57"];
imageData =
StringReplace[
data, __ ~~ "[\"data:image/jpeg;base64," ~~ x__ ~~ "\"]," ~~ __ :>
x]
I do not know how to convert imageData further but it is just a matter of knowing of JPEG format specification...
In case you are on OS X, ctrl+shift+cmd+4 results in the cursor changing to a cross with the current coordinates next to it; selecting an arbitrary rectangular area on the screen copies it to the clipboard, from which you can paste it into mma (as a raster graphic).
Surely there exist ways of doing this in other operating systems.
I'm currently creating my figures in matlab to embed themvia latex into a pdf for later printing. I save the figures and save them via the script export_fig! Now I wonder which is the best way to go:
Which size of the matlab figure window to chose
Which -m option to take for the script? It will change the resolution and the size of the image...
I'm wondering about those points in regards to the following two points:
When chosing the figure-size bigger, there are more tickmarks shown and the single point markers are better visible
When using a small figure and using a big -m option, I still have only some tickmarks
When I generate a image which is quite huge (e.g. resolution 300 and still 2000*2000px) and than embed it into the document: Does this than look ugly? Will this be embedded in a nice scaling mode or is it the same ugliness as if you upload a 1000*1000px image onto a homepage and embed it via the widht and height tags in html -> the browser displays it quite ugly because the browser doesn't do a real resize. So it looks unsharp and ugly.
Thanks in advance!
The MATLAB plots are internally described as vector graphics, and PDF files are also described using vector graphics. Rendering the plot to a raster format is a bad idea, because you end up having to choose resolution and end up with bigger files.
Just save the plot to EPS format, which can be directly embedded into a PDF file using latex. I usually save my MATLAB plots for publication using:
saveas(gcf, 'plot.eps', 'epsc');
and embed them directly into my latex file using:
\includegraphics[width=0.7\linewidth]{plot.eps}
Then, you only need to choose the proportion of the line the image is to take (in this case, 70%).
Edit: IrfanView and others (XnView) don't display EPS very well. You can open them in Adobe Illustrator to get a better preview of what it looks like. I always insert my plots this way and they always look exactly the same in the PDF as in MATLAB.
One bonus you also get with EPS is that you can actually specify a font size so that the text is readable even when you resize the image in the document.
As for the number of ticks, you can look at the axes properties in the MATLAB documentation. In particular, the XTick and YTick properties are very useful manually controlling how many ticks appear no matter what the window resolution is.
Edit (again): If you render the image to a raster format (such as PNG), it is preferable to choose the exact same resolution as the one used in the document. Rendering a large image (by using a big window size) and making it small in the PDF will yield bad results mainly because the size of the text will scale directly with the size of the image. Rendering a small image will obviously make for a very bad effect because of stretching.
That is why you should use a vector image format. However, the default MATLAB settings for figures produce some of the same problems as raster images: text size is not specified as a font size and the number of ticks varies with the window size.
To produce optimal plots in the final render, follow the given steps:
Set the figure's font size to a decent setting (e.g. 11pt)
Render the plot
Decide on number of ticks to get a good effect and set the ticks manually
Render the image to color EPS
In MATLAB code, this should look somewhat like the following:
function [] = nice_figure ( render )
%
% invisible figure, good for batch renders.
f = figure('Visible', 'Off');
% make plots look nice in output PDF.
set(f, ...
'DefaultAxesFontSize', 11, ...
'DefaultAxesLineWidth', 0.7, ...
'DefaultLineLineWidth', 0.8, ...
'DefaultPatchLineWidth', 0.7);
% actual plot to render.
a = axes('Parent', f);
% show whatever it is we need to show.
render(a);
% save file.
saveas(f, 'plot.eps', 'epsc');
% collect garbarge.
close(f);
end
Then, you can draw some fancy plot using:
function [] = some_line_plot ( a )
%
% render data.
x = -3 : 0.001 : +3;
y = expm1(x) - x - x.^2;
plot(a, x, y, 'g:');
title('f(x)=e^x-1-x-x^2');
xlabel('x');
ylabel('f(x)');
% force use of 'n' ticks.
n = 5;
xlimit = get(a, 'XLim');
ylimit = get(a, 'YLim');
xticks = linspace(xlimit(1), xlimit(2), n);
yticks = linspace(ylimit(1), ylimit(2), n);
set(a, 'XTick', xticks);
set(a, 'YTick', yticks);
end
And render the final output using:
nice_figure(#some_line_plot);
With such code, you don't need to worry about the window size at all. Notice that I haven't even showed the window for you to play with its size. Using this code, I always get beautiful output and small EPS and PDF file sizes (much smaller than when using PNG).
The only thing this solution does not address is adding more ticks when the plot is made larger in the latex code, but that can't be done anyways.
Is it possible to change the options of a Graphics object? Say you are working with a graphics object G2D as in the following picture
You can see from the InputForm of G2D that the PlotRange option is set to {{-0.025,1.025},{0,1.05}}. But later on on the code I decided to change the PlotRange option to a different one. What happens with the InputForm? The new option simply gets appended.
You can obtain the options set by a graphics object by using Options and AbsoluteOptions but I haven't found a way to change those options. The function SetOptions seemed like a likely candidate but it turns out that
this function only works with streams and functions. That is, it only allows to set the default behavior as they show in the examples.
If you want to clean up the set of options in the graphic, it's probably easiest to just construct the graphic anew. You can extract the main body of the graphic with First, and use DeleteDuplicates and Options to get the simplified list of options:
old = Graphics[{Blue, Disk[]}];
old = Show[old, ImageSize -> 1000];
old = Show[old, ImageSize -> 500];
old = Show[old, ImageSize -> 250];
old = Show[old, ImageSize -> 100]
InputForm[old]
new = Graphics[First[old],
DeleteDuplicates[Options[old], First[#] === First[#2] &]]
InputForm[new]
I've used Options because the options to Graphics can be, but aren't always, enclosed in a list, and Options will standardize the form.
I'd also like to point out that technically Show is prepending the option values, so the duplicated options aren't really harming anything, although they can make it harder to debug graphics output and slightly increase the size of the file.
You can also use SetOptions to change the default value for all graphics:
SetOptions[Graphics, Background -> Gray];
Graphics[Disk[]]