-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Fix 32-bit BMP loading (RGBA or RGBX) #1125
Conversation
PIL choked on perfectly valid BMP files (32 bits with Alpha). It could not handle valid RGBA masks to determine the raw format. To clarify things, I: - Rewrote the `BmpImagePlugin.BmpImageFile` class to be far more readable - Made error messages more explicit (e.g. say that RLE bitmaps are unsupported) - Made a readable dict to contain BMP header information - Kept the existing security checks - Instead of reading palette info by chunks of 3/4 bytes, read the whole palette info at once and parse the data. - Now works with BMPv4/5 with Alpha (and can be exported to alpha PNG for example) - Tested load and save with RGB24, RGB8, RGB8L, RGB32 and RGBA32. - Tested with one bogus file. File not accepted, as expected. I wanted to test more BMP formats, but I could not find that many images. But for all the types I tested, it worked flawlessly.
} | ||
|
||
|
||
def _save(im, fp, filename, check=0): | ||
try: | ||
print im.mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debug print
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my goodness. :/
Debug print left in _save. Removed.
Seems like a test with a BMP image has failed (Tests/images/bmp/g/pal1wb.bmp, too different from expected result). Investigating. |
It appears that {{{ The handling of 1bpp bitmaps is a little complicated. When reading 1bpp bitmaps, the palette is ignored. 1's are considered foreground, and they are considered black. 0's are considered background, and they are considered white. }}} so the raw mode has to be `1;I`
Use the provided image offset if there is palette data while the image is bitfielded.
Until tests pass.
Fixed loading of all types of provided images (+rgba). Added edge case where the header is reported as 40 bytes long with BITFIELDS (they start past the 40 bytes of the header). Loading fails for RLE, but IIRC, they're unsupported so it's normal.
Choked on roundtrip, where a P;1 image was returned instead of a 1 image.
Readapted some original code.
Getting bonkers but I need to know
I suspect the tests to check against an exact string when expecting an error
use offset provided
Various fixes on code broken or not passing tests
Again.
Some .cur file with alpha was loaded fully opaque with PIL. Fixed, and fixed the test to take that into account.
Fails on Python 3, tried some fixes before going the virtualenv3 route
Error happening in Python 3.x with P images: in original code, palette data was created from a list of bytestrings. Changed to a full bytestring. - `b"".join(list of bytestrings)` works in python 2.7 and 3.x - `b"".join(bytestring)` works in python 2.7 but fails in python 3.x No need to `join` anymore. Works in 3.x
There are a ton of BMP images in the test suite, Tests/images/bmp/*. G == good, q== questionable, b==bad. Look at |
Exactly. At first, I did not know how to test a thorough set of images. Then I found the images, understood how Travis CI works, and then I had a very hard time catering for every test (I even had to fix a test, since before the fix, PIL could not detect the A channel of a valid 32 bit RGBA .cur file and expected this behaviour) |
Does not change testing on other files, but fixes a case which previously made PIL collapse. The Bitmap was a 1x1 RGBA and provoked an exception in PIL, but every Image viewer can load it. Fixed code with comparison of header size, compression type and loading type of masks and fixed it.
Is this ready for 2.8.0? |
format = "BMP" | ||
""" Image plugin for the Windows Bitmap format (BMP) """ | ||
|
||
#--------------------------------------------------------------- Description |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very strange comments style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, sorry, gonna fix it very soon. This is the comment style automatically used by Eclipse, and it did fit me until very recently, when I started using flake8 to check coding style.
Fix 32-bit BMP loading (RGBA or RGBX)
Thanks, I'll fix the comments |
Yes, will have a look at it today. |
@artscoop thanks! ;) 💃 |
@techtonik , can you check if the version of Pillow in the https://github.com/artscoop/Pillow repo fixes or mitigates your problem ? |
@artscoop I can only check this change https://github.com/artscoop/Pillow/commit/6216d079f5bac0a7f13a43b76bf276542c1abd74 because I don't have Visual Studio to compile the whole extension. Let me check. |
Didn't help. The error message is the same: Traceback (most recent call last):
File "C:\Bin\saveclip.py", line 31, in <module>
im = ImageGrab.grabclipboard()
File "C:\Python27\lib\site-packages\PIL\ImageGrab.py", line 66, in grabclipboard
return BmpImagePlugin.DibImageFile(io.BytesIO(data))
File "C:\Python27\lib\site-packages\PIL\ImageFile.py", line 100, in __init__
self._open()
File "C:\Python27\lib\site-packages\PIL\BmpImagePlugin.py", line 208, in _open
self._bitmap()
File "C:\Python27\lib\site-packages\PIL\BmpImagePlugin.py", line 148, in _bitmap
raise IOError("Unsupported BMP bitfields layout")
IOError: Unsupported BMP bitfields layout and #!/usr/bin/env python
#
# the code is in public domain
#
# history:
# 1.1 - mention what library should be installed
# 1.0 - make get_avail_filename() function
__version__ = '1.1'
import os, sys
try:
from PIL import ImageGrab
except ImportError:
# https://github.com/python-pillow/Pillow/issues/1293
raise ImportError("Pillow is not installed (use Pillow==2.7.0)")
def get_avail_filename(basename, suffix='%0.2d.png'):
"""Find first non-existing filename with given numerical suffix"""
counter = 1
while True:
newname = basename + suffix % counter
if not os.path.exists(newname):
return newname
counter += 1
filename = 'clipboard.png'
if os.path.exists(filename):
filename = get_avail_filename('clipboard', suffix='%0.2d.png')
im = ImageGrab.grabclipboard()
if im is None:
sys.exit('Error: No image data in clipboard')
else:
im.save(filename, 'PNG')
print('Saved as %s' % filename) |
Uncommented line 147 just before the print(file_info['bits'], [hex(value) for value in file_info['rgb_mask']]) It gives this info: |
I was just going to ask you to uncomment that line :) |
The error exception with the latest code is strange:
I reverted and changed the line to dump
|
(Top tip: if there's unit tests for this, you can enable AppVeyor for your repo and it'll build and test it on Windows. And good to do so on Travis CI, for Linux. They're free. And they will also help guard against any other regressions.) |
@hugovk yes, but it is not clear what unit test is for. Right now the data is in Windows clipboard. I can dump the binary for unit test if somebody tells me how. |
Tracing with pdb..
|
And here comes the SyntaxError:
|
Here is the binary data from |
Hello, the latest BmpImagePlugin.py seems can't work with me Test32bitbmp |
From the code:
|
PIL choked on perfectly valid BMP files (32 bits with Alpha). It could not handle valid RGBA masks to determine the raw format.
To clarify things, I:
BmpImagePlugin.BmpImageFile
class to be far more readableI wanted to test more BMP formats, but I could not find that many images.
But for all the types I tested, it worked flawlessly.