This commit is contained in:
Andrew Murray 2025-04-04 19:10:22 +03:00 committed by GitHub
commit d1505153ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
79 changed files with 412 additions and 184 deletions

View File

@ -101,6 +101,7 @@ def assert_image_equal_tofile(
msg: str | None = None,
mode: str | None = None,
) -> None:
img: Image.Image
with Image.open(filename) as img:
if mode:
img = img.convert(mode)
@ -144,6 +145,7 @@ def assert_image_similar_tofile(
epsilon: float,
msg: str | None = None,
) -> None:
img: Image.Image
with Image.open(filename) as img:
assert_image_similar(a, img, epsilon, msg)

View File

@ -94,8 +94,11 @@ def test_good() -> None:
for f in get_files("g"):
try:
im: Image.Image
with Image.open(f) as im:
im.load()
compare: Image.Image
with Image.open(get_compare(f)) as compare:
compare.load()
if im.mode == "P":

View File

@ -277,25 +277,25 @@ def test_apng_mode() -> None:
assert isinstance(im, PngImagePlugin.PngImageFile)
assert im.mode == "P"
im.seek(im.n_frames - 1)
im = im.convert("RGB")
assert im.getpixel((0, 0)) == (0, 255, 0)
assert im.getpixel((64, 32)) == (0, 255, 0)
rgb_im = im.convert("RGB")
assert rgb_im.getpixel((0, 0)) == (0, 255, 0)
assert rgb_im.getpixel((64, 32)) == (0, 255, 0)
with Image.open("Tests/images/apng/mode_palette_alpha.png") as im:
assert isinstance(im, PngImagePlugin.PngImageFile)
assert im.mode == "P"
im.seek(im.n_frames - 1)
im = im.convert("RGBA")
assert im.getpixel((0, 0)) == (0, 255, 0, 255)
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
rgb_im = im.convert("RGBA")
assert rgb_im.getpixel((0, 0)) == (0, 255, 0, 255)
assert rgb_im.getpixel((64, 32)) == (0, 255, 0, 255)
with Image.open("Tests/images/apng/mode_palette_1bit_alpha.png") as im:
assert isinstance(im, PngImagePlugin.PngImageFile)
assert im.mode == "P"
im.seek(im.n_frames - 1)
im = im.convert("RGBA")
assert im.getpixel((0, 0)) == (0, 0, 255, 128)
assert im.getpixel((64, 32)) == (0, 0, 255, 128)
rgb_im = im.convert("RGBA")
assert rgb_im.getpixel((0, 0)) == (0, 0, 255, 128)
assert rgb_im.getpixel((64, 32)) == (0, 0, 255, 128)
def test_apng_chunk_errors() -> None:

View File

@ -14,6 +14,7 @@ import pytest
from PIL import (
AvifImagePlugin,
GifImagePlugin,
Image,
ImageDraw,
ImageFile,
@ -220,6 +221,7 @@ class TestFileAvif:
def test_background_from_gif(self, tmp_path: Path) -> None:
with Image.open("Tests/images/chi.gif") as im:
original_value = im.convert("RGB").getpixel((1, 1))
assert isinstance(original_value, tuple)
# Save as AVIF
out_avif = tmp_path / "temp.avif"
@ -232,6 +234,7 @@ class TestFileAvif:
with Image.open(out_gif) as reread:
reread_value = reread.convert("RGB").getpixel((1, 1))
assert isinstance(reread_value, tuple)
difference = sum([abs(original_value[i] - reread_value[i]) for i in range(3)])
assert difference <= 3
@ -240,6 +243,7 @@ class TestFileAvif:
with Image.open("Tests/images/chi.gif") as im:
im.save(temp_file)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 1
def test_invalid_file(self) -> None:
@ -254,7 +258,9 @@ class TestFileAvif:
assert_image(im, "RGBA", (64, 64))
# image has 876 transparent pixels
assert im.getchannel("A").getcolors()[0] == (876, 0)
colors = im.getchannel("A").getcolors()
assert colors is not None
assert colors[0] == (876, 0)
def test_save_transparent(self, tmp_path: Path) -> None:
im = Image.new("RGBA", (10, 10), (0, 0, 0, 0))
@ -596,10 +602,12 @@ class TestAvifAnimation:
"""
with Image.open(TEST_AVIF_FILE) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 1
assert not im.is_animated
with Image.open("Tests/images/avif/star.avifs") as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 5
assert im.is_animated
@ -610,11 +618,13 @@ class TestAvifAnimation:
"""
with Image.open("Tests/images/avif/star.gif") as original:
assert isinstance(original, GifImagePlugin.GifImageFile)
assert original.n_frames > 1
temp_file = tmp_path / "temp.avif"
original.save(temp_file, save_all=True)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == original.n_frames
# Compare first frame in P mode to frame from original GIF
@ -634,6 +644,7 @@ class TestAvifAnimation:
def check(temp_file: Path) -> None:
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 4
# Compare first frame to original
@ -706,6 +717,7 @@ class TestAvifAnimation:
)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 5
assert im.is_animated
@ -735,6 +747,7 @@ class TestAvifAnimation:
)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 5
assert im.is_animated

View File

@ -160,9 +160,9 @@ def test_save_dib(tmp_path: Path) -> None:
def test_rgba_bitfields() -> None:
# This test image has been manually hexedited
# to change the bitfield compression in the header from XBGR to RGBA
with Image.open("Tests/images/rgb32bf-rgba.bmp") as im:
with Image.open("Tests/images/rgb32bf-rgba.bmp") as bmp_im:
# So before the comparing the image, swap the channels
b, g, r = im.split()[1:]
b, g, r = bmp_im.split()[1:]
im = Image.merge("RGB", (r, g, b))
assert_image_equal_tofile(im, "Tests/images/bmp/q/rgb32bf-xbgr.bmp")

View File

@ -61,6 +61,7 @@ def test_handler(tmp_path: Path) -> None:
def load(self, im: ImageFile.StubImageFile) -> Image.Image:
self.loaded = True
assert im.fp is not None
im.fp.close()
return Image.new("RGB", (1, 1))

View File

@ -26,6 +26,7 @@ def test_invalid_file() -> None:
no_cursors_file = "Tests/images/no_cursors.cur"
cur = CurImagePlugin.CurImageFile(TEST_FILE)
assert cur.fp is not None
cur.fp.close()
with open(no_cursors_file, "rb") as cur.fp:
with pytest.raises(TypeError):

View File

@ -56,6 +56,7 @@ TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds"
)
def test_sanity_dxt1_bc1(image_path: str) -> None:
"""Check DXT1 and BC1 images can be opened"""
target: Image.Image
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
target = target.convert("RGBA")
with Image.open(image_path) as im:
@ -504,9 +505,9 @@ def test_save_dxt5(tmp_path: Path) -> None:
def test_save_dx10_bc5(tmp_path: Path) -> None:
out = tmp_path / "temp.dds"
with Image.open(TEST_FILE_DX10_BC5_TYPELESS) as im:
im.save(out, pixel_format="BC5")
assert_image_similar_tofile(im, out, 9.56)
with Image.open(TEST_FILE_DX10_BC5_TYPELESS) as img:
img.save(out, pixel_format="BC5")
assert_image_similar_tofile(img, out, 9.56)
im = hopper("L")
with pytest.raises(OSError, match="only RGB mode can be written as BC5"):

View File

@ -255,8 +255,8 @@ def test_bytesio_object() -> None:
with Image.open(img_bytes) as img:
img.load()
with Image.open(FILE1_COMPARE) as image1_scale1_compare:
image1_scale1_compare = image1_scale1_compare.convert("RGB")
with Image.open(FILE1_COMPARE) as im:
image1_scale1_compare = im.convert("RGB")
image1_scale1_compare.load()
assert_image_similar(img, image1_scale1_compare, 5)
@ -291,16 +291,16 @@ def test_render_scale1() -> None:
# Zero bounding box
with Image.open(FILE1) as image1_scale1:
image1_scale1.load()
with Image.open(FILE1_COMPARE) as image1_scale1_compare:
image1_scale1_compare = image1_scale1_compare.convert("RGB")
with Image.open(FILE1_COMPARE) as im:
image1_scale1_compare = im.convert("RGB")
image1_scale1_compare.load()
assert_image_similar(image1_scale1, image1_scale1_compare, 5)
# Non-zero bounding box
with Image.open(FILE2) as image2_scale1:
image2_scale1.load()
with Image.open(FILE2_COMPARE) as image2_scale1_compare:
image2_scale1_compare = image2_scale1_compare.convert("RGB")
with Image.open(FILE2_COMPARE) as im:
image2_scale1_compare = im.convert("RGB")
image2_scale1_compare.load()
assert_image_similar(image2_scale1, image2_scale1_compare, 10)
@ -314,8 +314,8 @@ def test_render_scale2() -> None:
with Image.open(FILE1) as image1_scale2:
assert isinstance(image1_scale2, EpsImagePlugin.EpsImageFile)
image1_scale2.load(scale=2)
with Image.open(FILE1_COMPARE_SCALE2) as image1_scale2_compare:
image1_scale2_compare = image1_scale2_compare.convert("RGB")
with Image.open(FILE1_COMPARE_SCALE2) as im:
image1_scale2_compare = im.convert("RGB")
image1_scale2_compare.load()
assert_image_similar(image1_scale2, image1_scale2_compare, 5)
@ -323,8 +323,8 @@ def test_render_scale2() -> None:
with Image.open(FILE2) as image2_scale2:
assert isinstance(image2_scale2, EpsImagePlugin.EpsImageFile)
image2_scale2.load(scale=2)
with Image.open(FILE2_COMPARE_SCALE2) as image2_scale2_compare:
image2_scale2_compare = image2_scale2_compare.convert("RGB")
with Image.open(FILE2_COMPARE_SCALE2) as im:
image2_scale2_compare = im.convert("RGB")
image2_scale2_compare.load()
assert_image_similar(image2_scale2, image2_scale2_compare, 10)
@ -334,9 +334,9 @@ def test_render_scale2() -> None:
"filename", (FILE1, FILE2, "Tests/images/eps/illu10_preview.eps")
)
def test_resize(filename: str) -> None:
with Image.open(filename) as im:
with Image.open(filename) as img:
new_size = (100, 100)
im = im.resize(new_size)
im = img.resize(new_size)
assert im.size == new_size

View File

@ -43,6 +43,8 @@ def test_sanity() -> None:
def test_prefix_chunk(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(ImageFile, "LOAD_TRUNCATED_IMAGES", True)
with Image.open(animated_test_file_with_prefix_chunk) as im:
assert isinstance(im, FliImagePlugin.FliImageFile)
assert im.mode == "P"
assert im.size == (320, 200)
assert im.format == "FLI"
@ -50,6 +52,7 @@ def test_prefix_chunk(monkeypatch: pytest.MonkeyPatch) -> None:
assert im.is_animated
palette = im.getpalette()
assert palette is not None
assert palette[3:6] == [255, 255, 255]
assert palette[381:384] == [204, 204, 12]
assert palette[765:] == [252, 0, 0]

View File

@ -224,6 +224,7 @@ def test_optimize_if_palette_can_be_reduced_by_half() -> None:
out = BytesIO()
im.save(out, "GIF", optimize=optimize)
with Image.open(out) as reloaded:
assert reloaded.palette is not None
assert len(reloaded.palette.palette) // 3 == colors
@ -280,6 +281,7 @@ def test_roundtrip_save_all(tmp_path: Path) -> None:
im.save(out, save_all=True)
with Image.open(out) as reread:
assert isinstance(reread, GifImagePlugin.GifImageFile)
assert reread.n_frames == 5
@ -305,6 +307,7 @@ def test_roundtrip_save_all_1(tmp_path: Path) -> None:
),
)
def test_loading_multiple_palettes(path: str, mode: str) -> None:
im: Image.Image
with Image.open(path) as im:
assert im.mode == "P"
assert im.palette is not None
@ -338,7 +341,7 @@ def test_headers_saving_for_animated_gifs(tmp_path: Path) -> None:
def test_palette_handling(tmp_path: Path) -> None:
# see https://github.com/python-pillow/Pillow/issues/513
im: Image.Image
with Image.open(TEST_GIF) as im:
im = im.convert("RGB")
@ -362,8 +365,8 @@ def test_palette_434(tmp_path: Path) -> None:
return reloaded
orig = "Tests/images/test.colors.gif"
with Image.open(orig) as im:
im: Image.Image
with Image.open("Tests/images/test.colors.gif") as im:
with roundtrip(im) as reloaded:
assert_image_similar(im, reloaded, 1)
with roundtrip(im, optimize=True) as reloaded:
@ -378,6 +381,7 @@ def test_palette_434(tmp_path: Path) -> None:
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_bmp_mode(tmp_path: Path) -> None:
img: Image.Image
with Image.open(TEST_GIF) as img:
img = img.convert("RGB")
@ -390,6 +394,7 @@ def test_save_netpbm_bmp_mode(tmp_path: Path) -> None:
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_l_mode(tmp_path: Path) -> None:
img: Image.Image
with Image.open(TEST_GIF) as img:
img = img.convert("L")
@ -540,7 +545,9 @@ def test_dispose_background_transparency() -> None:
img.seek(2)
px = img.load()
assert px is not None
assert px[35, 30][3] == 0
value = px[35, 30]
assert isinstance(value, tuple)
assert value[3] == 0
@pytest.mark.parametrize(
@ -1017,9 +1024,9 @@ def test_webp_background(tmp_path: Path) -> None:
# Test opaque WebP background
if features.check("webp"):
with Image.open("Tests/images/hopper.webp") as im:
assert im.info["background"] == (255, 255, 255, 255)
im.save(out)
with Image.open("Tests/images/hopper.webp") as img:
assert img.info["background"] == (255, 255, 255, 255)
img.save(out)
# Test non-opaque WebP background
im = Image.new("L", (100, 100), "#000")
@ -1028,6 +1035,7 @@ def test_webp_background(tmp_path: Path) -> None:
def test_comment(tmp_path: Path) -> None:
im: Image.Image
with Image.open(TEST_GIF) as im:
assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0"
@ -1358,7 +1366,9 @@ def test_palette_save_all_P(tmp_path: Path) -> None:
with Image.open(out) as im:
# Assert that the frames are correct, and each frame has the same palette
assert_image_equal(im.convert("RGB"), frames[0].convert("RGB"))
assert isinstance(im, GifImagePlugin.GifImageFile)
assert im.palette is not None
assert im.global_palette is not None
assert im.palette.palette == im.global_palette.palette
im.seek(1)
@ -1422,7 +1432,9 @@ def test_getdata(monkeypatch: pytest.MonkeyPatch) -> None:
def test_lzw_bits() -> None:
# see https://github.com/python-pillow/Pillow/issues/2811
with Image.open("Tests/images/issue_2811.gif") as im:
assert im.tile[0][3][0] == 11 # LZW bits
args = im.tile[0][3]
assert isinstance(args, tuple)
assert args[0] == 11 # LZW bits
# codec error prepatch
im.load()
@ -1477,7 +1489,11 @@ def test_saving_rgba(tmp_path: Path) -> None:
with Image.open(out) as reloaded:
reloaded_rgba = reloaded.convert("RGBA")
assert reloaded_rgba.load()[0, 0][3] == 0
px = reloaded_rgba.load()
assert px is not None
value = px[0, 0]
assert isinstance(value, tuple)
assert value[3] == 0
@pytest.mark.parametrize("params", ({}, {"disposal": 2, "optimize": False}))

View File

@ -59,8 +59,9 @@ def test_handler(tmp_path: Path) -> None:
def open(self, im: Image.Image) -> None:
self.opened = True
def load(self, im: Image.Image) -> Image.Image:
def load(self, im: ImageFile.ImageFile) -> Image.Image:
self.loaded = True
assert im.fp is not None
im.fp.close()
return Image.new("RGB", (1, 1))

View File

@ -61,8 +61,9 @@ def test_handler(tmp_path: Path) -> None:
def open(self, im: Image.Image) -> None:
self.opened = True
def load(self, im: Image.Image) -> Image.Image:
def load(self, im: ImageFile.ImageFile) -> Image.Image:
self.loaded = True
assert im.fp is not None
im.fp.close()
return Image.new("RGB", (1, 1))

View File

@ -28,7 +28,7 @@ def test_getiptcinfo_jpg_none() -> None:
# Arrange
with hopper() as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
iptc = IptcImagePlugin.getiptcinfo(im) # type: ignore[arg-type]
# Assert
assert iptc is None

View File

@ -132,26 +132,30 @@ class TestFileJpeg:
f = "Tests/images/pil_sample_cmyk.jpg"
with Image.open(f) as im:
# the source image has red pixels in the upper left corner.
c, m, y, k = (x / 255.0 for x in im.getpixel((0, 0)))
value = im.getpixel((0, 0))
assert isinstance(value, tuple)
c, m, y, k = (x / 255.0 for x in value)
assert c == 0.0
assert m > 0.8
assert y > 0.8
assert k == 0.0
# the opposite corner is black
c, m, y, k = (
x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))
)
value = im.getpixel((im.size[0] - 1, im.size[1] - 1))
assert isinstance(value, tuple)
c, m, y, k = (x / 255.0 for x in value)
assert k > 0.9
# roundtrip, and check again
im = self.roundtrip(im)
c, m, y, k = (x / 255.0 for x in im.getpixel((0, 0)))
value = im.getpixel((0, 0))
assert isinstance(value, tuple)
c, m, y, k = (x / 255.0 for x in value)
assert c == 0.0
assert m > 0.8
assert y > 0.8
assert k == 0.0
c, m, y, k = (
x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))
)
value = im.getpixel((im.size[0] - 1, im.size[1] - 1))
assert isinstance(value, tuple)
c, m, y, k = (x / 255.0 for x in value)
assert k > 0.9
def test_rgb(self) -> None:
@ -334,8 +338,10 @@ class TestFileJpeg:
# Reading
with Image.open("Tests/images/exif_gps.jpg") as im:
exif = im._getexif()
assert exif[gps_index] == expected_exif_gps
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[gps_index] == expected_exif_gps
# Writing
f = tmp_path / "temp.jpg"
@ -344,8 +350,10 @@ class TestFileJpeg:
hopper().save(f, exif=exif)
with Image.open(f) as reloaded:
exif = reloaded._getexif()
assert exif[gps_index] == expected_exif_gps
assert isinstance(reloaded, JpegImagePlugin.JpegImageFile)
exif_data = reloaded._getexif()
assert exif_data is not None
assert exif_data[gps_index] == expected_exif_gps
def test_empty_exif_gps(self) -> None:
with Image.open("Tests/images/empty_gps_ifd.jpg") as im:
@ -372,6 +380,7 @@ class TestFileJpeg:
exifs = []
for i in range(2):
with Image.open("Tests/images/exif-200dpcm.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exifs.append(im._getexif())
assert exifs[0] == exifs[1]
@ -405,13 +414,18 @@ class TestFileJpeg:
}
with Image.open("Tests/images/exif_gps.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exif = im._getexif()
assert exif is not None
for tag, value in expected_exif.items():
assert value == exif[tag]
def test_exif_gps_typeerror(self) -> None:
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
# Should not raise a TypeError
im._getexif()
@ -491,7 +505,9 @@ class TestFileJpeg:
def test_exif(self) -> None:
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
info = im._getexif()
assert info is not None
assert info[305] == "Adobe Photoshop CS Macintosh"
def test_get_child_images(self) -> None:
@ -677,10 +693,12 @@ class TestFileJpeg:
def test_save_multiple_16bit_qtables(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
im2 = self.roundtrip(im, qtables="keep")
assert isinstance(im, JpegImagePlugin.JpegImageFile)
assert im.quantization == im2.quantization
def test_save_single_16bit_qtable(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
im2 = self.roundtrip(im, qtables={0: im.quantization[0]})
assert len(im2.quantization) == 1
assert im2.quantization[0] == im.quantization[0]
@ -889,7 +907,10 @@ class TestFileJpeg:
# in contrast to normal 8
with Image.open("Tests/images/exif-ifd-offset.jpg") as im:
# Act / Assert
assert im._getexif()[306] == "2017:03:13 23:03:09"
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exif = im._getexif()
assert exif is not None
assert exif[306] == "2017:03:13 23:03:09"
def test_multiple_exif(self) -> None:
with Image.open("Tests/images/multiple_exif.jpg") as im:
@ -1110,8 +1131,9 @@ class TestFileCloseW32:
im.save(tmpfile)
im = Image.open(tmpfile)
assert im.fp is not None
assert not im.fp.closed
fp = im.fp
assert not fp.closed
with pytest.raises(OSError):
os.remove(tmpfile)
im.load()

View File

@ -164,7 +164,7 @@ def test_reduce() -> None:
with Image.open("Tests/images/test-card-lossless.jp2") as im:
assert callable(im.reduce)
im.reduce = 2
im.reduce = 2 # type: ignore[method-assign, assignment]
assert im.reduce == 2
im.load()

View File

@ -11,7 +11,15 @@ from typing import Any, NamedTuple
import pytest
from PIL import Image, ImageFilter, ImageOps, TiffImagePlugin, TiffTags, features
from PIL import (
Image,
ImageFile,
ImageFilter,
ImageOps,
TiffImagePlugin,
TiffTags,
features,
)
from PIL.TiffImagePlugin import OSUBFILETYPE, SAMPLEFORMAT, STRIPOFFSETS, SUBIFD
from .helper import (
@ -27,7 +35,7 @@ from .helper import (
@skip_unless_feature("libtiff")
class LibTiffTestCase:
def _assert_noerr(self, tmp_path: Path, im: TiffImagePlugin.TiffImageFile) -> None:
def _assert_noerr(self, tmp_path: Path, im: ImageFile.ImageFile) -> None:
"""Helper tests that assert basic sanity about the g4 tiff reading"""
# 1 bit
assert im.mode == "1"
@ -441,7 +449,6 @@ class TestFileLibTiff(LibTiffTestCase):
assert isinstance(orig, TiffImagePlugin.TiffImageFile)
out = tmp_path / "temp.tif"
orig.tag[269] = "temp.tif"
orig.save(out)
@ -469,8 +476,8 @@ class TestFileLibTiff(LibTiffTestCase):
# test case from irc, how to do blur on b/w image
# and save to compressed tif.
out = tmp_path / "temp.tif"
with Image.open("Tests/images/pport_g4.tif") as im:
im = im.convert("L")
with Image.open("Tests/images/pport_g4.tif") as img:
im = img.convert("L")
im = im.filter(ImageFilter.GaussianBlur(4))
im.save(out, compression="tiff_adobe_deflate")
@ -564,8 +571,9 @@ class TestFileLibTiff(LibTiffTestCase):
im.save(out, compression=compression)
def test_fp_leak(self) -> None:
im: Image.Image | None = Image.open("Tests/images/hopper_g4_500.tif")
im: ImageFile.ImageFile | None = Image.open("Tests/images/hopper_g4_500.tif")
assert im is not None
assert im.fp is not None
fn = im.fp.fileno()
os.fstat(fn)
@ -1053,8 +1061,8 @@ class TestFileLibTiff(LibTiffTestCase):
# Set EXIF Orientation to 2
data = data[:102] + b"\x02" + data[103:]
with Image.open(io.BytesIO(data)) as im:
im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
with Image.open(io.BytesIO(data)) as img:
im = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png")
def test_open_missing_samplesperpixel(self) -> None:
@ -1122,9 +1130,8 @@ class TestFileLibTiff(LibTiffTestCase):
with Image.open("Tests/images/g4_orientation_1.tif") as base_im:
for i in range(2, 9):
with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im:
im = ImageOps.exif_transpose(im)
assert_image_similar(base_im, im, 0.7)
transposed_im = ImageOps.exif_transpose(im)
assert_image_similar(base_im, transposed_im, 0.7)
@pytest.mark.parametrize(
"test_file",

View File

@ -22,10 +22,10 @@ def test_sanity() -> None:
# Adjust for the gamma of 2.2 encoded into the file
lut = ImagePalette.make_gamma_lut(1 / 2.2)
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
im1 = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
im2 = hopper("RGBA")
assert_image_similar(im, im2, 10)
assert_image_similar(im1, im2, 10)
def test_n_frames() -> None:

View File

@ -120,9 +120,11 @@ def test_ignore_frame_size() -> None:
# Ignore the different size of the second frame
# since this is not a "Large Thumbnail" image
with Image.open("Tests/images/ignore_frame_size.mpo") as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
assert im.size == (64, 64)
im.seek(1)
assert im.mpinfo is not None
assert (
im.mpinfo[0xB002][1]["Attribute"]["MPType"]
== "Multi-Frame Image: (Disparity)"
@ -155,7 +157,9 @@ def test_reload_exif_after_seek() -> None:
@pytest.mark.parametrize("test_file", test_files)
def test_mp(test_file: str) -> None:
with Image.open(test_file) as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
mpinfo = im._getmp()
assert mpinfo is not None
assert mpinfo[45056] == b"0100"
assert mpinfo[45057] == 2
@ -164,7 +168,9 @@ def test_mp_offset() -> None:
# This image has been manually hexedited to have an IFD offset of 10
# in APP2 data, in contrast to normal 8
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
mpinfo = im._getmp()
assert mpinfo is not None
assert mpinfo[45056] == b"0100"
assert mpinfo[45057] == 2
@ -180,7 +186,9 @@ def test_mp_no_data() -> None:
@pytest.mark.parametrize("test_file", test_files)
def test_mp_attribute(test_file: str) -> None:
with Image.open(test_file) as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
mpinfo = im._getmp()
assert mpinfo is not None
for frame_number, mpentry in enumerate(mpinfo[0xB002]):
mpattr = mpentry["Attribute"]
if frame_number:
@ -281,6 +289,7 @@ def test_save(test_file: str) -> None:
def test_save_all() -> None:
im: Image.Image
for test_file in test_files:
with Image.open(test_file) as im:
im_reloaded = roundtrip(im, save_all=True)

View File

@ -93,6 +93,7 @@ class TestFilePng:
hopper("RGB").save(test_file)
im: Image.Image
with Image.open(test_file) as im:
im.load()
assert im.mode == "RGB"
@ -103,6 +104,8 @@ class TestFilePng:
for mode in ["1", "L", "P", "RGB", "I", "I;16", "I;16B"]:
im = hopper(mode)
im.save(test_file)
reloaded: Image.Image
with Image.open(test_file) as reloaded:
if mode in ("I", "I;16B"):
reloaded = reloaded.convert(mode)
@ -225,11 +228,13 @@ class TestFilePng:
test_file = "Tests/images/pil123p.png"
with Image.open(test_file) as im:
assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
assert_image(im, "RGBA", (162, 150))
rgba_im = im.convert("RGBA")
assert_image(rgba_im, "RGBA", (162, 150))
# image has 124 unique alpha values
assert len(im.getchannel("A").getcolors()) == 124
colors = rgba_im.getchannel("A").getcolors()
assert colors is not None
assert len(colors) == 124
def test_load_transparent_rgb(self) -> None:
test_file = "Tests/images/rgb_trns.png"
@ -237,11 +242,13 @@ class TestFilePng:
assert im.info["transparency"] == (0, 255, 52)
assert_image(im, "RGB", (64, 64))
im = im.convert("RGBA")
assert_image(im, "RGBA", (64, 64))
rgba_im = im.convert("RGBA")
assert_image(rgba_im, "RGBA", (64, 64))
# image has 876 transparent pixels
assert im.getchannel("A").getcolors()[0][0] == 876
colors = rgba_im.getchannel("A").getcolors()
assert colors is not None
assert colors[0][0] == 876
def test_save_p_transparent_palette(self, tmp_path: Path) -> None:
in_file = "Tests/images/pil123p.png"
@ -258,11 +265,13 @@ class TestFilePng:
assert len(im.info["transparency"]) == 256
assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
assert_image(im, "RGBA", (162, 150))
rgba_im = im.convert("RGBA")
assert_image(rgba_im, "RGBA", (162, 150))
# image has 124 unique alpha values
assert len(im.getchannel("A").getcolors()) == 124
colors = rgba_im.getchannel("A").getcolors()
assert colors is not None
assert len(colors) == 124
def test_save_p_single_transparency(self, tmp_path: Path) -> None:
in_file = "Tests/images/p_trns_single.png"
@ -279,13 +288,15 @@ class TestFilePng:
assert im.info["transparency"] == 164
assert im.getpixel((31, 31)) == 164
assert_image(im, "P", (64, 64))
im = im.convert("RGBA")
assert_image(im, "RGBA", (64, 64))
rgba_im = im.convert("RGBA")
assert_image(rgba_im, "RGBA", (64, 64))
assert im.getpixel((31, 31)) == (0, 255, 52, 0)
assert rgba_im.getpixel((31, 31)) == (0, 255, 52, 0)
# image has 876 transparent pixels
assert im.getchannel("A").getcolors()[0][0] == 876
colors = rgba_im.getchannel("A").getcolors()
assert colors is not None
assert colors[0][0] == 876
def test_save_p_transparent_black(self, tmp_path: Path) -> None:
# check if solid black image with full transparency
@ -313,7 +324,9 @@ class TestFilePng:
assert im.info["transparency"] == 255
im_rgba = im.convert("RGBA")
assert im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
colors = im_rgba.getchannel("A").getcolors()
assert colors is not None
assert colors[0][0] == num_transparent
test_file = tmp_path / "temp.png"
im.save(test_file)
@ -324,7 +337,9 @@ class TestFilePng:
assert_image_equal(im, test_im)
test_im_rgba = test_im.convert("RGBA")
assert test_im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
colors = test_im_rgba.getchannel("A").getcolors()
assert colors is not None
assert colors[0][0] == num_transparent
def test_save_rgb_single_transparency(self, tmp_path: Path) -> None:
in_file = "Tests/images/caption_6_33_22.png"
@ -671,6 +686,9 @@ class TestFilePng:
im.save(out, bits=4, save_all=save_all)
with Image.open(out) as reloaded:
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
assert reloaded.png is not None
assert reloaded.png.im_palette is not None
assert len(reloaded.png.im_palette[1]) == 48
def test_plte_length(self, tmp_path: Path) -> None:
@ -681,6 +699,9 @@ class TestFilePng:
im.save(out)
with Image.open(out) as reloaded:
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
assert reloaded.png is not None
assert reloaded.png.im_palette is not None
assert len(reloaded.png.im_palette[1]) == 3
def test_getxmp(self) -> None:
@ -702,13 +723,17 @@ class TestFilePng:
def test_exif(self) -> None:
# With an EXIF chunk
with Image.open("Tests/images/exif.png") as im:
exif = im._getexif()
assert exif[274] == 1
assert isinstance(im, PngImagePlugin.PngImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[274] == 1
# With an ImageMagick zTXt chunk
with Image.open("Tests/images/exif_imagemagick.png") as im:
exif = im._getexif()
assert exif[274] == 1
assert isinstance(im, PngImagePlugin.PngImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[274] == 1
# Assert that info still can be extracted
# when the image is no longer a PngImageFile instance
@ -717,8 +742,10 @@ class TestFilePng:
# With a tEXt chunk
with Image.open("Tests/images/exif_text.png") as im:
exif = im._getexif()
assert exif[274] == 1
assert isinstance(im, PngImagePlugin.PngImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[274] == 1
# With XMP tags
with Image.open("Tests/images/xmp_tags_orientation.png") as im:
@ -740,7 +767,9 @@ class TestFilePng:
im.save(test_file, exif=im.getexif())
with Image.open(test_file) as reloaded:
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
exif = reloaded._getexif()
assert exif is not None
assert exif[274] == 1
@mark_if_feature_version(
@ -752,7 +781,9 @@ class TestFilePng:
im.save(test_file, exif=im.getexif())
with Image.open(test_file) as reloaded:
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
exif = reloaded._getexif()
assert exif is not None
assert exif[305] == "Adobe Photoshop CS Macintosh"
def test_exif_argument(self, tmp_path: Path) -> None:
@ -776,7 +807,6 @@ class TestFilePng:
@pytest.mark.parametrize("buffer", (True, False))
def test_save_stdout(self, buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None:
class MyStdOut:
buffer = BytesIO()
@ -785,7 +815,7 @@ class TestFilePng:
monkeypatch.setattr(sys, "stdout", mystdout)
with Image.open(TEST_PNG_FILE) as im:
im.save(sys.stdout, "PNG")
im.save(sys.stdout, "PNG") # type: ignore[arg-type]
if isinstance(mystdout, MyStdOut):
mystdout = mystdout.buffer

View File

@ -365,7 +365,6 @@ def test_mimetypes(tmp_path: Path) -> None:
@pytest.mark.parametrize("buffer", (True, False))
def test_save_stdout(buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None:
class MyStdOut:
buffer = BytesIO()
@ -374,7 +373,7 @@ def test_save_stdout(buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(sys, "stdout", mystdout)
with Image.open(TEST_FILE) as im:
im.save(sys.stdout, "PPM")
im.save(sys.stdout, "PPM") # type: ignore[arg-type]
if isinstance(mystdout, MyStdOut):
mystdout = mystdout.buffer

View File

@ -84,8 +84,8 @@ def test_rgbx() -> None:
with Image.open(io.BytesIO(data)) as im:
r, g, b = im.split()
im = Image.merge("RGB", (b, g, r))
assert_image_equal_tofile(im, os.path.join(EXTRA_DIR, "32bpp.png"))
im_bgr = Image.merge("RGB", (b, g, r))
assert_image_equal_tofile(im_bgr, os.path.join(EXTRA_DIR, "32bpp.png"))
@pytest.mark.skipif(

View File

@ -220,12 +220,16 @@ def test_horizontal_orientations() -> None:
with Image.open("Tests/images/rgb32rle_top_right.tga") as im:
px = im.load()
assert px is not None
assert px[90, 90][:3] == (0, 0, 0)
value = px[90, 90]
assert isinstance(value, tuple)
assert value[:3] == (0, 0, 0)
with Image.open("Tests/images/rgb32rle_bottom_right.tga") as im:
px = im.load()
assert px is not None
assert px[90, 90][:3] == (0, 255, 0)
value = px[90, 90]
assert isinstance(value, tuple)
assert value[:3] == (0, 255, 0)
def test_save_rle(tmp_path: Path) -> None:
@ -268,13 +272,17 @@ def test_save_l_transparency(tmp_path: Path) -> None:
in_file = "Tests/images/la.tga"
with Image.open(in_file) as im:
assert im.mode == "LA"
assert im.getchannel("A").getcolors()[0][0] == num_transparent
colors = im.getchannel("A").getcolors()
assert colors is not None
assert colors[0][0] == num_transparent
out = tmp_path / "temp.tga"
im.save(out)
with Image.open(out) as test_im:
assert test_im.mode == "LA"
assert test_im.getchannel("A").getcolors()[0][0] == num_transparent
colors = test_im.getchannel("A").getcolors()
assert colors is not None
assert colors[0][0] == num_transparent
assert_image_equal(im, test_im)

View File

@ -395,6 +395,7 @@ class TestFileTiff:
assert isinstance(im, TiffImagePlugin.TiffImageFile)
# Act
assert isinstance(im, TiffImagePlugin.TiffImageFile)
ret = str(im.ifd)
# Assert
@ -762,13 +763,13 @@ class TestFileTiff:
def test_tiff_save_all(self) -> None:
mp = BytesIO()
with Image.open("Tests/images/multipage.tiff") as im:
im.save(mp, format="tiff", save_all=True)
with Image.open("Tests/images/multipage.tiff") as img:
img.save(mp, format="tiff", save_all=True)
mp.seek(0, os.SEEK_SET)
with Image.open(mp) as im:
assert isinstance(im, TiffImagePlugin.TiffImageFile)
assert im.n_frames == 3
with Image.open(mp) as img:
assert isinstance(img, TiffImagePlugin.TiffImageFile)
assert img.n_frames == 3
# Test appending images
mp = BytesIO()
@ -956,6 +957,7 @@ class TestFileTiff:
im = Image.open(tmpfile)
fp = im.fp
assert fp is not None
assert not fp.closed
im.load()
assert fp.closed
@ -969,6 +971,7 @@ class TestFileTiff:
with open(tmpfile, "rb") as f:
im = Image.open(f)
fp = im.fp
assert fp is not None
assert not fp.closed
im.load()
assert not fp.closed
@ -1019,8 +1022,9 @@ class TestFileTiffW32:
im.save(tmpfile)
im = Image.open(tmpfile)
assert im.fp is not None
assert not im.fp.closed
fp = im.fp
assert not fp.closed
with pytest.raises(OSError):
os.remove(tmpfile)
im.load()

View File

@ -175,13 +175,13 @@ def test_change_stripbytecounts_tag_type(tmp_path: Path) -> None:
del info[278]
# Resize the image so that STRIPBYTECOUNTS will be larger than a SHORT
im = im.resize((500, 500))
info[TiffImagePlugin.IMAGEWIDTH] = im.width
resized_im = im.resize((500, 500))
info[TiffImagePlugin.IMAGEWIDTH] = resized_im.width
# STRIPBYTECOUNTS can be a SHORT or a LONG
info.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] = TiffTags.SHORT
im.save(out, tiffinfo=info)
resized_im.save(out, tiffinfo=info)
with Image.open(out) as reloaded:
assert isinstance(reloaded, TiffImagePlugin.TiffImageFile)

View File

@ -219,6 +219,7 @@ class TestFileWebp:
# Save P mode GIF with background
with Image.open("Tests/images/chi.gif") as im:
original_value = im.convert("RGB").getpixel((1, 1))
assert isinstance(original_value, tuple)
# Save as WEBP
im.save(out_webp, save_all=True)
@ -230,6 +231,7 @@ class TestFileWebp:
with Image.open(out_gif) as reread:
reread_value = reread.convert("RGB").getpixel((1, 1))
assert isinstance(reread_value, tuple)
difference = sum(abs(original_value[i] - reread_value[i]) for i in range(3))
assert difference < 5

View File

@ -22,11 +22,13 @@ except ImportError:
def test_read_exif_metadata() -> None:
file_path = "Tests/images/flower.webp"
with Image.open(file_path) as image:
assert isinstance(image, WebPImagePlugin.WebPImageFile)
assert image.format == "WEBP"
exif_data = image.info.get("exif", None)
assert exif_data
exif = image._getexif()
assert exif is not None
# Camera make
assert exif[271] == "Canon"

View File

@ -615,8 +615,8 @@ class TestImage:
assert im.mode == mode
assert im.getpixel((0, 0)) == 0
assert im.getpixel((255, 255)) == 255
with Image.open(target_file) as target:
target = target.convert(mode)
with Image.open(target_file) as img:
target = img.convert(mode)
assert_image_equal(im, target)
def test_radial_gradient_wrong_mode(self) -> None:
@ -640,8 +640,8 @@ class TestImage:
assert im.mode == mode
assert im.getpixel((0, 0)) == 255
assert im.getpixel((128, 128)) == 0
with Image.open(target_file) as target:
target = target.convert(mode)
with Image.open(target_file) as img:
target = img.convert(mode)
assert_image_equal(im, target)
def test_register_extensions(self) -> None:
@ -662,8 +662,8 @@ class TestImage:
def test_remap_palette(self) -> None:
# Test identity transform
with Image.open("Tests/images/hopper.gif") as im:
assert_image_equal(im, im.remap_palette(list(range(256))))
with Image.open("Tests/images/hopper.gif") as img:
assert_image_equal(img, img.remap_palette(list(range(256))))
# Test identity transform with an RGBA palette
im = Image.new("P", (256, 1))
@ -673,6 +673,7 @@ class TestImage:
im_remapped = im.remap_palette(list(range(256)))
assert_image_equal(im, im_remapped)
assert im.palette is not None
assert im_remapped.palette is not None
assert im.palette.palette == im_remapped.palette.palette
# Test illegal image mode

View File

@ -76,8 +76,8 @@ def test_8bit() -> None:
def test_16bit() -> None:
with Image.open("Tests/images/16bit.cropped.tif") as im:
_test_float_conversion(im)
with Image.open("Tests/images/16bit.cropped.tif") as img:
_test_float_conversion(img)
for color in (65535, 65536):
im = Image.new("I", (1, 1), color)

View File

@ -78,13 +78,13 @@ def test_crop_crash() -> None:
extents = (1, 1, 10, 10)
# works prepatch
with Image.open(test_img) as img:
img2 = img.crop(extents)
img2.load()
img1 = img.crop(extents)
img1.load()
# fail prepatch
with Image.open(test_img) as img:
img = img.crop(extents)
img.load()
img2 = img.crop(extents)
img2.load()
def test_crop_zero() -> None:

View File

@ -38,6 +38,7 @@ def test_close_after_load(caplog: pytest.LogCaptureFixture) -> None:
def test_contextmanager() -> None:
fn = None
with Image.open("Tests/images/hopper.gif") as im:
assert im.fp is not None
fn = im.fp.fileno()
os.fstat(fn)

View File

@ -62,6 +62,7 @@ def test_putpalette_with_alpha_values() -> None:
expected = im.convert("RGBA")
palette = im.getpalette()
assert palette is not None
transparency = im.info.pop("transparency")
palette_with_alpha_values = []

View File

@ -56,20 +56,21 @@ def test_rgba_quantize() -> None:
def test_quantize() -> None:
with Image.open("Tests/images/caption_6_33_22.png") as image:
image = image.convert("RGB")
converted = image.quantize()
converted = image.convert("RGB")
converted = converted.quantize()
assert converted.mode == "P"
assert_image_similar(converted.convert("RGB"), image, 1)
def test_quantize_no_dither() -> None:
image = hopper()
palette: Image.Image
with Image.open("Tests/images/caption_6_33_22.png") as palette:
palette = palette.convert("P")
converted = image.quantize(dither=Image.Dither.NONE, palette=palette)
converted = hopper().quantize(dither=Image.Dither.NONE, palette=palette)
assert converted.mode == "P"
assert converted.palette is not None
assert palette.palette is not None
assert converted.palette.palette == palette.palette.palette
@ -93,8 +94,8 @@ def test_quantize_no_dither2() -> None:
def test_quantize_dither_diff() -> None:
image = hopper()
with Image.open("Tests/images/caption_6_33_22.png") as palette:
palette = palette.convert("P")
with Image.open("Tests/images/caption_6_33_22.png") as im:
palette = im.convert("P")
dither = image.quantize(dither=Image.Dither.FLOYDSTEINBERG, palette=palette)
nodither = image.quantize(dither=Image.Dither.NONE, palette=palette)

View File

@ -313,8 +313,8 @@ class TestImageResize:
@skip_unless_feature("libtiff")
def test_transposed(self) -> None:
with Image.open("Tests/images/g4_orientation_5.tif") as im:
im = im.resize((64, 64))
with Image.open("Tests/images/g4_orientation_5.tif") as img:
im = img.resize((64, 64))
assert im.size == (64, 64)
@pytest.mark.parametrize(

View File

@ -40,8 +40,8 @@ def test_mode(mode: str) -> None:
@pytest.mark.parametrize("angle", (0, 90, 180, 270))
def test_angle(angle: int) -> None:
with Image.open("Tests/images/test-card.png") as im:
rotate(im, im.mode, angle)
with Image.open("Tests/images/test-card.png") as img:
rotate(img, img.mode, angle)
im = hopper()
assert_image_equal(im.rotate(angle), im.rotate(angle, expand=1))
@ -74,6 +74,7 @@ def test_center_0() -> None:
im = hopper()
im = im.rotate(45, center=(0, 0), resample=Image.Resampling.BICUBIC)
target: Image.Image
with Image.open("Tests/images/hopper_45.png") as target:
target_origin = target.size[1] / 2
target = target.crop((0, target_origin, 128, target_origin + 128))
@ -85,6 +86,7 @@ def test_center_14() -> None:
im = hopper()
im = im.rotate(45, center=(14, 14), resample=Image.Resampling.BICUBIC)
target: Image.Image
with Image.open("Tests/images/hopper_45.png") as target:
target_origin = target.size[1] / 2 - 14
target = target.crop((6, target_origin, 128 + 6, target_origin + 128))
@ -94,6 +96,8 @@ def test_center_14() -> None:
def test_translate() -> None:
im = hopper()
target: Image.Image
with Image.open("Tests/images/hopper_45.png") as target:
target_origin = (target.size[1] / 2 - 64) - 5
target = target.crop(

View File

@ -156,6 +156,7 @@ def test_reducing_gap_values() -> None:
def test_reducing_gap_for_DCT_scaling() -> None:
ref: Image.Image
with Image.open("Tests/images/hopper.jpg") as ref:
# thumbnail should call draft with reducing_gap scale
ref.draft(None, (18 * 3, 18 * 3))

View File

@ -48,6 +48,7 @@ class TestImageTransform:
im.size, Image.Transform.AFFINE, [1, 0, 0, 0, 1, 0]
)
assert im.palette is not None
assert transformed.palette is not None
assert im.palette.palette == transformed.palette.palette
def test_extent(self) -> None:
@ -246,14 +247,14 @@ class TestImageTransform:
def test_missing_method_data(self) -> None:
with hopper() as im:
with pytest.raises(ValueError):
im.transform((100, 100), None)
im.transform((100, 100), None) # type: ignore[arg-type]
@pytest.mark.parametrize("resample", (Image.Resampling.BOX, "unknown"))
def test_unknown_resampling_filter(self, resample: Image.Resampling | str) -> None:
with hopper() as im:
(w, h) = im.size
with pytest.raises(ValueError):
im.transform((100, 100), Image.Transform.EXTENT, (0, 0, w, h), resample)
im.transform((100, 100), Image.Transform.EXTENT, (0, 0, w, h), resample) # type: ignore[arg-type]
class TestImageTransformAffine:

View File

@ -194,6 +194,7 @@ def test_bitmap() -> None:
# Arrange
im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im)
small: Image.Image
with Image.open("Tests/images/pil123rgba.png") as small:
small = small.resize((50, 50), Image.Resampling.NEAREST)

View File

@ -245,8 +245,8 @@ def test_colorize_2color() -> None:
# Test the colorizing function with 2-color functionality
# Open test image (256px by 10px, black to white)
with Image.open("Tests/images/bw_gradient.png") as im:
im = im.convert("L")
with Image.open("Tests/images/bw_gradient.png") as img:
im = img.convert("L")
# Create image with original 2-color functionality
im_test = ImageOps.colorize(im, "red", "green")
@ -285,8 +285,8 @@ def test_colorize_2color_offset() -> None:
# Test the colorizing function with 2-color functionality and offset
# Open test image (256px by 10px, black to white)
with Image.open("Tests/images/bw_gradient.png") as im:
im = im.convert("L")
with Image.open("Tests/images/bw_gradient.png") as img:
im = img.convert("L")
# Create image with original 2-color functionality with offsets
im_test = ImageOps.colorize(
@ -327,8 +327,8 @@ def test_colorize_3color_offset() -> None:
# Test the colorizing function with 3-color functionality and offset
# Open test image (256px by 10px, black to white)
with Image.open("Tests/images/bw_gradient.png") as im:
im = im.convert("L")
with Image.open("Tests/images/bw_gradient.png") as img:
im = img.convert("L")
# Create image with new three color functionality with offsets
im_test = ImageOps.colorize(
@ -422,6 +422,7 @@ def test_exif_transpose() -> None:
check(orientation_im)
# Orientation from "XML:com.adobe.xmp" info key
im: Image.Image
for suffix in ("", "_exiftool"):
with Image.open("Tests/images/xmp_tags_orientation" + suffix + ".png") as im:
assert im.getexif()[0x0112] == 3

View File

@ -76,9 +76,14 @@ def test_consecutive() -> None:
def test_palette_mmap() -> None:
# Using mmap in ImageFile can require to reload the palette.
with Image.open("Tests/images/multipage-mmap.tiff") as im:
color1 = im.getpalette()[:3]
palette = im.getpalette()
assert palette is not None
color1 = palette[:3]
im.seek(0)
color2 = im.getpalette()[:3]
palette = im.getpalette()
assert palette is not None
color2 = palette[:3]
assert color1 == color2

View File

@ -17,6 +17,7 @@ def helper_pickle_file(
tmp_path: Path, protocol: int, test_file: str, mode: str | None
) -> None:
# Arrange
im: Image.Image
with Image.open(test_file) as im:
filename = tmp_path / "temp.pkl"
if mode:
@ -33,6 +34,7 @@ def helper_pickle_file(
def helper_pickle_string(protocol: int, test_file: str, mode: str | None) -> None:
im: Image.Image
with Image.open(test_file) as im:
if mode:
im = im.convert(mode)
@ -89,8 +91,8 @@ def test_pickle_jpeg() -> None:
def test_pickle_la_mode_with_palette(tmp_path: Path) -> None:
# Arrange
filename = tmp_path / "temp.pkl"
with Image.open("Tests/images/hopper.jpg") as im:
im = im.convert("PA")
with Image.open("Tests/images/hopper.jpg") as img:
im = img.convert("PA")
# Act / Assert
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):

View File

@ -50,11 +50,13 @@ class TestShellInjection:
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_filename_bmp_mode(self, tmp_path: Path) -> None:
with Image.open(TEST_GIF) as im:
im = im.convert("RGB")
self.assert_save_filename_check(tmp_path, im, GifImagePlugin._save_netpbm)
im_rgb = im.convert("RGB")
self.assert_save_filename_check(
tmp_path, im_rgb, GifImagePlugin._save_netpbm
)
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_filename_l_mode(self, tmp_path: Path) -> None:
with Image.open(TEST_GIF) as im:
im = im.convert("L")
self.assert_save_filename_check(tmp_path, im, GifImagePlugin._save_netpbm)
im_l = im.convert("L")
self.assert_save_filename_check(tmp_path, im_l, GifImagePlugin._save_netpbm)

View File

@ -213,6 +213,7 @@ class DdsImageFile(ImageFile.ImageFile):
format_description = "DirectDraw Surface"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(4)):
msg = "not a DDS file"
raise SyntaxError(msg)

View File

@ -175,6 +175,7 @@ testpaths = [
python_version = "3.9"
pretty = true
disallow_any_generics = true
disallow_untyped_defs = true
enable_error_code = "ignore-without-code"
extra_checks = true
follow_imports = "silent"

View File

@ -78,6 +78,8 @@ class AvifImageFile(ImageFile.ImageFile):
):
msg = "Invalid opening codec"
raise ValueError(msg)
assert self.fp is not None
self._decoder = _avif.AvifDecoder(
self.fp.read(),
DECODE_CODEC_CHOICE,

View File

@ -258,6 +258,7 @@ class BlpImageFile(ImageFile.ImageFile):
format_description = "Blizzard Mipmap Format"
def _open(self) -> None:
assert self.fp is not None
self.magic = self.fp.read(4)
if not _accept(self.magic):
msg = f"Bad BLP magic {repr(self.magic)}"

View File

@ -76,6 +76,7 @@ class BmpImageFile(ImageFile.ImageFile):
def _bitmap(self, header: int = 0, offset: int = 0) -> None:
"""Read relevant info about the BMP"""
assert self.fp is not None
read, seek = self.fp.read, self.fp.seek
if header:
seek(header)
@ -311,6 +312,7 @@ class BmpImageFile(ImageFile.ImageFile):
def _open(self) -> None:
"""Open file, check magic number and read header"""
# read 14 bytes: magic number, filesize, reserved, header final offset
assert self.fp is not None
head_data = self.fp.read(14)
# choke if the file does not have the required magic bytes
if not _accept(head_data):

View File

@ -41,6 +41,7 @@ class BufrStubImageFile(ImageFile.StubImageFile):
format_description = "BUFR"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(4)):
msg = "Not a BUFR file"
raise SyntaxError(msg)

View File

@ -38,6 +38,7 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
format_description = "Windows Cursor"
def _open(self) -> None:
assert self.fp is not None
offset = self.fp.tell()
# check magic

View File

@ -45,6 +45,7 @@ class DcxImageFile(PcxImageFile):
def _open(self) -> None:
# Header
assert self.fp is not None
s = self.fp.read(4)
if not _accept(s):
msg = "not a DCX file"

View File

@ -333,6 +333,7 @@ class DdsImageFile(ImageFile.ImageFile):
format_description = "DirectDraw Surface"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(4)):
msg = "not a DDS file"
raise SyntaxError(msg)

View File

@ -189,6 +189,7 @@ class EpsImageFile(ImageFile.ImageFile):
mode_map = {1: "L", 2: "LAB", 3: "RGB", 4: "CMYK"}
def _open(self) -> None:
assert self.fp is not None
(length, offset) = self._find_offset(self.fp)
# go to offset - start of "%!PS"
@ -400,6 +401,7 @@ class EpsImageFile(ImageFile.ImageFile):
) -> Image.core.PixelAccess | None:
# Load EPS via Ghostscript
if self.tile:
assert self.fp is not None
self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency)
self._mode = self.im.mode
self._size = self.im.size

View File

@ -48,6 +48,7 @@ class FliImageFile(ImageFile.ImageFile):
def _open(self) -> None:
# HEAD
assert self.fp is not None
s = self.fp.read(128)
if not (_accept(s) and s[20:22] == b"\x00\x00"):
msg = "not an FLI/FLC file"
@ -111,6 +112,7 @@ class FliImageFile(ImageFile.ImageFile):
# load palette
i = 0
assert self.fp is not None
for e in range(i16(self.fp.read(2))):
s = self.fp.read(2)
i = i + s[0]

View File

@ -58,6 +58,7 @@ class FpxImageFile(ImageFile.ImageFile):
# read the OLE directory and see if this is a likely
# to be a FlashPix file
assert self.fp is not None
try:
self.ole = olefile.OleFileIO(self.fp)
except OSError as e:
@ -229,6 +230,7 @@ class FpxImageFile(ImageFile.ImageFile):
if y >= ysize:
break # isn't really required
assert self.fp is not None
self.stream = stream
self._fp = self.fp
self.fp = None

View File

@ -72,6 +72,7 @@ class FtexImageFile(ImageFile.ImageFile):
format_description = "Texture File Format (IW2:EOC)"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(4)):
msg = "not an FTEX file"
raise SyntaxError(msg)

View File

@ -42,6 +42,7 @@ class GbrImageFile(ImageFile.ImageFile):
format_description = "GIMP brush file"
def _open(self) -> None:
assert self.fp is not None
header_size = i32(self.fp.read(4))
if header_size < 20:
msg = "not a GIMP brush"
@ -91,6 +92,8 @@ class GbrImageFile(ImageFile.ImageFile):
def load(self) -> Image.core.PixelAccess | None:
if self._im is None:
self.im = Image.core.new(self.mode, self.size)
assert self.fp is not None
self.frombytes(self.fp.read(self._data_size))
return Image.Image.load(self)

View File

@ -31,7 +31,7 @@ import os
import subprocess
from enum import IntEnum
from functools import cached_property
from typing import IO, Any, Literal, NamedTuple, Union
from typing import IO, Any, Literal, NamedTuple, Union, cast
from . import (
Image,
@ -85,6 +85,7 @@ class GifImageFile(ImageFile.ImageFile):
global_palette = None
def data(self) -> bytes | None:
assert self.fp is not None
s = self.fp.read(1)
if s and s[0]:
return self.fp.read(s[0])
@ -98,6 +99,7 @@ class GifImageFile(ImageFile.ImageFile):
def _open(self) -> None:
# Screen
assert self.fp is not None
s = self.fp.read(13)
if not _accept(s):
msg = "not a GIF file"
@ -114,8 +116,8 @@ class GifImageFile(ImageFile.ImageFile):
# check if palette contains colour indices
p = self.fp.read(3 << bits)
if self._is_palette_needed(p):
p = ImagePalette.raw("RGB", p)
self.global_palette = self.palette = p
palette = ImagePalette.raw("RGB", p)
self.global_palette = self.palette = palette
self._fp = self.fp # FIXME: hack
self.__rewind = self.fp.tell()
@ -254,7 +256,7 @@ class GifImageFile(ImageFile.ImageFile):
info["comment"] += b"\n" + comment
else:
info["comment"] = comment
s = None
s = b""
continue
elif s[0] == 255 and frame == 0 and block is not None:
#
@ -297,7 +299,7 @@ class GifImageFile(ImageFile.ImageFile):
bits = self.fp.read(1)[0]
self.__offset = self.fp.tell()
break
s = None
s = b""
if interlace is None:
msg = "image not found in GIF frame"
@ -350,7 +352,10 @@ class GifImageFile(ImageFile.ImageFile):
if self._frame_palette:
if color * 3 + 3 > len(self._frame_palette.palette):
color = 0
return tuple(self._frame_palette.palette[color * 3 : color * 3 + 3])
return cast(
tuple[int, int, int],
tuple(self._frame_palette.palette[color * 3 : color * 3 + 3]),
)
else:
return (color, color, color)

View File

@ -41,6 +41,7 @@ class GribStubImageFile(ImageFile.StubImageFile):
format_description = "GRIB"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(8)):
msg = "Not a GRIB file"
raise SyntaxError(msg)

View File

@ -41,6 +41,7 @@ class HDF5StubImageFile(ImageFile.StubImageFile):
format_description = "HDF5"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(8)):
msg = "Not an HDF file"
raise SyntaxError(msg)

View File

@ -266,6 +266,7 @@ class IcnsImageFile(ImageFile.ImageFile):
format_description = "Mac OS icns resource"
def _open(self) -> None:
assert self.fp is not None
self.icns = IcnsFile(self.fp)
self._mode = "RGBA"
self.info["sizes"] = self.icns.itersizes()

View File

@ -326,6 +326,7 @@ class IcoImageFile(ImageFile.ImageFile):
format_description = "Windows Icon"
def _open(self) -> None:
assert self.fp is not None
self.ico = IcoFile(self.fp)
self.info["sizes"] = self.ico.sizes()
self.size = self.ico.entry[0].dim

View File

@ -125,6 +125,7 @@ class ImImageFile(ImageFile.ImageFile):
# Quick rejection: if there's not an LF among the first
# 100 bytes, this is (probably) not a text header.
assert self.fp is not None
if b"\n" not in self.fp.read(100):
msg = "not an IM file"
raise SyntaxError(msg)
@ -304,6 +305,8 @@ class ImImageFile(ImageFile.ImageFile):
size = ((self.size[0] * bits + 7) // 8) * self.size[1]
offs = self.__offset + frame * size
if isinstance(self._fp, DeferredError):
raise self._fp.ex
self.fp = self._fp
self.tile = [

View File

@ -601,16 +601,11 @@ class Image:
return new
# Context manager support
def __enter__(self):
def __enter__(self) -> Image:
return self
def __exit__(self, *args):
from . import ImageFile
if isinstance(self, ImageFile.ImageFile):
if getattr(self, "_exclusive_fp", False):
self._close_fp()
self.fp = None
def __exit__(self, *args: object) -> None:
pass
def close(self) -> None:
"""
@ -1528,10 +1523,14 @@ class Image:
exif_info = bytes.fromhex(
"".join(self.info["Raw profile type exif"].split("\n")[3:])
)
elif hasattr(self, "tag_v2"):
self._exif.bigtiff = self.tag_v2._bigtiff
self._exif.endian = self.tag_v2._endian
self._exif.load_from_fp(self.fp, self.tag_v2._offset)
else:
from . import TiffImagePlugin
if isinstance(self, TiffImagePlugin.TiffImageFile):
self._exif.bigtiff = self.tag_v2._bigtiff
self._exif.endian = self.tag_v2._endian
assert self.fp is not None
self._exif.load_from_fp(self.fp, self.tag_v2._offset)
if exif_info is not None:
self._exif.load(exif_info)

View File

@ -130,6 +130,8 @@ class ImageFile(Image.Image):
self.decoderconfig: tuple[Any, ...] = ()
self.decodermaxblock = MAXBLOCK
self.fp: IO[bytes] | None
self._fp: IO[bytes] | DeferredError
if is_path(fp):
# filename
self.fp = open(fp, "rb")
@ -166,14 +168,23 @@ class ImageFile(Image.Image):
def _open(self) -> None:
pass
def _close_fp(self):
if getattr(self, "_fp", False) and not isinstance(self._fp, DeferredError):
# Context manager support
def __enter__(self) -> ImageFile:
return self
def _close_fp(self) -> None:
if hasattr(self, "_fp") and not isinstance(self._fp, DeferredError):
if self._fp != self.fp:
self._fp.close()
self._fp = DeferredError(ValueError("Operation on closed image"))
if self.fp:
self.fp.close()
def __exit__(self, *args: object) -> None:
if getattr(self, "_exclusive_fp", False):
self._close_fp()
self.fp = None
def close(self) -> None:
"""
Closes the file pointer, if possible.
@ -265,7 +276,7 @@ class ImageFile(Image.Image):
# raise exception if something's wrong. must be called
# directly after open, and closes file when finished.
if self._exclusive_fp:
if self._exclusive_fp and self.fp:
self.fp.close()
self.fp = None
@ -283,6 +294,7 @@ class ImageFile(Image.Image):
self.map: mmap.mmap | None = None
use_mmap = self.filename and len(self.tile) == 1
assert self.fp is not None
readonly = 0
# look for read/seek overrides

View File

@ -77,6 +77,7 @@ class IptcImageFile(ImageFile.ImageFile):
def field(self) -> tuple[tuple[int, int] | None, int]:
#
# get a IPTC field header
assert self.fp is not None
s = self.fp.read(5)
if not s.strip(b"\x00"):
return None, 0
@ -104,6 +105,7 @@ class IptcImageFile(ImageFile.ImageFile):
def _open(self) -> None:
# load descriptive fields
assert self.fp is not None
while True:
offset = self.fp.tell()
tag, size = self.field()
@ -157,6 +159,7 @@ class IptcImageFile(ImageFile.ImageFile):
offset, compression = self.tile[0][2:]
assert self.fp is not None
self.fp.seek(offset)
# Copy image data to temporary file
@ -165,6 +168,7 @@ class IptcImageFile(ImageFile.ImageFile):
# To simplify access to the extracted file,
# prepend a PPM header
o.write(b"P5\n%d %d\n255\n" % self.size)
assert self.fp is not None
while True:
type, size = self.field()
if type != (8, 10):

View File

@ -248,6 +248,7 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
format_description = "JPEG 2000 (ISO 15444)"
def _open(self) -> None:
assert self.fp is not None
sig = self.fp.read(4)
if sig == b"\xff\x4f\xff\x51":
self.codec = "j2k"
@ -300,6 +301,7 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
]
def _parse_comment(self) -> None:
assert self.fp is not None
while True:
marker = self.fp.read(2)
if not marker:

View File

@ -61,6 +61,7 @@ if TYPE_CHECKING:
def Skip(self: JpegImageFile, marker: int) -> None:
assert self.fp is not None
n = i16(self.fp.read(2)) - 2
ImageFile._safe_read(self.fp, n)
@ -70,6 +71,7 @@ def APP(self: JpegImageFile, marker: int) -> None:
# Application marker. Store these in the APP dictionary.
# Also look for well-known application markers.
assert self.fp is not None
n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n)
@ -174,6 +176,7 @@ def APP(self: JpegImageFile, marker: int) -> None:
def COM(self: JpegImageFile, marker: int) -> None:
#
# Comment marker. Store these in the APP dictionary.
assert self.fp is not None
n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n)
@ -190,6 +193,7 @@ def SOF(self: JpegImageFile, marker: int) -> None:
# mode. Note that this could be made a bit brighter, by
# looking for JFIF and Adobe APP markers.
assert self.fp is not None
n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n)
self._size = i16(s, 3), i16(s, 1)
@ -238,6 +242,7 @@ def DQT(self: JpegImageFile, marker: int) -> None:
# FIXME: The quantization tables can be used to estimate the
# compression quality.
assert self.fp is not None
n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n)
while len(s):
@ -338,6 +343,7 @@ class JpegImageFile(ImageFile.ImageFile):
format_description = "JPEG (ISO 10918)"
def _open(self) -> None:
assert self.fp is not None
s = self.fp.read(3)
if not _accept(s):
@ -412,6 +418,7 @@ class JpegImageFile(ImageFile.ImageFile):
For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker
so libjpeg can finish decoding
"""
assert self.fp is not None
s = self.fp.read(read_bytes)
if not s and ImageFile.LOAD_TRUNCATED_IMAGES and not hasattr(self, "_ended"):

View File

@ -67,6 +67,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
self._n_frames = len(self.images)
self.is_animated = self._n_frames > 1
assert self.fp is not None
self.__fp = self.fp
self.seek(0)

View File

@ -99,6 +99,7 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
_close_exclusive_fp_after_loading = False
def _open(self) -> None:
assert self.fp is not None
self.fp.seek(0) # prep the fp in order to pass the JPEG test
JpegImagePlugin.JpegImageFile._open(self)
self._after_jpeg_open()
@ -118,6 +119,7 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
assert self.n_frames == len(self.__mpoffsets)
del self.info["mpoffset"] # no longer needed
self.is_animated = self.n_frames > 1
assert self.fp is not None
self._fp = self.fp # FIXME: hack
self._fp.seek(self.__mpoffsets[0]) # get ready to read first frame
self.__frame = 0

View File

@ -754,6 +754,7 @@ class PngImageFile(ImageFile.ImageFile):
format_description = "Portable network graphics"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(8)):
msg = "not a PNG file"
raise SyntaxError(msg)
@ -985,6 +986,7 @@ class PngImageFile(ImageFile.ImageFile):
"""internal: read more image data"""
assert self.png is not None
assert self.fp is not None
while self.__idat == 0:
# end of chunk, skip forward to next one
@ -1018,6 +1020,7 @@ class PngImageFile(ImageFile.ImageFile):
def load_end(self) -> None:
"""internal: finished reading image data"""
assert self.png is not None
assert self.fp is not None
if self.__idat != 0:
self.fp.read(self.__idat)
while True:

View File

@ -61,6 +61,7 @@ class PsdImageFile(ImageFile.ImageFile):
_close_exclusive_fp_after_loading = False
def _open(self) -> None:
assert self.fp is not None
read = self.fp.read
#
@ -178,6 +179,8 @@ class PsdImageFile(ImageFile.ImageFile):
self._mode = mode
self.tile = tile
self.frame = layer
if isinstance(self._fp, DeferredError):
raise self._fp.ex
self.fp = self._fp
def tell(self) -> int:

View File

@ -22,6 +22,7 @@ class QoiImageFile(ImageFile.ImageFile):
format_description = "Quite OK Image"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(4)):
msg = "not a QOI file"
raise SyntaxError(msg)

View File

@ -103,6 +103,7 @@ class SpiderImageFile(ImageFile.ImageFile):
def _open(self) -> None:
# check header
assert self.fp is not None
n = 27 * 4 # read 27 float values
f = self.fp.read(n)
@ -184,6 +185,9 @@ class SpiderImageFile(ImageFile.ImageFile):
if isinstance(self._fp, DeferredError):
raise self._fp.ex
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
if isinstance(self._fp, DeferredError):
raise self._fp.ex
self.fp = self._fp
self.fp.seek(self.stkoffset)
self._open()
@ -323,9 +327,9 @@ if __name__ == "__main__":
outfile = sys.argv[2]
# perform some image operation
im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
transposed_im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
print(
f"saving a flipped version of {os.path.basename(filename)} "
f"as {outfile} "
)
im.save(outfile, SpiderImageFile.format)
transposed_im.save(outfile, SpiderImageFile.format)

View File

@ -1179,6 +1179,7 @@ class TiffImageFile(ImageFile.ImageFile):
"""Open the first image in a TIFF file"""
# Header
assert self.fp is not None
ifh = self.fp.read(8)
if ifh[2] == 43:
ifh += self.fp.read(8)
@ -1341,6 +1342,7 @@ class TiffImageFile(ImageFile.ImageFile):
# To be nice on memory footprint, if there's a
# file descriptor, use that instead of reading
# into a string in python.
assert self.fp is not None
try:
fp = hasattr(self.fp, "fileno") and self.fp.fileno()
# flush the file descriptor, prevents error on pypy 2.4+

View File

@ -39,6 +39,7 @@ class WalImageFile(ImageFile.ImageFile):
self._mode = "P"
# read header fields
assert self.fp is not None
header = self.fp.read(32 + 24 + 32 + 12)
self._size = i32(header, 32), i32(header, 36)
Image._decompression_bomb_check(self.size)
@ -55,6 +56,7 @@ class WalImageFile(ImageFile.ImageFile):
def load(self) -> Image.core.PixelAccess | None:
if self._im is None:
assert self.fp is not None
self.im = Image.core.new(self.mode, self.size)
self.frombytes(self.fp.read(self.size[0] * self.size[1]))
self.putpalette(quake2palette)

View File

@ -43,6 +43,7 @@ class WebPImageFile(ImageFile.ImageFile):
def _open(self) -> None:
# Use the newer AnimDecoder API to parse the (possibly) animated file,
# and access muxed chunks like ICC/EXIF/XMP.
assert self.fp is not None
self._decoder = _webp.WebPAnimDecoder(self.fp.read())
# Get info from decoder

View File

@ -49,6 +49,7 @@ if hasattr(Image.core, "drawwmf"):
self.bbox = im.info["wmf_bbox"]
def load(self, im: ImageFile.StubImageFile) -> Image.Image:
assert im.fp is not None
im.fp.seek(0) # rewind
return Image.frombytes(
"RGB",
@ -81,6 +82,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
def _open(self) -> None:
# check placable header
assert self.fp is not None
s = self.fp.read(80)
if s.startswith(b"\xd7\xcd\xc6\x9a\x00\x00"):

View File

@ -58,15 +58,15 @@ class XVThumbImageFile(ImageFile.ImageFile):
# skip info comments
while True:
s = self.fp.readline()
if not s:
line = self.fp.readline()
if not line:
msg = "Unexpected EOF reading XV thumbnail file"
raise SyntaxError(msg)
if s[0] != 35: # ie. when not a comment: '#'
if line[0] != 35: # ie. when not a comment: '#'
break
# parse header line (already read)
s = s.strip().split()
s = line.strip().split()
self._mode = "P"
self._size = int(s[0]), int(s[1])

View File

@ -37,17 +37,18 @@ class XpmImageFile(ImageFile.ImageFile):
format_description = "X11 Pixel Map"
def _open(self) -> None:
assert self.fp is not None
if not _accept(self.fp.read(9)):
msg = "not an XPM file"
raise SyntaxError(msg)
# skip forward to next string
while True:
s = self.fp.readline()
if not s:
line = self.fp.readline()
if not line:
msg = "broken XPM file"
raise SyntaxError(msg)
m = xpm_head.match(s)
m = xpm_head.match(line)
if m:
break
@ -66,14 +67,14 @@ class XpmImageFile(ImageFile.ImageFile):
palette = [b"\0\0\0"] * 256
for _ in range(pal):
s = self.fp.readline()
if s.endswith(b"\r\n"):
s = s[:-2]
elif s.endswith((b"\r", b"\n")):
s = s[:-1]
line = self.fp.readline()
if line.endswith(b"\r\n"):
line = line[:-2]
elif line.endswith((b"\r", b"\n")):
line = line[:-1]
c = s[1]
s = s[2:-2].split()
c = line[1]
s = line[2:-2].split()
for i in range(0, len(s), 2):
if s[i] == b"c":
@ -83,9 +84,11 @@ class XpmImageFile(ImageFile.ImageFile):
self.info["transparency"] = c
elif rgb.startswith(b"#"):
# FIXME: handle colour names (see ImagePalette.py)
rgb = int(rgb[1:], 16)
rgb_int = int(rgb[1:], 16)
palette[c] = (
o8((rgb >> 16) & 255) + o8((rgb >> 8) & 255) + o8(rgb & 255)
o8((rgb_int >> 16) & 255)
+ o8((rgb_int >> 8) & 255)
+ o8(rgb_int & 255)
)
else:
# unknown colour
@ -109,6 +112,7 @@ class XpmImageFile(ImageFile.ImageFile):
xsize, ysize = self.size
assert self.fp is not None
s = [self.fp.readline()[1 : xsize + 1].ljust(xsize) for i in range(ysize)]
return b"".join(s)