diff --git a/PIL/ImageQt.py b/PIL/ImageQt.py index 0e8cee00908..2131f8264ed 100644 --- a/PIL/ImageQt.py +++ b/PIL/ImageQt.py @@ -80,6 +80,33 @@ def fromqpixmap(im): # bytes_io.seek(0) # return PIL.Image.open(bytes_io) +def align8to32(bytes, width, mode): + """ + converts each scanline of data from 8 bit to 32 bit aligned + """ + + bits_per_pixel = { + '1': 1, + 'L': 8, + 'P': 8, + }[mode] + + # calculate bytes per line and the extra padding if needed + bits_per_line = bits_per_pixel * width + full_bytes_per_line, remaining_bits_per_line = divmod(bits_per_line, 8) + bytes_per_line = full_bytes_per_line + (1 if remaining_bits_per_line else 0) + + extra_padding = -bytes_per_line % 4 + + # already 32 bit aligned by luck + if not extra_padding: + return bytes + + new_data = [] + for i in range(len(bytes) / bytes_per_line): + new_data.append(bytes[i*bytes_per_line:(i+1)*bytes_per_line] + '\x00' * extra_padding) + + return ''.join(new_data) def _toqclass_helper(im): data = None @@ -123,7 +150,7 @@ def _toqclass_helper(im): raise ValueError("unsupported image mode %r" % im.mode) # must keep a reference, or Qt will crash! - __data = data or im.tobytes() + __data = data or align8to32(im.tobytes(), im.size[0], im.mode) return { 'data': __data, 'im': im, 'format': format, 'colortable': colortable } diff --git a/Tests/images/7x13.png b/Tests/images/7x13.png new file mode 100644 index 00000000000..d160c8b3877 Binary files /dev/null and b/Tests/images/7x13.png differ diff --git a/Tests/test_image_fromqimage.py b/Tests/test_image_fromqimage.py index 957ec9cc1cb..24ec19616b6 100644 --- a/Tests/test_image_fromqimage.py +++ b/Tests/test_image_fromqimage.py @@ -1,30 +1,41 @@ from helper import unittest, PillowTestCase, hopper from test_imageqt import PillowQtTestCase -from PIL import ImageQt +from PIL import ImageQt, Image class TestFromQImage(PillowQtTestCase, PillowTestCase): + files_to_test = [ + hopper(), + Image.open('Tests/images/transparent.png'), + Image.open('Tests/images/7x13.png'), + ] + def roundtrip(self, expected): result = ImageQt.fromqimage(expected.toqimage()) # Qt saves all images as rgb self.assert_image_equal(result, expected.convert('RGB')) def test_sanity_1(self): - self.roundtrip(hopper('1')) + for im in self.files_to_test: + self.roundtrip(im.convert('1')) def test_sanity_rgb(self): - self.roundtrip(hopper('RGB')) + for im in self.files_to_test: + self.roundtrip(im.convert('RGB')) def test_sanity_rgba(self): - self.roundtrip(hopper('RGBA')) + for im in self.files_to_test: + self.roundtrip(im.convert('RGBA')) def test_sanity_l(self): - self.roundtrip(hopper('L')) + for im in self.files_to_test: + self.roundtrip(im.convert('L')) def test_sanity_p(self): - self.roundtrip(hopper('P')) + for im in self.files_to_test: + self.roundtrip(im.convert('P')) if __name__ == '__main__':