vigata / petitoJPEG

A high performance JPEG Encoder written in JavaScript
Other
70 stars 13 forks source link

Recompression artifacts at higher quality settings #8

Open tomdav999 opened 3 years ago

tomdav999 commented 3 years ago

Hi, first off thanks so much for this library. I found it indispensable to compress images client side without chroma sub-sampling. It's not practical to do with canvas.toBlob() because chrome and safari apply 2x2 chroma sub-sampling below 100% quality (ridiculous) and firefox applies 2x2 chroma sub-sampling below 90% quality.

Anyway, non withstanding the chroma sub-sampling differences, I wanted to compare encoding quality of canvas.toBlob() vs. petitoJPEG by re-compressing the same image multiple times, and I was surprised to see some strange artifacts with petitoJPEG. See demo here:

https://tomdav.com/tests/recompress.html

When I re-compress the sample image more than 15 times at quality 90 (or higher) it will start to show blocky artifacts with petitoJPEG, These artifacts don't manifest at quality 80 (or lower). Instead the re-compression becomes lossless, which is what happens when I re-compress with canvas.toBlob() in firefox or chrome (I am not able to test safari). I'm not sure what's going on with petitoJPEG. I don't think it is the compounding of jpeg artifacts because this should be worse at lower quality settings. Also, even if I set quality to 99 in petitoJPEG the artifacts still arise, which is concerning.

Do you have any thoughts?

Edit: I did more testing with different browsers and while desktop chrome canvas.toBlob() seems well behaved, mobile chrome canvas.toBlob() exhibits issues at high quality settings. While different than petitoJPEG,, at least other encoders are exhibiting issues. On my tablet, quality 99 in mobile chrome blurred out the test image and quality 100 exhibited artifact blooming. I'm starting to wonder if it might be a math precision issue.

Samples here: http://www.nwhikers.net/forums/viewtopic.php?t=8033907

vigata commented 3 years ago

This is definitely worth a look. Conceptually the process of reencoding an image with the exact same encoder, settings and exact same input is a no-op. In practicality there are YUV-RGB-YUV-... conversions, resizes. happening that will shift the pixel values around.

The artifacts we are seeing on quality 80+ start being visible at around 20 recompress times on very specific 8x8 blocks, and they very gradually increase on every recompression. They also happen to be blocks with just 1,2,3 DCT coefficients sent in the bitstream from the look of it. This sort of hints to some very slight math divergence. I'll take a look.