-
Notifications
You must be signed in to change notification settings - Fork 857
Convert image back to original color "mode" after resizing #873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
For cases when palette has fewer then 256 colors, will this always produce 256 colors palettes in output? If so, would it be valuable to get number of colors in existing palette and quantize RGBA image using PIL.Image.Image.quantize method to get back to original number of colors? |
|
@kkopachev It doesn't seem to require a min of 256 colors to be in P mode. The "after" output above, has 169 colors and is in P mode. The original had 128 colors. This makes sense, we added some colors during downscaling anti-aliasing. I think we are doing the right thing by letting Pillow generate a new pallete and leaving it at that. |
|
Ok, sounds good. I just thought it might be valuable to reduce palette size back to original number of colors (128 in that case). Despite of antialiasing creating more colors, we might just want to ignore extra colors it created. |
|
@kkopachev Yeah, I actually wondered the exact same thing when I was writing this so I completely understand. I considered saving the old palette before conversion and then somehow forcing it after resize. But I reached out to someone who knows more about these things than I do and he pointed out that anti-aliasing would probably produce some new colors (makes sense) and those details would be lost if we forced the old palette (also makes sense). I think if we forced the old palette, we would in effect be de-anti-aliasing the image and it would result in jagged edges, etc. It's also more code/CPU/Mem/time to do that. Ultimately I don't think this is the right place to make that sort of lossy optimization. |
|
OK, that totally makes sense! |
|
Nice change, @okor! Thanks in advance!
What do you think about adding a specific test case for this? |
|
@scorphus Test added. New image was sourced from Wikipedia, Public Domain: https://en.wikipedia.org/wiki/8-bit_color#/media/File:256colour.png |
|
Great, @okor! Thanks! |
If you resize an indexed color (aka palatted aka "P" mode) PNG with Thumbor, it correctly converts the PNG to RGBA before resizing to avoid resampling artifacts considering forced nearest neighbor algorithm with P mode images. However, this has the side effect of making indexed color PNGs much larger in bytes than is necessary. The simplest solution is to convert the image back to it's original color mode after resizing. This will more often than not, reduce the byte size of the resized image by a non-trivial amount - for PNG8 images.
Single test case with 256 indexed color PNG, reduced file size from 176kb to 37kb - 78.97% decrease).
original:

before:

after:

dssim (0.00120901):

One thing to note is that when we convert to RGBA then resize, it changes the colors. When we convert back to paletted mode it's probably going to be a little different. Hard to say to what degree without extensive testing. But that's always the case with image processing - depends on the input and so many other variables. You can see the delta according to dssim which is a bit apples to oranges since we really care about colors in original vs colors in output - not output vs output.
There may be some gotchas with this PR so we should think about it carefully. All tests pass ... but it's possible there could be some unintended side effects. I don't see any ... but maybe.
I was originally concerned that without a guard against CMYK, it may cause issues. But after my change, the image is always returned in RGB mode which is what we want. That happens regardless of what options are passed, even a pass through such as
http://localhost:8888/unsafe/http://192.168.1.12:8080/cmyk.jpgproduces an RGB jpeg. This does mean however, that real 1bit images will be converted to RGB which adds a lot of bytes to the PNG ... but that use case seems rare and could be addressed in another PR if we really want to optimize for 1bit images.