Rotation-Based Compression

26 pointsposted 11 hours ago
by sotix

14 Comments

pwg

11 hours ago

From TFA:

> 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.

audrey1

7 hours ago

Only fully losslessly if the image dimensions are a multiple of the MCU (usually 8x8px or 16x16px, I can't recall/depends) any pixels part of a DCT block on the edges are cropped when rendered, so jpegtran will drop those blocks when transforming the image since the alternative is introducing artifacts, since jpeg only supports cropping DCT blocks on the right and bottom edges.

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

01HNNWZ0MV43FF

3 hours ago

8 vs 16 Probably depends on whether chroma subsampling is enabled, off the top of my head

lifthrasiir

2 hours ago

Not just that, but the Exif orientation can be used to do the lossless rotation nowadays. (It's really the postprocessing step, but that step is now widely implemented.) This approach has no MCU limitation and even is honored by JPEG XL.

> 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.

a_e_k

7 hours ago

Right. The lossiness in JPEG comes from quantization of the DCT coefficients. But with the way the DCT works:

- 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.

pornel

7 hours ago

It's possible to get slightly better compression by losslessly rearranging data in a JPEG (DC components are compressed row by row, and prefer fewer horizontal color changes).

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.

vanderZwan

6 hours ago

> 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!"

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)

sotix

6 hours ago

Yes this is the crux and the fun of my discovery! I was surprised how using sips to rotate the image resulted in a lower size than using sips or ImageMagick to directly compress the image.

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.

lifthrasiir

2 hours ago

See my other comment for the result from ImageMagick, which shows little difference regardless of the orientation. For sips, there is a possibility that chroma subsampling impacted the result (because there are two different scaling factors for each axis) and you are technically comparing different images.

lifthrasiir

2 hours ago

Not really surprising, given that the original image seems to be compressed very conservatively:

    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.

RachelF

6 hours ago

Note that JPEGs can be rotated without decompression, just by swapping the axes of the compression cells.

Some of the software he uses may do this, others may decompress, rotate and recompress.

phkahler

7 hours ago

I've always wanted a tool to rotate and crop jpeg images on tile boundaries so no loss happens. This limits how precise a crop can be, but preserves pixels perfectly. Is there a tool like this?

msephton

4 hours ago

I think GraphicConverter can do this. Or maybe it was IrfanView. One of the old classics.