Skip to content

Conversation

@Eta0
Copy link

@Eta0 Eta0 commented Nov 22, 2025

Preserve ICC profiles (also, direct libpng & libjpeg-turbo encoders)

Howdy!

This PR allows encoded JPEG and PNG files to copy over ICC profiles from their decoded sources. It does so by implementing dedicated JPEG and PNG encoders based on libjpeg-turbo and libpng, respectively. They have the same default settings as OpenCV's encoder, so their performance is effectively identical, but benchmarks are included to let folks test that claim (BenchmarkJpegEncoder and BenchmarkPngEncoder). The OpenCV encoder for JPEGs and PNGs is left completely intact here, but NewEncoder prefers to select the dedicated encoders.

Switching to full implementations instead of relying on OpenCV's write function adds a bit of code here, but it allows quite a lot of flexibility in return, as OpenCV doesn't expose as much functionality in its write function as using the underlying libraries directly.

Motivation

ICC profiles are currently accounted for with several encoders, but not OpenCV, meaning that JPEG and PNG files in particular will lose their ICC profile information when reëncoded, which can change the appearance of an image. On Discord, this comes up as a problem especially for iOS users, as iOS clients are served JPEG/PNG thumbnails, but photos taken on iPhones all use the Display P3 profile, meaning iOS users' own photos appear washed-out once they upload them.

Implementation notes

A single jpegEncoder or pngEncoder object can be used multiple times to encode to the same destination buffer., and they will always write starting at position 0 in that buffer. I had assumed that this was how openCVEncoder objects worked as well, but after testing, I realized that using the same openCVEncoder for multiple encode operations actually appears to write each new one after the end of the last encoded image in the destination buffer. I couldn't tell if this was intentional, or a bug, or what, so right now the new encoders just differ from openCVEncoder objects in that respect (though either one could be changed fairly easily to match).

Also, I'm not sure how this PR fits in with respect to the changes that were developed in parallel in #274. At a glance, it doesn't seem entirely incompatible (it looks like the same logic could be fit into the encoding paths for the new encoders). Maybe with the ability to embed ICC profiles in PNGs, compensating for the lack of an ICC profile is less necessary, if that's what that is for—but I'm not as familiar with the motivating issues for #274 to really have an opinion on what the best handling would look like. But let me know if or how y'all would like me to change this for it to be more compatible with that one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant