Apr 28
OptiJPEG - how to optimize JPG images losslessly
optipng and pngcrush are well known tools to optimize data structures within PNG images without actually re-compressing image data. These tools are quite effective in shaving off a few bytes, and sometimes can lead to 20-30% reduction in file size.
JPEG images on the other hand can't be optimized the same way. (There's no such tool named OptiJPEG, I made that up.) The Huffman coding compression scheme can't be optimized to a similar extent. And more effective coding schemes, like arithmetic coding (saving around 10%), became available a few years ago (due to an expired patent) yet decoder libraries too seldomly support it to allow a widespread use.
Even when your sacrificing "immediate viewability" by using a file compressor/archiver, you'll soon find out that JPEGs don't compress well. This page here has a comparison of compression options for JPEGs.
So there's very few left. This stackoverflow question outlines a few.
jpegtran, which is part of libjpeg, allows you to remove unnecessary comments and tags from images, is able to optimize Huffman tables, and can convert images to progressive. Progressive images are not streamable (means a viewer has to keep the whole image in memory for decoding) yet they are usually smaller.
jpegoptim seems to be more of a batch processing tool, which provides most features of jpegtran. Further, it is able to apply lossy re-compression when files are compressed with a quality setting above a certain threshold. (I don't know if or how the tool determines the original quality setting used. Let's hope it does so by using forensics like documented here, here or elsewhere?)
Example 1:
jpegoptim --all-progressive -v --strip-all --max=85 --preserve test.jpg
This will work (-v verbosely) on file test.jpg, overwriting it with a progressive JPEG stripped of all EXIF, etc. tags and in case it's a JPEG with quality > 85%, it will be re-compressed in a lossly way to 85% ("another generation"). File mtime will be kept.
Example 2:
find . -type f -name "*.jpg* -execdir jpegoptim --all-progressive -v --strip-all --max=85 --preserve '{}' \;
This command will traverse the current and all sub directories, finding files ending in .jpg and executes jpegoptim on them. See the post about executing a command on each file from a file glob for how this is done.
Sadly, plain classic JPEG (in contrast to JPEG2000) does not offer selective compression. In jpeg2000 interesting parts of an image can be compressed with a higher quality setting, while less important parts can be heavily compressed. What you can do with JPEGs is blanking certain parts of an image, wiping them with all gray. jpegtran is able to do so. For completeness it should be mentioned that you can also crop images losslessly with jpegtran.
So, once again, here's what you can do:
- optimize (declutter) the file structure, with jpegtran or jpegoptim
- crop the image and/or wipe less important areas with jpegtran
After that, you can compress files even further but only by wrapping them in another file format, so an image viewer will not be able to instantly display such files (without extracting them from an archive).
packJPG (now github, originated from Hochschule Aalen) (here's a GUI) is designed to compress JPEG files and can achieve 20% size reduction, but resulting files are .PJG files which no viewer I know of is able to display.
WinZip seems to use an effective way of treating JPEGs, but I haven't tested it
The PAQ compressor and companion ZPAQ archiver implements an algorithm designed for packing JPEGs.
7z offers "method 60: jpeg" as part of its pluggable compressor architecture, but I couldn't get it to work and so can't say anything about what it does, if it works, or if it's meant to compress JPEGs in the first place.
So that's what you can do (not much) to save a few bytes.
Coming from lossless?
For completeness, when you have access to the uncompressed (lossless) source image (like a RAW or PNG/TIFF/...), try to use the most recent libjpeg library for an efficient compression. Often mozjpeg is mentioned as a very capable alternative.
Don't use best quality (setting 12 in PhotoShop or 100% in GIMP). For everyday use, select something between 70-85% (GIMP), and for high quality images something around 10 (PS) or 95-98% (GIMP). 99% and 100% (GIMP) won't buy you anything and file size may double.
Further JPEG related reading: