How to make the PDFs produced by pdfLaTeX smaller?
A common approach is to let Ghostscript (gs
) optimize and compress the PDF after it has been created with pdflatex
.
Ghostscript is installed by most Linux distributions and easily available for other platforms (Windows as binaries, MacOS via MacPorts). In fact, almost all size-optimizing tools for PDF (save for Acrobat) you can find on the internet, internally use Ghostscript -- so you can as well call it directly.
There is a plethora of options available; I personally use the following:
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dNOPAUSE -dQUIET -dBATCH -dPrinted=false -sOutputFile=foo-compressed.pdf foo.pdf
I use this mostly for beamer presentations, where it gets me a size reduction of 60–70 percent. (A 10 MiB lecture note becomes 3–4 MiB in size.)
Edit 2020-02-06: Added -dPrinted=false
to preserve Hyperlinks.
Edit 2020-09-10: Changed -dCompatibilityLevel
from 1.4 to 1.5 as pdflatex
outputs PDF 1.5 by default since 2010.
Here is a revised version of the script above. The basics are unchanged, but it now handles paths and such in a sane manner, automatically copies the new over the old IFF the new file is smaller then the original (and not 0). It also gives some info on space savings. For some unknown reason, running it again can give even smaller output, but usually not by much. The first run gives the big speedup.
For example:
ekl@Taro:~/Documents⟫ optpdf techResume.pdf
Saving 1245351 bytes (now 6% of old)
ekl@Taro:~/Documents⟫ optpdf techResume.pdf
Saving 31 bytes (now 99% of old)
ekl@Taro:~/Documents⟫ optpdf techResume.pdf
Saving 7 bytes (now 99% of old)
ekl@Taro:~/Documents⟫ optpdf techResume.pdf
Didn't make it smaller! Keeping original
It is legal to give it long paths, but it currently doesn't like spaces in your filenames. Sorry. Getting shell scripts to handle this correctly in all instances is a pain, so just don't don't do it.
Here is the code:
#!/bin/bash
#
# optpdf file.pdf
# This script will attempt to optimize the given pdf
file="$1"
filebase="$(basename "$file" .pdf)"
optfile="/tmp/$$-${filebase}_opt.pdf"
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dNOPAUSE -dQUIET -dBATCH \
-sOutputFile="${optfile}" "${file}"
if [ $? == '0' ]; then
optsize=$(stat -c "%s" "${optfile}")
orgsize=$(stat -c "%s" "${file}")
if [ "${optsize}" -eq 0 ]; then
echo "No output! Keeping original"
rm -f "${optfile}"
exit;
fi
if [ ${optsize} -ge ${orgsize} ]; then
echo "Didn't make it smaller! Keeping original"
rm -f "${optfile}"
exit;
fi
bytesSaved=$(expr $orgsize - $optsize)
percent=$(expr $optsize '*' 100 / $orgsize)
echo Saving $bytesSaved bytes \(now ${percent}% of old\)
rm "${file}"
mv "${optfile}" "${file}"
fi
Enjoy!
There is a wonderful script to shrink a PDF: https://github.com/pts/pdfsizeopt . I've been using it for years and can recommend it. The main effect is that it compresses the embedded fonts. Very helpfull if a font is large, like Linux Libertine. The script shrinks such a PDF (if no pictures are included) to 10% of the size!
Using it under Windows requires carefull installation to get all the necessary *.dll files.
Once in a while the script quits with an error message. The most frequent reason is that Multivalent has an issue. Simply avoid multivalent with the command pdfsizeopt.py --use-multivalent=false ...
.
Another issue comes up, if you include other PDFs made by pdftex. Sometimes -- especially with Linux Libertine -- the italic letters in the included PDFs get garbled. We can avoid this by adding as first line to the *.tex file: \pdfinclusioncopyfonts=1
.