# Exporting graphics to PDF - huge file

I want to draw some basic surfaces, export them to PDF and include them in a LaTeX file. I create a simple 3D graphics object, for instance with

 ParametricPlot3D[{r Cos[\[Theta]], r Sin[\[Theta]], r^2}, {r, 0, 1}, {\[Theta], 0, 2 \[Pi]}]


then context-click on the graphics and select Save Graphic As ..., and save it as PDF.

The resulting PDF is 5MB large! When I include it in my LaTeX file it takes a long time to compile and to render in a PDF viewer.

I know that I can save it in another format such as PNG to get the file size down (in this case all the way to 33KB). But I'd prefer a vector format because my final product will be PDF. Are there some options to the Export[] command which might reduce the number of colors and make the exported file smaller?

-
This is one downfall of the new (since V6) graphics engine. The exported vector graphics (EPS or PDF) were very useful up to version 5. Would be very interested in a fix, too. Had to change a lot of my export stuff to sufficiently large rasterized images (for which the pdf export works pretty well, esp. with PDFLaTeX). –  Yves Klett Feb 9 '12 at 14:03
One way is to rasterize the surface but not the axes. See here. –  Alexey Popkov Feb 9 '12 at 14:21
Also see here. –  Eli Lansey Feb 9 '12 at 14:38
Are Wolfram aware of the problems with vector export? ...does anyone know ...@Brett?? –  Mike Honeychurch Feb 9 '12 at 22:24
Check also here: stackoverflow.com/questions/7953955/… –  Piotr Migdal Feb 13 '12 at 18:09

My preferred method to export graphics to pdf is to do something like

Export["figure.pdf", plot, "AllowRasterization" -> True,
ImageSize -> 360, ImageResolution -> 600]


This uses vectors for simple graphics, but produces a high resolution rasterized image if the plot becomes too complicated.

-
the documentation for AllowRasterization says "whether to rasterize a graphic that requires advanced versions of PDF". Do you know what is meant by advanced versions? Is that more recent versions than when Mma was written? I've had import problems with recent PDF formats and had to re-save them as "older" PDFs to get them to import. –  Mike Honeychurch Feb 9 '12 at 22:08
I hink this has the best chance of being close to foolproof, so I'm upvoting it. –  Jens Feb 10 '12 at 3:10
Very nice, upvoting. This also works on a whole notebook. So if bignb has head NotebookObject one can just do, e.g.: Export["tentimessmallerfile.pdf", bignb, "AllowRasterization" -> True, ImageResolution -> 300] –  Rolf Mertig Feb 16 '12 at 9:28
Making use of this now, thanks. –  rcollyer Nov 30 '12 at 15:49
If I want to export graphics to .eps instead of .pdf what should be changed to the Export[]; it's not working with .eps files, the size remains the same. –  Vaggelis_Z Aug 11 '13 at 12:52

Before you step into the same traps I once stepped, let me point out some key-points. First of all two things: 1. although I spend some time digging in the subject, my knowledge is far from being complete, keep this in mind. 2. as everyone else around here, I would really like to have a fast, good-looking export of vector graphics too. Unfortunately, we have none of those properties currently. Here are some issues I spend some time investigating:

1. The exported vector-graphics from Mathematica are more or less projection of the (OpenGL-)polygon-scene which is showed in the frontend. This has several disatvantages, first of all a huge amount of polygons is exported. Not only the visible ones, even when you don't use Opacity all polygons are exported. This does not only result in very big file-sizes, it is not uncommon, that those pdf-files need 10 minutes or longer to render in a pdf-viewer. This is simply impossible to use.

2. Altough the polygons share the same vertex-points, their edges are not completely opaque when rendered in a pdf-viewer. This might result from the alpha-blending which is done at points a line (or a polygon-border) does not lie completely on a pixel-position (which is almost never). This results in artifacts which let you see the polygon-structure. This problem is often discussed, since it happens in density-plots too. If the background is white and the polygons are infront of this background, this looks then like the image below. The situation gets worse when you have surface behind visible polygons. Then you kind of see the 3d-surface through like it would not be completely opaque. I discussed this issue some time ago with one of the developers of InkScape who (and others) was kind enough to explain what happens. You can find this discussion here

3. One particular thing which really bothers me even if I ignore the first two points are the mesh-lines. In the good old days mesh-lines represented really the underlying sampling. This is no longer the case, but since they are just so cute and everyone likes them, they are added to the 3d model. Unfortunately, this is not done correctly since it leads to serious display-error. Even in the above image the mesh-lines do not look equally thick, but taking a closer look shows the chaos:

## Idea for a solution

The main-idea is, that while I see the requirement for included text to be in vector-format, for the surface with its smooth lighting and color-gradients it would be enough to have a high-resolution raster image. So maybe we can extract them, transform the surface and put it back together, but how to do it? Like everywhere in science you can easily use the results of smart people who where kind enough to share the knowledge. So please look at the references.

So what you could do is that you plot your Graphics as usual

size = 800;
g = ParametricPlot3D[{r Cos[\[Theta]], r Sin[\[Theta]], r^2}, {r, 0,
1}, {\[Theta], 0, 2 \[Pi]}, ImageSize -> size];


The next step is to take the Graphics3D and use only the surface without the axes and the box. Since we are rasterizing this graphics anyway, we could in this step smooth out hard edges and supress aliasing effects. A very simple an nice approach was given by @Szabolcs:

antialias[g_] :=
ImageResize[
Rasterize[g, "Image", ImageResolution -> 72*2, Background -> None],
Scaled[1/2]]

img = antialias[Show[g, Axes -> False, Boxed -> False]];


After having the surface as image you can use Inset to put it back into the graphics. Please note, that Background->None in the antialiasing function makes the white background transparent and therefore it works so nicely with the axes.

final = Graphics3D[
Inset[img, ImageScaled[{1/2, 1/2, 0}], {Center, Center}, size],
AbsoluteOptions[g], ImageSize -> size];
Export["tmp/gr3d.pdf", final]


What you should not now is, that the axes are vector-graphics while the rest is a raster-graphics;

## Open Questions

• If the ImageSize option is not used, the placement of the surface with Inset works find. Using a higher ImageSize requires an adjustment of the surface-size when it is inset. It's open to be proofed that this works reliable and that the surface is placed correctly.

• The pdf-export seems to use jpg-encoding for the raster-image. This look ugly. Maybe whe can prevent it anyhow from doing that during the export

• Note how nice it works that the box-lines are sometimes over and sometimes under the surface, always right. Inset seems to place the raster really in 3d. Does this work always.

## References

-
@AlexeyPopkov I missed that. Did you, just for curiosity, export your 3d-plot to a pdf? It's 1.1 GB here ;-) –  halirutan Feb 11 '12 at 15:44
No, I export rasterized version with high resolution. But it is also not so easy as one can expect... –  Alexey Popkov Feb 11 '12 at 17:46
" It's open to be proved..." I have an example that shows this placement method doesn't always work: raw.github.com/peeterjoot/mathematica/master/phy487/… –  Peeter Joot Dec 14 '13 at 1:41
@halirutan When I copy the code above and execute it, the final figure I get (the one that in your code follows the Export), I get an axis box that seems to be twice as big as the image (That is, the vertex appears to be at the origin, but the top circle at $z=0.5$). Did you use exactly the code in your answer to get the output you show? (MMA 9, if that matters) –  rogerl Apr 7 '14 at 22:29

For 3D graphics, I truly don't think it's worth the effort to attempt exporting as vector graphics. The valiant attempts to keep at least the axes and labels as vector graphics are in my opinion not something an everyday user would consider.

With PDF for 3D graphics, you're fighting two problems: not just the file size but also the slow rendering when your PDF reader has to execute a huge computation whenever the page containing the graphic needs to be displayed. The argument for vector graphics is typically that it creates smaller files because the graphic is essentially a program that runs at the time of rendering. But if that program (the PDF) just stupidly enumerates zillions points or polygons to be drawn one by one, you get the worst of both worlds: inefficient data representation with lots of data.

So I would just say: retreat to bitmaps, as Szabolcs was saying. This isn't necessarily a bad thing. Consider the example plot

a = Show[ParametricPlot3D[{16 Sin[t/3], 15 Cos[t] + 7 Sin[2 t],
8 Cos[3 t]}, {t, 0, 8 \[Pi]}, PlotStyle -> Tube[.2],
AxesStyle -> Directive[Black, Thickness[.004]]],
TextStyle -> {FontFamily -> "Helvetica", FontSize -> 12},
DefaultBoxStyle -> {Gray, Thick}]


This takes up 200 MB when exported straight to PDF. If instead I export this with

Export["wiggle.png", Magnify[a, 4]]


the file size is a reasonable 170 KB. The pixelated axes can of course be discerned if you look closely -- but so can the imperfections in the 3D plot itself that will always be there due to limited number of polygons.

The actual question was how to export to PDF, so I guess I'll answer it this way:

Export["wiggles.pdf", Rasterize[Magnify[a, 4], "Image"]]


Edit:

Unfortunately, this isn't foolproof because Magnifiy stops magnifying when the size exceeds the width of the notebook window! If the window isn't big enough to accomodate the desired magnification, the relative scaling of fonts and graphics will be messed up.

Edit 2:

As is discussed in this related question, Magnify will work reliably provided that you specify an explicit value for the ImageSize option of your 3D graphics.

Edit 3:

The remaining problem with Magnify is that it doesn't scale up tick marks properly. So I asked myself how to make @Heike's method of rasterization work automatically for Graphics3D without having to think about the resolution and image size every time.

Of course one could write a custom export function, but in some situations it would be convenient if one could modify the standard export behavior for the entire notebook. To do this, one only has to make sure that all Graphics3D automatically contain some part that requires an advanced version of PDF. In particular, this is the case for polygons with vertex colors.

So to achieve rasterization by default, one could initialize the notebook with a statement like this:

Map[SetOptions[#,
Prolog -> {{EdgeForm[], Texture[{{{0, 0, 0, 0}}}],
Polygon[#, VertexTextureCoordinates -> #] &[{{0, 0}, {1,
0}, {1, 1}}]}}] &, {Graphics3D, ContourPlot3D,
ListContourPlot3D, ListPlot3D, Plot3D, ListSurfacePlot3D,
ListVectorPlot3D, ParametricPlot3D, RegionPlot3D, RevolutionPlot3D,
SphericalPlot3D, VectorPlot3D}];


This adds an invisible 2D polygon as a Prolog to every Graphics3D that is created in the notebook (edit: I had to explicitly do this for various wrapper functions that create Graphics3D, such as ParametricPlot3D). My rationale is that Prolog isn't likely to be needed for anything else in my 3D plots under normal circumstances. Now when I try the above plot a in a simple export command such as

Export["a.pdf",a]


I get a high-resolution image that's ready for printing.

-

I suggest exporting to a raster format with high resolution. The ImageResolution option is very useful for controlling the resolution. I wrote a little tutorial on how to export images for LaTeX in this answer (since I would just repeat the same thing here, I am linking to it instead).

Note: High resolution raster images will take up a lot of space, but they are fast to render, and with a high enough resolution they give the same quality in printed documents as vector images. The size of included figures should not influence TeX compilation time significantly.

-
Seconded, but especially for fine line graphics containing e.g. a lot of text as well (e.g. technical drawings) working with the vector graphics was a pleasure and the file sizes and compilation speeds in LaTeX were a joy. –  Yves Klett Feb 9 '12 at 14:13
@Yves I agree with you, I also don't like how 3D graphics export to a vector format. I don't believe all those tiny polygons are necessary because PDF does support "triangle gradients". There's this little OpenGL to PostScript/PDF library that produces much much better results, so it is definitely technically possible to export 3D graphics to a small fast to render good quality PDF. –  Szabolcs Feb 9 '12 at 14:27
–  Szabolcs Feb 9 '12 at 14:28
Just don´t hold your breath ;-) –  Yves Klett Feb 9 '12 at 14:34
... and to be fair, I would not want to go back to Version5Graphics, got used to pretty things like Opacity or Texture far too quickly. –  Yves Klett Feb 9 '12 at 14:37

One workaround I've discovered is to export as SVG, open in Inkscape, and save as PDF. The default parameters there (which I have not explored thoroughly) result in a PDF file size of 324KB.

-
That works for relatively benign SVG - I was even thinking I could write a script for that. But then I realized that even for moderately complex 3D files, the intermediate SVG that you'd have to export can be so large that it will crash Inkscape. The example in my answer below gives a 90 MB SVG file, for example. That's very unwieldy to work with. –  Jens Feb 9 '12 at 18:48
It doesnt preserve the figure labels especially if they are complicated! –  Seyhmus Güngören Feb 1 at 14:31

Another convenient workaround is to export to PDF, reimport the PDF file and export it again. For my files it reduced sizes from 2 MB down to 200 kb.

Regards Patrick

Edit: Here is an example of an 700kb export. If reimported and reexported, the file size is down to 28k. Quality seems the same to me. Special characters however, like ä or ö from German are not converted correctly though. If anybody has an idea on how to deal with this?

Export["C:\Users\Desktop\test.pdf", "abc äüö"];

reimport = Import["C:\Users\Desktop\test.pdf"];

Export["C:\Users\Desktop\test2.pdf", reimport];

-
To illustrate your solution, you could add example code and images (is there any quality difference...?). –  Yves Klett Sep 6 '13 at 12:30
That might just be due to the font embedding issue: mathematica.stackexchange.com/questions/15929/… –  Peeter Joot Dec 13 '13 at 15:40