diff --git a/Tests/images/hopper_webp_bits.ppm b/Tests/images/hopper_webp_bits.ppm index 6dce2da2e..f431bc7b1 100644 Binary files a/Tests/images/hopper_webp_bits.ppm and b/Tests/images/hopper_webp_bits.ppm differ diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 06e274d0a..305abf481 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -16,8 +16,7 @@ class TestFileWebp(PillowTestCase): self.skipTest('WebP support not installed') return - # WebPAnimDecoder only returns RGBA or RGBX, never RGB - self.rgb_mode = "RGBX" if _webp.HAVE_WEBPANIM else "RGB" + self.rgb_mode = "RGB" def test_version(self): _webp.WebPDecoderVersion() @@ -29,8 +28,7 @@ class TestFileWebp(PillowTestCase): Does it have the bits we expect? """ - file_path = "Tests/images/hopper.webp" - image = Image.open(file_path) + image = Image.open("Tests/images/hopper.webp") self.assertEqual(image.mode, self.rgb_mode) self.assertEqual(image.size, (128, 128)) @@ -40,9 +38,7 @@ class TestFileWebp(PillowTestCase): # generated with: # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm - target = Image.open('Tests/images/hopper_webp_bits.ppm') - target = target.convert(self.rgb_mode) - self.assert_image_similar(image, target, 20.0) + self.assert_image_similar_tofile(image, 'Tests/images/hopper_webp_bits.ppm', 1.0) def test_write_rgb(self): """ @@ -61,13 +57,8 @@ class TestFileWebp(PillowTestCase): image.load() image.getdata() - # If we're using the exact same version of WebP, this test should pass. - # but it doesn't if the WebP is generated on Ubuntu and tested on - # Fedora. - # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm - # target = Image.open('Tests/images/hopper_webp_write.ppm') - # self.assert_image_equal(image, target) + self.assert_image_similar_tofile(image, 'Tests/images/hopper_webp_write.ppm', 12.0) # This test asserts that the images are similar. If the average pixel # difference between the two images is less than the epsilon value, diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index 10354c55f..4c35dad73 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -19,8 +19,7 @@ class TestFileWebpLossless(PillowTestCase): if (_webp.WebPDecoderVersion() < 0x0200): self.skipTest('lossless not included') - # WebPAnimDecoder only returns RGBA or RGBX, never RGB - self.rgb_mode = "RGBX" if _webp.HAVE_WEBPANIM else "RGB" + self.rgb_mode = "RGB" def test_write_lossless_rgb(self): temp_file = self.tempfile("temp.webp") diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index 39a8f2e35..1d8a0c10b 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -5,6 +5,7 @@ from io import BytesIO _VALID_WEBP_MODES = { "RGBX": True, "RGBA": True, + "RGB": True, } _VALID_WEBP_LEGACY_MODES = { @@ -63,7 +64,8 @@ class WebPImageFile(ImageFile.ImageFile): bgcolor & 0xFF self.info["background"] = (bg_r, bg_g, bg_b, bg_a) self._n_frames = frame_count - self.mode = mode + self.mode = 'RGB' if mode == 'RGBX' else mode + self.rawmode = mode self.tile = [] # Attempt to read ICC / EXIF / XMP chunks from file @@ -154,7 +156,7 @@ class WebPImageFile(ImageFile.ImageFile): # Set tile self.fp = BytesIO(data) - self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)] return super(WebPImageFile, self).load() @@ -240,16 +242,23 @@ def _save_all(im, fp, filename): # Make sure image mode is supported frame = ims + rawmode = ims.mode if ims.mode not in _VALID_WEBP_MODES: - alpha = ims.mode == 'P' and 'A' in ims.im.getpalettemode() - frame = ims.convert('RGBA' if alpha else 'RGBX') + alpha = 'A' in ims.mode or 'a' in ims.mode \ + or ims.mode == 'P' and 'A' in ims.im.getpalettemode() + rawmode = 'RGBA' if alpha else 'RGBX' + frame = ims.convert(rawmode) + + if rawmode == 'RGB': + # For faster conversion, use RGBX + rawmode = 'RGBX' # Append the frame to the animation encoder enc.add( - frame.tobytes(), + frame.tobytes('raw', rawmode), timestamp, frame.size[0], frame.size[1], - frame.mode, + rawmode, lossless, quality, method @@ -288,7 +297,8 @@ def _save(im, fp, filename): xmp = im.encoderinfo.get("xmp", "") if im.mode not in _VALID_WEBP_LEGACY_MODES: - alpha = im.mode == 'P' and 'A' in im.im.getpalettemode() + alpha = 'A' in im.mode or 'a' in im.mode \ + or im.mode == 'P' and 'A' in im.im.getpalettemode() im = im.convert('RGBA' if alpha else 'RGB') data = _webp.WebPEncode( diff --git a/src/_webp.c b/src/_webp.c index f23d950f7..66b6d3268 100644 --- a/src/_webp.c +++ b/src/_webp.c @@ -216,6 +216,8 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) WebPPictureImportRGBA(frame, rgb, 4 * width); } else if (strcmp(mode, "RGBX")==0) { WebPPictureImportRGBX(frame, rgb, 4 * width); + } else { + WebPPictureImportRGB(frame, rgb, 3 * width); } // Add the frame to the encoder