mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-02 02:43:06 +03:00
Merge branch 'main' into registered_extensions
This commit is contained in:
commit
c6d1fddba5
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
|
@ -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"
|
||||||
|
|
2
.github/workflows/test-cygwin.yml
vendored
2
.github/workflows/test-cygwin.yml
vendored
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 |
|
||||||
+----------------------------------+----------------------------+---------------------+
|
+----------------------------------+----------------------------+---------------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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-"),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user