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

ImageDraw only uses lower 8-bits of colors in I;16 images #7245

Closed
elipsitz opened this issue Jun 30, 2023 · 4 comments · Fixed by #7257
Closed

ImageDraw only uses lower 8-bits of colors in I;16 images #7245

elipsitz opened this issue Jun 30, 2023 · 4 comments · Fixed by #7257
Labels
Bug Any unexpected behavior, until confirmed feature.

Comments

@elipsitz
Copy link

What did you do?

ImageDraw on an image with mode I;16 fails to work correctly. When given a fill color (in the range 0...0xFFFF), it draws the shapes correctly, but uses a color with the lower 8-bits repeated twice.

What did you expect to happen?

The full 16-bit fill color provided should be used to draw on the image.

What actually happened?

Only the lower 8-bits (duplicated into the higher and lower byte) were used.

What are your OS, Python and Pillow versions?

  • OS: macOS 12 (also confirmed on Ubuntu 20.04)
  • Python: 3.10
  • Pillow: 9.5.0
from PIL import Image, ImageDraw
image = Image.new("I;16", (10, 10))
draw = ImageDraw.Draw(image)

c = 0x1234
draw.point([(0, 0)], fill=c)
print(hex(image.load()[0, 0]))
# --> 0x3434
# (but we expect it to be 0x1234)

c = 0x4567
draw.line([(0, 0), (5, 0)], fill=c)
print(hex(image.load()[0, 0]))
# --> 0x6767
# (but we expect it to be 0x4567)

c = 0x89AB
draw.rectangle([(0, 0), (5, 5)], fill=c)
print(hex(image.load()[0, 0]))
# --> 0xABAB
# (but we expect it to be 0x89AB)

As you can see, for each color, the actual color applied to the image is based on the lower 8-bits, duplicated twice.

I suspect this has something to do with this:

im->image8[y][x * 2] = (UINT8)ink;
im->image8[y][x * 2 + 1] = (UINT8)ink;

(Which was originally added in #3899)

Note that that issue is also referenced by #5598, so I suspect there might be a similar issue with drawing text.

@elipsitz
Copy link
Author

So the fix seems to be to switch those two lines to

            im->image8[y][x * 2] = (UINT8)ink;
            im->image8[y][x * 2 + 1] = (UINT8)(ink >> 8);

However, at the top of the file, the INK8 macro (used in DRAWINIT) truncates the input to the lower 8 bits:

#define INK8(ink) (*(UINT8 *)ink)

So it's also necessary to not do that. Switching it to #define INK8(ink) (*(UINT16 *)ink) works, but that seems wrong.

@radarhere
Copy link
Member

Thanks for the partial solution. I've created PR #7257 to resolve this, see what you think.

@elipsitz
Copy link
Author

elipsitz commented Jul 7, 2023

Looks good to me, thanks! Does text need a similar fix? Based on #5598 it looks like it has the same issue with the ink.

@radarhere
Copy link
Member

Ok, I've added a commit for text as well.

@radarhere radarhere added the Bug Any unexpected behavior, until confirmed feature. label Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Any unexpected behavior, until confirmed feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants