Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow encoderconfig and encoderinfo to be set for appended TIFF images #8780

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
12 changes: 12 additions & 0 deletions Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,18 @@ def test_rowsperstrip(self, tmp_path: Path) -> None:
assert isinstance(im, TiffImagePlugin.TiffImageFile)
assert im.tag_v2[278] == 256

im = hopper()
im2 = Image.new("L", (128, 128))
im2.encoderinfo = {"tiffinfo": {278: 256}}
im.save(outfile, save_all=True, append_images=[im2])

with Image.open(outfile) as im:
assert isinstance(im, TiffImagePlugin.TiffImageFile)
assert im.tag_v2[278] == 128

im.seek(1)
assert im.tag_v2[278] == 256

def test_strip_raw(self) -> None:
infile = "Tests/images/tiff_strip_raw.tif"
with Image.open(infile) as im:
Expand Down
4 changes: 1 addition & 3 deletions docs/handbook/image-file-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1162,9 +1162,7 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum

**append_images**
A list of images to append as additional frames. Each of the
images in the list can be single or multiframe images. Note however, that for
correct results, all the appended images should have the same
``encoderinfo`` and ``encoderconfig`` properties.
images in the list can be single or multiframe images.

.. versionadded:: 4.2.0

Expand Down
16 changes: 15 additions & 1 deletion src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2475,7 +2475,21 @@ def save(
format to use is determined from the filename extension.
If a file object was used instead of a filename, this
parameter should always be used.
:param params: Extra parameters to the image writer.
:param params: Extra parameters to the image writer. These can also be
set on the image itself through ``encoderinfo``. This is useful when
saving multiple images::

# Saving XMP data to a single image
from PIL import Image
red = Image.new("RGB", (1, 1), "#f00")
red.save("out.mpo", xmp=b"test")

# Saving XMP data to the second frame of an image
from PIL import Image
black = Image.new("RGB", (1, 1))
red = Image.new("RGB", (1, 1), "#f00")
red.encoderinfo = {"xmp": b"test"}
black.save("out.mpo", save_all=True, append_images=[red])
:returns: None
:exception ValueError: If the output format could not be determined
from the file name. Use the format option to solve this.
Expand Down
15 changes: 6 additions & 9 deletions src/PIL/TiffImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2295,22 +2295,19 @@


def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
encoderinfo = im.encoderinfo.copy()
encoderconfig = im.encoderconfig
append_images = list(encoderinfo.get("append_images", []))
append_images = list(im.encoderinfo.get("append_images", []))

Check warning on line 2298 in src/PIL/TiffImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/TiffImagePlugin.py#L2298

Added line #L2298 was not covered by tests
if not hasattr(im, "n_frames") and not append_images:
return _save(im, fp, filename)

cur_idx = im.tell()
try:
with AppendingTiffWriter(fp) as tf:
for ims in [im] + append_images:
ims.encoderinfo = encoderinfo
ims.encoderconfig = encoderconfig
if not hasattr(ims, "n_frames"):
nfr = 1
else:
nfr = ims.n_frames
if not hasattr(ims, "encoderinfo"):
ims.encoderinfo = {}
if not hasattr(ims, "encoderconfig"):
ims.encoderconfig = ()
nfr = getattr(ims, "n_frames", 1)

Check warning on line 2310 in src/PIL/TiffImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/TiffImagePlugin.py#L2306-L2310

Added lines #L2306 - L2310 were not covered by tests

for idx in range(nfr):
ims.seek(idx)
Expand Down
Loading