diff --git a/Tests/test_file_vtf.py b/Tests/test_file_vtf.py index 62a6ad47d..6a7032494 100644 --- a/Tests/test_file_vtf.py +++ b/Tests/test_file_vtf.py @@ -24,7 +24,7 @@ from .helper import assert_image_equal, assert_image_similar (2000, 2048), ], ) -def test_closest_power(size: int, expected_size: int): +def test_closest_power(size: int, expected_size: int) -> None: assert _closest_power(size) == expected_size @@ -42,7 +42,7 @@ def test_closest_power(size: int, expected_size: int): ((1024, 1), 11), ], ) -def test_get_mipmap_count(size: tuple[int, int], expected_count: int): +def test_get_mipmap_count(size: tuple[int, int], expected_count: int) -> None: assert _get_mipmap_count(*size) == expected_count @@ -64,7 +64,7 @@ def test_get_mipmap_count(size: tuple[int, int], expected_count: int): ) def test_get_texture_size( pixel_format: VtfPF, size: tuple[int, int], expected_size: int -): +) -> None: assert _get_texture_size(pixel_format, *size) == expected_size @@ -82,15 +82,17 @@ def test_get_texture_size( ("Tests/images/vtf_rgba8888.png", "Tests/images/vtf_rgba8888.vtf", "RGBA", 0), ], ) -def test_vtf_read(etalon_path: str, file_path: str, expected_mode: str, epsilon: float): - e = Image.open(etalon_path) - f = Image.open(file_path) - assert f.mode == expected_mode - e = e.convert(expected_mode) - if epsilon == 0: - assert_image_equal(e, f) - else: - assert_image_similar(e, f, epsilon) +def test_vtf_read( + etalon_path: str, file_path: str, expected_mode: str, epsilon: float +) -> None: + with Image.open(file_path) as f: + assert f.mode == expected_mode + with Image.open(etalon_path) as e: + converted_e = e.convert(expected_mode) + if epsilon == 0: + assert_image_equal(converted_e, f) + else: + assert_image_similar(converted_e, f, epsilon) @pytest.mark.parametrize( @@ -109,7 +111,7 @@ def test_vtf_read(etalon_path: str, file_path: str, expected_mode: str, epsilon: ) def test_vtf_save( pixel_format: VtfPF, file_path: str, expected_mode: str, epsilon: float, tmp_path -): +) -> None: f: Image.Image = Image.open(file_path) out = (tmp_path / "tmp.vtf").as_posix() f.save(out, pixel_format=pixel_format) diff --git a/src/PIL/VtfImagePlugin.py b/src/PIL/VtfImagePlugin.py index 8aa9c4324..7e123cdae 100644 --- a/src/PIL/VtfImagePlugin.py +++ b/src/PIL/VtfImagePlugin.py @@ -14,9 +14,9 @@ from __future__ import annotations import struct from enum import IntEnum, IntFlag -from io import BufferedIOBase, BytesIO +from io import BytesIO from math import ceil, log -from typing import NamedTuple +from typing import IO, NamedTuple from . import Image, ImageFile @@ -149,7 +149,7 @@ def _get_texture_size(pixel_format: VtfPF, width, height): raise VTFException(msg) -def _get_mipmap_count(width: int, height: int): +def _get_mipmap_count(width: int, height: int) -> int: mip_count = 1 while True: mip_width = width >> mip_count @@ -159,8 +159,9 @@ def _get_mipmap_count(width: int, height: int): mip_count += 1 -def _write_image(fp: BufferedIOBase, im: Image.Image, pixel_format: VtfPF): +def _write_image(fp: IO[bytes], im: Image.Image, pixel_format: VtfPF) -> None: extents = (0, 0) + im.size + encoder_args: tuple[int, str] | tuple[str, int, int] if pixel_format == VtfPF.DXT1: encoder = "bcn" encoder_args = (1, "DXT1") @@ -309,8 +310,7 @@ class VtfImageFile(ImageFile.ImageFile): self.tile = [tile] -def _save(im, fp, filename): - im: Image.Image +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if im.mode not in ("RGB", "RGBA", "L", "LA"): msg = f"cannot write mode {im.mode} as VTF" raise OSError(msg) @@ -406,7 +406,7 @@ def _save(im, fp, filename): _write_image(fp, im, pixel_format) -def _accept(prefix): +def _accept(prefix: bytes) -> bool: valid_header = prefix[:4] == b"VTF\x00" valid_version = struct.unpack_from("<2I", prefix, 4) >= (7, 0) return valid_header and valid_version