Merge branch 'main' into registered_extensions

This commit is contained in:
Andrew Murray 2022-12-22 07:45:52 +11:00
commit c6d1fddba5
11 changed files with 43 additions and 20 deletions

View File

@ -20,7 +20,7 @@ jobs:
steps: steps:
- name: "Check issues" - name: "Check issues"
uses: actions/stale@v6 uses: actions/stale@v7
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
only-labels: "Awaiting OP Action" only-labels: "Awaiting OP Action"

View File

@ -15,7 +15,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-minor-version: [7, 8, 9] python-minor-version: [8, 9]
timeout-minutes: 40 timeout-minutes: 40

View File

@ -5,6 +5,12 @@ Changelog (Pillow)
9.4.0 (unreleased) 9.4.0 (unreleased)
------------------ ------------------
- Ignore non-opaque WebP background when saving as GIF #6792
[radarhere]
- Only set tile in ImageFile __setstate__ #6793
[radarhere]
- When reading BLP, do not trust JPEG decoder to determine image is CMYK #6767 - When reading BLP, do not trust JPEG decoder to determine image is CMYK #6767
[radarhere] [radarhere]

View File

@ -875,14 +875,23 @@ def test_background(tmp_path):
im.info["background"] = 1 im.info["background"] = 1
im.save(out) im.save(out)
with Image.open(out) as reread: with Image.open(out) as reread:
assert reread.info["background"] == im.info["background"] assert reread.info["background"] == im.info["background"]
def test_webp_background(tmp_path):
out = str(tmp_path / "temp.gif")
# Test opaque WebP background
if features.check("webp") and features.check("webp_anim"): if features.check("webp") and features.check("webp_anim"):
with Image.open("Tests/images/hopper.webp") as im: with Image.open("Tests/images/hopper.webp") as im:
assert isinstance(im.info["background"], tuple) assert im.info["background"] == (255, 255, 255, 255)
im.save(out) im.save(out)
# Test non-opaque WebP background
im = Image.new("L", (100, 100), "#000")
im.info["background"] = (0, 0, 0, 0)
im.save(out)
def test_comment(tmp_path): def test_comment(tmp_path):
with Image.open(TEST_GIF) as im: with Image.open(TEST_GIF) as im:

View File

@ -34,7 +34,7 @@ def test_numpy_to_image():
# Check supported 1-bit integer formats # Check supported 1-bit integer formats
assert_image(to_image(bool, 1, 1), "1", TEST_IMAGE_SIZE) assert_image(to_image(bool, 1, 1), "1", TEST_IMAGE_SIZE)
assert_image(to_image(numpy.bool8, 1, 1), "1", TEST_IMAGE_SIZE) assert_image(to_image(numpy.bool_, 1, 1), "1", TEST_IMAGE_SIZE)
# Check supported 8-bit integer formats # Check supported 8-bit integer formats
assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE) assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
@ -193,7 +193,7 @@ def test_putdata():
"dtype", "dtype",
( (
bool, bool,
numpy.bool8, numpy.bool_,
numpy.int8, numpy.int8,
numpy.int16, numpy.int16,
numpy.int32, numpy.int32,

View File

@ -460,7 +460,7 @@ These platforms are built and tested for every change.
| +----------------------------+---------------------+ | +----------------------------+---------------------+
| | 3.9 (MinGW) | x86, x86-64 | | | 3.9 (MinGW) | x86, x86-64 |
| +----------------------------+---------------------+ | +----------------------------+---------------------+
| | 3.7, 3.8, 3.9 (Cygwin) | x86-64 | | | 3.8, 3.9 (Cygwin) | x86-64 |
+----------------------------------+----------------------------+---------------------+ +----------------------------------+----------------------------+---------------------+

View File

@ -886,20 +886,23 @@ def _get_palette_bytes(im):
def _get_background(im, info_background): def _get_background(im, info_background):
background = 0 background = 0
if info_background: if info_background:
background = info_background if isinstance(info_background, tuple):
if isinstance(background, tuple):
# WebPImagePlugin stores an RGBA value in info["background"] # WebPImagePlugin stores an RGBA value in info["background"]
# So it must be converted to the same format as GifImagePlugin's # So it must be converted to the same format as GifImagePlugin's
# info["background"] - a global color table index # info["background"] - a global color table index
try: try:
background = im.palette.getcolor(background, im) background = im.palette.getcolor(info_background, im)
except ValueError as e: except ValueError as e:
if str(e) == "cannot allocate more than 256 colors": if str(e) not in (
# If all 256 colors are in use, # If all 256 colors are in use,
# then there is no need for the background color # then there is no need for the background color
return 0 "cannot allocate more than 256 colors",
else: # Ignore non-opaque WebP background
"cannot add non-opaque RGBA color to RGB palette",
):
raise raise
else:
background = info_background
return background return background

View File

@ -711,7 +711,6 @@ class Image:
def __setstate__(self, state): def __setstate__(self, state):
Image.__init__(self) Image.__init__(self)
self.tile = []
info, mode, size, palette, data = state info, mode, size, palette, data = state
self.info = info self.info = info
self.mode = mode self.mode = mode

View File

@ -137,6 +137,10 @@ class ImageFile(Image.Image):
if self.format is not None: if self.format is not None:
return Image.MIME.get(self.format.upper()) return Image.MIME.get(self.format.upper())
def __setstate__(self, state):
self.tile = []
super().__setstate__(state)
def verify(self): def verify(self):
"""Check file integrity""" """Check file integrity"""

View File

@ -208,7 +208,9 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
tokens = b"".join(block.split()) tokens = b"".join(block.split())
for token in tokens: for token in tokens:
if token not in (48, 49): if token not in (48, 49):
raise ValueError(f"Invalid token for this mode: {bytes([token])}") raise ValueError(
b"Invalid token for this mode: %s" % bytes([token])
)
data = (data + tokens)[:total_bytes] data = (data + tokens)[:total_bytes]
invert = bytes.maketrans(b"01", b"\xFF\x00") invert = bytes.maketrans(b"01", b"\xFF\x00")
return data.translate(invert) return data.translate(invert)
@ -242,13 +244,13 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
half_token = tokens.pop() # save half token for later half_token = tokens.pop() # save half token for later
if len(half_token) > max_len: # prevent buildup of half_token if len(half_token) > max_len: # prevent buildup of half_token
raise ValueError( raise ValueError(
f"Token too long found in data: {half_token[:max_len + 1]}" b"Token too long found in data: %s" % half_token[: max_len + 1]
) )
for token in tokens: for token in tokens:
if len(token) > max_len: if len(token) > max_len:
raise ValueError( raise ValueError(
f"Token too long found in data: {token[:max_len + 1]}" b"Token too long found in data: %s" % token[: max_len + 1]
) )
value = int(token) value = int(token)
if value > maxval: if value > maxval:

View File

@ -355,9 +355,9 @@ deps = {
"libs": [r"imagequant.lib"], "libs": [r"imagequant.lib"],
}, },
"harfbuzz": { "harfbuzz": {
"url": "https://github.com/harfbuzz/harfbuzz/archive/5.3.1.zip", "url": "https://github.com/harfbuzz/harfbuzz/archive/6.0.0.zip",
"filename": "harfbuzz-5.3.1.zip", "filename": "harfbuzz-6.0.0.zip",
"dir": "harfbuzz-5.3.1", "dir": "harfbuzz-6.0.0",
"license": "COPYING", "license": "COPYING",
"build": [ "build": [
cmd_set("CXXFLAGS", "-d2FH4-"), cmd_set("CXXFLAGS", "-d2FH4-"),