Rotation-Based Compression
winstoncooke.com
winstoncooke.com
> My understanding is that JPEGs don’t have lossless rotation by default, and that is true for sips as well.
This is incorrect. JPEG's can be losslessly rotated in 90 degree increments. See the -rotate option to 'jpegtran' in the libjpeg toolset.
https://man.archlinux.org/man/jpegtran.1.en
Best guess at what the author saw, the original files were likely originally compressed with an encoder that did not optimize the huffman table, and his newer tools likely do compute an optimal huffman table for compressing the DCT coefficients, that and the fact that the author was doing a lossy recompression would often result in file size reductions.
Also, passing jpeg's through jpegtran's lossless '-optimize' option often shrinks them in size. I.e., the jpeg's direct from most cameras often shrink (sometimes substantially) when optimizing them this way.
- You can flip a block horizontally, left-to-right, by negating the DCT coefficients in the odd-numbered columns (zero-indexed).
- You can flip a block vertically, top-to-bottom, by negating the DCT coefficients in the odd-numbered rows (zero-indexed).
- You can transpose a block by transposing the DCT coefficients.
In combination, that's enough to rotate a block in 90 degree increments, and to do so losslessly/reversibly without harming the original quantization (you don't even need to do an IDCT). Then you swap the blocks around to the right order and redo the lossless entropy encoding stages.
I modified jpegtran to work as a dll and wrote a python wrapper for it for a project so I could use it in a small-image compression pipeline (due to several limitations with calling the binary). I needed to save a few hundred million 100x100 jpegs, so I overwrite the height/width to trick the decoder into thinking the edge blocks are full, then I stitch them into ~10x10 mega-images with my jpegtran wrapper, requantize with mozjpeg, then recompress with dropbox lepton, it saves about 20-30% overall, with each step saving about 10% each (the stitching benefits the lepton step). https://i.imgur.com/6PV5WDM.jpeg
> Best guess at what the author saw, the original files were likely originally compressed with an encoder that did not optimize the huffman table, and his newer tools likely do compute an optimal huffman table for compressing the DCT coefficients, that and the fact that the author was doing a lossy recompression would often result in file size reductions.
`jpegtran -optimize` or any other optimizer (I tried ECT in particular) didn't work much for this particular image, so the Huffman table should have been almost optimal. Probably it has very low quantization factors instead.
However, here the author seems to accidentally fully recompress the images, and falls into the classic trap of "looks almost the same but the file is much smaller!"
That's what every lossy format does every time. They're designed to lose data that is hardest to see with the naked eye.
At the top end of the quality range, file sizes grow exponentially in proportion to quality (it's natural consequence of allowing less and less data to be lost, and approaching lossless compression that has a hard limit on how effective it can be).
But conversely this means that going from very high quality to still-pretty-high quality moves the file size along the exponential curve and seems to give dramatic reduction in file size. This isn't any trick, that's how it works.
File size change is easy to measure, but visual quality change is difficult to quantify, so people disregard the visual change. In reality they're just moving a point along a curve, and recompression gets a worse curve (less quality for the same file size) than the quality-to-file-size ratio of compressing the file at the lower quality from the start.
Except they didn't quite do that: yes, they recompressed the image instead of using the lossles rotation that JPEG is capable of. However, they then compared a recompressed rotated image to a recompressed image that wasn't rotated, and noted there was still a significant size differnce.
He also claims to have verified in GIMP that the two recompressed files were visually identical after rotating (I'm a little suspicious of that bit, since you wouldn't notice a tiny difference unless you use the "difference" layer mode and theo manually amplify the miniscule differences with something like the curves tool)
I’d encourage you to download the image from the link in the article and try yourself if you have a Mac and then compare them with GIMP because it’s very possible I didn’t do a perfect job with that.
Some of the software he uses may do this, others may decompress, rotate and recompress.
13,290,914 original.jpeg
15,357,049 magick-q99.jpg
13,323,544 magick-q98.jpg
12,197,196 magick-q97.jpg
10,745,457 magick-q96.jpg
8,577,000 magick-q95.jpg
7,933,287 magick-q94.jpg
7,360,975 magick-q93.jpg
15,386,195 magick-rot90-q99.jpg
13,325,385 magick-rot90-q98.jpg
12,115,271 magick-rot90-q97.jpg
10,733,896 magick-rot90-q96.jpg
8,661,101 magick-rot90-q95.jpg
7,962,175 magick-rot90-q94.jpg
7,343,580 magick-rot90-q93.jpg
Here all `magick-[rot-]qXX.jpg` files come from `convert original.jpeg [-rotate 90] -quality XX magick-qXX.jpg`, where my ImageMagick version is 7.1.1-12 (Windows x86-64, Q16-HDRI). The initial shrinkage is solely from the lossy compression process and doesn't depend on the rotation angle that much.