Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion Tests/test_file_im.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from __future__ import annotations

import filecmp
import io
import warnings
from pathlib import Path

import pytest

from PIL import Image, ImImagePlugin

from .helper import assert_image_equal_tofile, hopper, is_pypy
from .helper import assert_image_equal, assert_image_equal_tofile, hopper, is_pypy

# sample im
TEST_IM = "Tests/images/hopper.im"
Expand Down Expand Up @@ -83,6 +84,41 @@ def test_eoferror() -> None:
im.seek(n_frames - 1)


@pytest.mark.parametrize(
"image_type, rawmode, mode",
(
("L 16", "I;16", "I;16"),
("L 32S", "I;32S", "I"),
("L 32F", "F;32F", "F"),
("YCC", "YCbCr;L", "YCbCr"),
),
)
def test_seek_non_8bit(image_type: str, rawmode: str, mode: str) -> None:
# The frame stride must be derived from the actual bytes per pixel, not
# from the length of the mode name (which only matches for 8-bit bands).
w, h = 4, 4
frames = []
for base in (0, 1000):
frame = Image.new(mode, (w, h))
for y in range(h):
for x in range(w):
frame.putpixel((x, y), base + y * w + x)
frames.append(frame)

header = (
f"Image type: {image_type} image\r\n"
f"Image size (x*y): {w}*{h}\r\n"
f"File size (no of images): {len(frames)}\r\n"
).encode("ascii")
header += b"\x00" * (511 - len(header)) + b"\x1a"
data = b"".join(frame.tobytes("raw", rawmode, 0, -1) for frame in frames)

with Image.open(io.BytesIO(header + data)) as im:
for index, frame in enumerate(frames):
im.seek(index)
assert_image_equal(im, frame)


@pytest.mark.parametrize("mode", ("RGB", "P", "PA"))
def test_roundtrip(mode: str, tmp_path: Path) -> None:
out = tmp_path / "temp.im"
Expand Down
5 changes: 3 additions & 2 deletions src/PIL/ImImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import re
from typing import IO, Any

from . import Image, ImageFile, ImagePalette
from . import Image, ImageFile, ImageMode, ImagePalette
from ._util import DeferredError

# --------------------------------------------------------------------
Expand Down Expand Up @@ -300,7 +300,8 @@ def seek(self, frame: int) -> None:
if self.mode == "1":
bits = 1
else:
bits = 8 * len(self.mode)
mode = ImageMode.getmode(self.mode)
bits = 8 * len(mode.bands) * int(mode.typestr[-1])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really not clear to a reader why we multiply things with an integer from the last character of a type string :)


size = ((self.size[0] * bits + 7) // 8) * self.size[1]
offs = self.__offset + frame * size
Expand Down
Loading