python-pillow / Pillow

Python Imaging Library (Fork)
https://python-pillow.org
Other
12.14k stars 2.21k forks source link

Incorrect output when converting greyscale to bilevel #3394

Closed Raptoer closed 5 years ago

Raptoer commented 5 years ago

What did you do?

converted test image to bilevel

What did you expect to happen?

Most of the image should be black, only the very bottom should be white

What actually happened?

half is black, half is white

What are your OS, Python and Pillow versions?

Documentation states If dither is NONE, all non-zero values are set to 255 (white)

included image and code show that this is not the case, instead any value under 128 becomes white while any value over 128 becomes black. Considering the behavior of other programs, it is likely that the documentation is wrong rather than the behavior.

graydient.zip

Files have been zipped due to github not accepting bmp images.

Image.open("input.bmp").convert("1", dither=Image.NONE).save("output.bmp")
hugovk commented 5 years ago

The docs say:

The default method of converting a greyscale (“L”) or “RGB” image into a bilevel (mode “1”) image uses Floyd-Steinberg dither to approximate the original image luminosity levels. If dither is NONE, all non-zero values are set to 255 (white).

Looks like the conversion is done in tobilevel which indeed has a cutoff at 128:

https://github.com/python-pillow/Pillow/blob/3437d5fcb4880f622f72f313ecc764e140f13dfb/src/libImaging/Convert.c#L1203-L1285

This hasn't really changed since the PIL->Pillow fork:

https://github.com/python-pillow/Pillow/blame/master/src/libImaging/Convert.c#L1203-L1285

Those docs were last edited in https://github.com/python-pillow/Pillow/issues/407 to correct the bit about FLOYDSTEINBERG being used by default, but didn't adjust this bit.

Please could you send a PR to correct the docs? It's from the docstring:

https://github.com/python-pillow/Pillow/blob/master/src/PIL/Image.py#L856