Skip to content
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

[Regression] image save() corrupted the image color start from Pillow 8.3.0 #6210

Closed
yusharon opened this issue Apr 14, 2022 · 7 comments · Fixed by #6283
Closed

[Regression] image save() corrupted the image color start from Pillow 8.3.0 #6210

yusharon opened this issue Apr 14, 2022 · 7 comments · Fixed by #6283
Labels

Comments

@yusharon
Copy link

yusharon commented Apr 14, 2022

What did you do?

import io
import numpy as np
from PIL import Image

#generate random data with 21 classes
num_classes = 21
height = 200
width = 300
data = np.random.rand(num_classes, height, width)

#prepare and generate image from numpy array use mode P
pred = np.squeeze(data)
pred = np.argmax(pred, axis=0)
img_with_correct_colors = Image.fromarray(pred.astype('uint8'), mode='P')
print(img_with_correct_colors.getcolors())

#save image uses BytesIO
fp = io.BytesIO()
img_with_correct_colors.save(fp, 'png')
img_with_wrong_colors = Image.open(io.BytesIO(fp.getvalue()))
img_with_wrong_colors.getcolors()

What did you expect to happen?

I expect image contains correct number of class before and after saving (which should have 21 number of classes)

What actually happened?

I run the exact same commands on Pillow 8.3.0 and Pillow 8.2.0

Pillow 8.2.0 gives the correct result

The img_with_correct_colors produce correct number of class

Image before saving(container 21 classes):

>>> print(img_with_correct_colors.getcolors())
[(2883, 0), (2847, 1), (2852, 2), (2889, 3), (2850, 4), (2870, 5), (2826, 6), (2846, 7), (2861, 8), (2836, 9), (2764, 10), (2915, 11), (2831, 12), (2852, 13), (2873, 14), (2826, 15), (2880, 16), (2866, 17), (2756, 18), (2928, 19), (2949, 20)]

After save, the image saved preserves the correct number of class as well (container 21 classes):

>>> img_with_wrong_colors.getcolors()
[(2883, 0), (2847, 1), (2852, 2), (2889, 3), (2850, 4), (2870, 5), (2826, 6), (2846, 7), (2861, 8), (2836, 9), (2764, 10), (2915, 11), (2831, 12), (2852, 13), (2873, 14), (2826, 15), (2880, 16), (2866, 17), (2756, 18), (2928, 19), (2949, 20)]

However, starting with Pillow >= 8.3.0 (Also tested on latest Pillow version 9.1.0)

Image before saving is still correct but image after saving produces wrong number of colors. The result looks like except the class 0 everything else got aggregate to the class 1.

Image before saving:

>>> print(img_with_correct_colors.getcolors())
[(2846, 0), (2940, 1), (2861, 2), (2834, 3), (2886, 4), (2911, 5), (2739, 6), (2797, 7), (2751, 8), (2960, 9), (2900, 10), (2880, 11), (2893, 12), (2810, 13), (2851, 14), (2870, 15), (2780, 16), (2775, 17), (2863, 18), (2954, 19), (2899, 20)]

Image after saving:

>>> print(img_with_wrong_colors.getcolors())
[(2846, 0), (57154, 1)]

What are your OS, Python and Pillow versions?

  • OS: Mac OS
  • Python: Python 3.7
  • Pillow: Pillow 8.2.0 / Pillow 8.3.0 / Pillow 9.1.0
@hugovk
Copy link
Member

hugovk commented Apr 14, 2022

Bisecting between 8.2.0 and 8.3.0 points to 4d36fee from PR #5552.

@radarhere
Copy link
Member

If you would like an immediate fix, I've found the following options work -

  1. Specify the number of colors when saving to PNG - img_with_correct_colors.save(fp, 'png', bits=8).
  2. Change the mode to "L". That may not work for the rest of your scenario, but it fixes the example you've provided here.

@yusharon
Copy link
Author

yusharon commented Apr 15, 2022

Thanks for providing the immediate workaround! Going to try and see if that works.

@yusharon
Copy link
Author

The workaround works! Thanks for the help! Curious about what change causing this issue and do you have any ETA for the fix. Thanks!

@radarhere
Copy link
Member

Just to be clear - I meant that you could do either 1 or 2 as a workaround, you don't have to do both.

@yusharon
Copy link
Author

Yes, we did option 1 as option 2 doesn't apply to us. Thanks for clarify though.

@radarhere
Copy link
Member

I've created PR #6283 to resolve this.

The next Pillow release is scheduled for July 1, so if the PR is merged before that, this will be fixed then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants