Skip truncated mask if LOAD_TRUNCATED_IMAGES is enabled

This commit is contained in:
Andrew Murray 2024-07-01 19:36:15 +10:00
parent 585bd6ad48
commit d3f343bb9b
2 changed files with 56 additions and 17 deletions

View File

@ -6,7 +6,7 @@ from pathlib import Path
import pytest import pytest
from PIL import IcoImagePlugin, Image, ImageDraw from PIL import IcoImagePlugin, Image, ImageDraw, ImageFile
from .helper import assert_image_equal, assert_image_equal_tofile, hopper from .helper import assert_image_equal, assert_image_equal_tofile, hopper
@ -241,3 +241,29 @@ def test_draw_reloaded(tmp_path: Path) -> None:
with Image.open(outfile) as im: with Image.open(outfile) as im:
assert_image_equal_tofile(im, "Tests/images/hopper_draw.ico") assert_image_equal_tofile(im, "Tests/images/hopper_draw.ico")
def test_truncated_mask() -> None:
# 1 bpp
with open("Tests/images/hopper_mask.ico", "rb") as fp:
data = fp.read()
ImageFile.LOAD_TRUNCATED_IMAGES = True
data = data[:-3]
try:
with Image.open(io.BytesIO(data)) as im:
with Image.open("Tests/images/hopper_mask.png") as expected:
assert im.mode == "1"
# 32 bpp
output = io.BytesIO()
expected = hopper("RGBA")
expected.save(output, "ico", bitmap_format="bmp")
data = output.getvalue()[:-1]
with Image.open(io.BytesIO(data)) as im:
assert im.mode == "RGB"
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False

View File

@ -235,6 +235,7 @@ class IcoFile:
alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4] alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4]
# convert to an 8bpp grayscale image # convert to an 8bpp grayscale image
try:
mask = Image.frombuffer( mask = Image.frombuffer(
"L", # 8bpp "L", # 8bpp
im.size, # (w, h) im.size, # (w, h)
@ -242,6 +243,11 @@ class IcoFile:
"raw", # raw decoder "raw", # raw decoder
("L", 0, -1), # 8bpp inverted, unpadded, reversed ("L", 0, -1), # 8bpp inverted, unpadded, reversed
) )
except ValueError:
if ImageFile.LOAD_TRUNCATED_IMAGES:
mask = None
else:
raise
else: else:
# get AND image from end of bitmap # get AND image from end of bitmap
w = im.size[0] w = im.size[0]
@ -259,6 +265,7 @@ class IcoFile:
mask_data = self.buf.read(total_bytes) mask_data = self.buf.read(total_bytes)
# convert raw data to image # convert raw data to image
try:
mask = Image.frombuffer( mask = Image.frombuffer(
"1", # 1 bpp "1", # 1 bpp
im.size, # (w, h) im.size, # (w, h)
@ -266,10 +273,16 @@ class IcoFile:
"raw", # raw decoder "raw", # raw decoder
("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed ("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed
) )
except ValueError:
if ImageFile.LOAD_TRUNCATED_IMAGES:
mask = None
else:
raise
# now we have two images, im is XOR image and mask is AND image # now we have two images, im is XOR image and mask is AND image
# apply mask image as alpha channel # apply mask image as alpha channel
if mask:
im = im.convert("RGBA") im = im.convert("RGBA")
im.putalpha(mask) im.putalpha(mask)