mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 00:46:16 +03:00
- flake8 formatting fixes
- webp => WebP doc and comment changes
This commit is contained in:
parent
c9258d6cdb
commit
28bec69e98
|
@ -44,6 +44,7 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
self.size = width, height
|
||||
self.fp = BytesIO(data)
|
||||
self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
|
||||
self._n_frames = 1
|
||||
return
|
||||
|
||||
# Use the newer AnimDecoder API to parse the (possibly) animated file,
|
||||
|
@ -51,7 +52,8 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
self._decoder = _webp.WebPAnimDecoder(self.fp.read())
|
||||
|
||||
# Get info from decoder
|
||||
width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()
|
||||
width, height, loop_count, bgcolor, frame_count, mode = \
|
||||
self._decoder.get_info()
|
||||
self.size = width, height
|
||||
self.info["loop"] = loop_count
|
||||
bg_a, bg_r, bg_g, bg_b = \
|
||||
|
@ -85,14 +87,10 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if not _webp.HAVE_WEBPANIM:
|
||||
return 1
|
||||
return self._n_frames
|
||||
|
||||
@property
|
||||
def is_animated(self):
|
||||
if not _webp.HAVE_WEBPANIM:
|
||||
return False
|
||||
return self._n_frames > 1
|
||||
|
||||
def seek(self, frame):
|
||||
|
@ -122,7 +120,7 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
|
||||
# Check if an error occurred
|
||||
if ret is None:
|
||||
self._reset() # Reset just to be safe
|
||||
self._reset() # Reset just to be safe
|
||||
self.seek(0)
|
||||
raise EOFError("failed to decode next frame in WebP file")
|
||||
|
||||
|
@ -130,20 +128,18 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
data, timestamp = ret
|
||||
duration = timestamp - self.__timestamp
|
||||
self.__timestamp = timestamp
|
||||
timestamp -= duration # libwebp gives frame end, adjust to start of frame
|
||||
|
||||
# libwebp gives frame end, adjust to start of frame
|
||||
timestamp -= duration
|
||||
return data, timestamp, duration
|
||||
|
||||
def _seek(self, frame):
|
||||
if self.__physical_frame == frame:
|
||||
return # Nothing to do
|
||||
|
||||
return # Nothing to do
|
||||
if frame < self.__physical_frame:
|
||||
# Rewind to beginning
|
||||
self._reset()
|
||||
|
||||
# Advance to the requested frame
|
||||
self._reset() # Rewind to beginning
|
||||
while self.__physical_frame < frame:
|
||||
self._get_next()
|
||||
self._get_next() # Advance to the requested frame
|
||||
|
||||
def load(self):
|
||||
if _webp.HAVE_WEBPANIM:
|
||||
|
@ -168,6 +164,7 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
|
||||
return self.__logical_frame
|
||||
|
||||
|
||||
def _save_all(im, fp, filename):
|
||||
encoderinfo = im.encoderinfo.copy()
|
||||
append_images = encoderinfo.get("append_images", [])
|
||||
|
@ -207,9 +204,12 @@ def _save_all(im, fp, filename):
|
|||
# Validate background color
|
||||
if (not isinstance(background, (list, tuple)) or len(background) != 4 or
|
||||
not all(v >= 0 and v < 256 for v in background)):
|
||||
raise IOError("Background color is not an RGBA tuple clamped to (0-255): %s" % str(background))
|
||||
raise IOError("Background color is not an RGBA tuple clamped "
|
||||
"to (0-255): %s" % str(background))
|
||||
|
||||
# Convert to packed uint
|
||||
bg_r, bg_g, bg_b, bg_a = background
|
||||
background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0) # Convert to packed uint
|
||||
background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)
|
||||
|
||||
# Setup the WebP animation encoder
|
||||
enc = _webp.WebPAnimEncoder(
|
||||
|
@ -240,7 +240,7 @@ def _save_all(im, fp, filename):
|
|||
|
||||
# Make sure image mode is supported
|
||||
frame = ims
|
||||
if not ims.mode in _VALID_WEBP_MODES:
|
||||
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')
|
||||
|
||||
|
@ -256,7 +256,10 @@ def _save_all(im, fp, filename):
|
|||
)
|
||||
|
||||
# Update timestamp and frame index
|
||||
timestamp += duration[frame_idx] if isinstance(duration, (list, tuple)) else duration
|
||||
if isinstance(duration, (list, tuple)):
|
||||
timestamp += duration[frame_idx]
|
||||
else:
|
||||
timestamp += duration
|
||||
frame_idx += 1
|
||||
|
||||
finally:
|
||||
|
@ -272,10 +275,11 @@ def _save_all(im, fp, filename):
|
|||
# Get the final output from the encoder
|
||||
data = enc.assemble(icc_profile, exif, xmp)
|
||||
if data is None:
|
||||
raise IOError("cannot write file as WEBP (encoder returned None)")
|
||||
raise IOError("cannot write file as WebP (encoder returned None)")
|
||||
|
||||
fp.write(data)
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
lossless = im.encoderinfo.get("lossless", False)
|
||||
quality = im.encoderinfo.get("quality", 80)
|
||||
|
@ -299,7 +303,7 @@ def _save(im, fp, filename):
|
|||
xmp
|
||||
)
|
||||
if data is None:
|
||||
raise IOError("cannot write file as WEBP (encoder returned None)")
|
||||
raise IOError("cannot write file as WebP (encoder returned None)")
|
||||
|
||||
fp.write(data)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ try:
|
|||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
|
||||
class TestFileWebp(PillowTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -24,7 +25,7 @@ class TestFileWebp(PillowTestCase):
|
|||
|
||||
def test_read_rgb(self):
|
||||
"""
|
||||
Can we read a RGB mode webp file without error.
|
||||
Can we read a RGB mode WebP file without error?
|
||||
Does it have the bits we expect?
|
||||
"""
|
||||
|
||||
|
@ -39,7 +40,8 @@ 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').convert(self.rgb_mode)
|
||||
target = Image.open('Tests/images/hopper_webp_bits.ppm')
|
||||
target = target.convert(self.rgb_mode)
|
||||
self.assert_image_similar(image, target, 20.0)
|
||||
|
||||
def test_write_rgb(self):
|
||||
|
@ -77,7 +79,7 @@ class TestFileWebp(PillowTestCase):
|
|||
|
||||
def test_write_unsupported_mode_L(self):
|
||||
"""
|
||||
Saving a black-and-white file to webp format should work, and be
|
||||
Saving a black-and-white file to WebP format should work, and be
|
||||
similar to the original file.
|
||||
"""
|
||||
|
||||
|
@ -97,7 +99,7 @@ class TestFileWebp(PillowTestCase):
|
|||
|
||||
def test_write_unsupported_mode_P(self):
|
||||
"""
|
||||
Saving a palette-based file to webp format should work, and be
|
||||
Saving a palette-based file to WebP format should work, and be
|
||||
similar to the original file.
|
||||
"""
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class TestFileWebpAlpha(PillowTestCase):
|
|||
|
||||
def test_read_rgba(self):
|
||||
"""
|
||||
Can we read a RGBA mode file without error.
|
||||
Can we read an RGBA mode file without error?
|
||||
Does it have the bits we expect?
|
||||
"""
|
||||
|
||||
|
@ -44,8 +44,8 @@ class TestFileWebpAlpha(PillowTestCase):
|
|||
|
||||
def test_write_lossless_rgb(self):
|
||||
"""
|
||||
Can we write a RGBA mode file with lossless compression without error.
|
||||
Does it have the bits we expect?
|
||||
Can we write an RGBA mode file with lossless compression without
|
||||
error? Does it have the bits we expect?
|
||||
"""
|
||||
|
||||
temp_file = self.tempfile("temp.webp")
|
||||
|
@ -102,7 +102,7 @@ class TestFileWebpAlpha(PillowTestCase):
|
|||
|
||||
def test_write_unsupported_mode_PA(self):
|
||||
"""
|
||||
Saving a palette-based file with transparency to webp format
|
||||
Saving a palette-based file with transparency to WebP format
|
||||
should work, and be similar to the original file.
|
||||
"""
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from helper import unittest, PillowTestCase
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
@ -8,6 +8,7 @@ try:
|
|||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
|
||||
class TestFileWebpAnimation(PillowTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -21,7 +22,7 @@ class TestFileWebpAnimation(PillowTestCase):
|
|||
|
||||
def test_n_frames(self):
|
||||
"""
|
||||
Ensure that webp format sets n_frames and is_animated
|
||||
Ensure that WebP format sets n_frames and is_animated
|
||||
attributes correctly.
|
||||
"""
|
||||
|
||||
|
@ -68,16 +69,15 @@ class TestFileWebpAnimation(PillowTestCase):
|
|||
temp_file2 = self.tempfile("temp.png")
|
||||
frame1 = Image.open('Tests/images/anim_frame1.webp')
|
||||
frame2 = Image.open('Tests/images/anim_frame2.webp')
|
||||
frame1.save(temp_file, save_all=True, append_images=[frame2], lossless=True)
|
||||
frame1.save(temp_file,
|
||||
save_all=True, append_images=[frame2], lossless=True)
|
||||
|
||||
im = Image.open(temp_file)
|
||||
self.assertEqual(im.n_frames, 2)
|
||||
print("Test File: " + temp_file)
|
||||
|
||||
# Compare first frame to original
|
||||
im.load()
|
||||
im.save(temp_file2)
|
||||
print("Frame 1: " + temp_file2)
|
||||
self.assert_image_equal(im, frame1.convert("RGBA"))
|
||||
|
||||
# Compare second frame to original
|
||||
|
@ -103,7 +103,7 @@ class TestFileWebpAnimation(PillowTestCase):
|
|||
self.assertEqual(im.n_frames, 5)
|
||||
self.assertTrue(im.is_animated)
|
||||
|
||||
# Double-check that timestamps and durations match original values specified
|
||||
# Check that timestamps and durations match original values specified
|
||||
ts = 0
|
||||
for frame in range(im.n_frames):
|
||||
im.seek(frame)
|
||||
|
@ -114,7 +114,7 @@ class TestFileWebpAnimation(PillowTestCase):
|
|||
|
||||
def test_seeking(self):
|
||||
"""
|
||||
Create an animated webp file, and then try seeking through
|
||||
Create an animated WebP file, and then try seeking through
|
||||
frames in reverse-order, verifying the timestamps and durations
|
||||
are correct.
|
||||
"""
|
||||
|
@ -131,7 +131,7 @@ class TestFileWebpAnimation(PillowTestCase):
|
|||
self.assertEqual(im.n_frames, 5)
|
||||
self.assertTrue(im.is_animated)
|
||||
|
||||
# Traverse frames in reverse order, double-check timestamps and duration
|
||||
# Traverse frames in reverse, checking timestamps and durations
|
||||
ts = dur * (im.n_frames-1)
|
||||
for frame in reversed(range(im.n_frames)):
|
||||
im.seek(frame)
|
||||
|
|
|
@ -8,6 +8,7 @@ try:
|
|||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
|
||||
class TestFileWebpLossless(PillowTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -8,6 +8,7 @@ try:
|
|||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
|
||||
class TestFileWebpMetadata(PillowTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
4
_webp.c
4
_webp.c
|
@ -12,7 +12,7 @@
|
|||
|
||||
/*
|
||||
* Check the versions from mux.h and demux.h, to ensure the WebPAnimEncoder and
|
||||
* WebPAnimDecoder API's are present (initial support was added in 0.5.0). The
|
||||
* WebPAnimDecoder APIs are present (initial support was added in 0.5.0). The
|
||||
* very early versions added had some significant differences, so we require
|
||||
* later versions, before enabling animation support.
|
||||
*/
|
||||
|
@ -591,7 +591,7 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
|
|||
}
|
||||
#else
|
||||
{
|
||||
/* I want to truncate the *_size items that get passed into webp
|
||||
/* I want to truncate the *_size items that get passed into WebP
|
||||
data. Pypy2.1.0 had some issues where the Py_ssize_t items had
|
||||
data in the upper byte. (Not sure why, it shouldn't have been there)
|
||||
*/
|
||||
|
|
|
@ -658,7 +658,7 @@ format are currently undocumented.
|
|||
The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||
|
||||
**lossless**
|
||||
If present and true, instructs the WEBP writer to use lossless compression.
|
||||
If present and true, instructs the WebP writer to use lossless compression.
|
||||
|
||||
**quality**
|
||||
Integer, 1-100, Defaults to 80. For lossy, 0 gives the smallest
|
||||
|
@ -671,23 +671,23 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
|||
|
||||
**icc_procfile**
|
||||
The ICC Profile to include in the saved file. Only supported if
|
||||
the system webp library was built with webpmux support.
|
||||
the system WebP library was built with webpmux support.
|
||||
|
||||
**exif**
|
||||
The exif data to include in the saved file. Only supported if
|
||||
the system webp library was built with webpmux support.
|
||||
the system WebP library was built with webpmux support.
|
||||
|
||||
Saving sequences
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. note::
|
||||
|
||||
Support for animated WebP files will only be enabled if the system webp
|
||||
Support for animated WebP files will only be enabled if the system WebP
|
||||
library is v0.5.0 or later. You can check webp animation support at
|
||||
runtime by inspecting the `_webp.HAVE_WEBPANIM` module flag.
|
||||
runtime by calling `features.check("webp_anim")`.
|
||||
|
||||
When calling :py:meth:`~PIL.Image.Image.save`, the following options
|
||||
are available when the save_all argument is present and true.
|
||||
are available when the `save_all` argument is present and true.
|
||||
|
||||
**append_images**
|
||||
A list of images to append as additional frames. Each of the
|
||||
|
|
Loading…
Reference in New Issue
Block a user