Skip to content

Commit

Permalink
Merge pull request #5848 from radarhere/sampleformat
Browse files Browse the repository at this point in the history
Pass SAMPLEFORMAT to libtiff
  • Loading branch information
hugovk committed Dec 28, 2021
2 parents e7b5325 + 2e9193a commit 1806cf5
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 7 deletions.
13 changes: 12 additions & 1 deletion Tests/test_file_libtiff.py
Expand Up @@ -9,7 +9,7 @@
import pytest

from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features
from PIL.TiffImagePlugin import STRIPOFFSETS, SUBIFD
from PIL.TiffImagePlugin import SAMPLEFORMAT, STRIPOFFSETS, SUBIFD

from .helper import (
assert_image_equal,
Expand Down Expand Up @@ -825,6 +825,17 @@ def test_sampleformat(self):

assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")

def test_sampleformat_write(self, tmp_path):
im = Image.new("F", (1, 1))
out = str(tmp_path / "temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out)
TiffImagePlugin.WRITE_LIBTIFF = False

with Image.open(out) as reloaded:
assert reloaded.mode == "F"
assert reloaded.getexif()[SAMPLEFORMAT] == 3

def test_lzw(self):
with Image.open("Tests/images/hopper_lzw.tif") as im:
assert im.mode == "RGB"
Expand Down
17 changes: 11 additions & 6 deletions src/PIL/TiffImagePlugin.py
Expand Up @@ -1676,8 +1676,6 @@ def _save(im, fp, filename):

# optional types for non core tags
types = {}
# SAMPLEFORMAT is determined by the image format and should not be copied
# from legacy_ifd.
# STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
# based on the data in the strip.
# The other tags expect arrays with a certain length (fixed or depending on
Expand All @@ -1686,7 +1684,6 @@ def _save(im, fp, filename):
# SUBIFD may also cause a segfault.
blocklist += [
REFERENCEBLACKWHITE,
SAMPLEFORMAT,
STRIPBYTECOUNTS,
STRIPOFFSETS,
TRANSFERFUNCTION,
Expand All @@ -1702,9 +1699,14 @@ def _save(im, fp, filename):
legacy_ifd = {}
if hasattr(im, "tag"):
legacy_ifd = im.tag.to_v2()
for tag, value in itertools.chain(
ifd.items(), getattr(im, "tag_v2", {}).items(), legacy_ifd.items()
):

# SAMPLEFORMAT is determined by the image format and should not be copied
# from legacy_ifd.
supplied_tags = {**getattr(im, "tag_v2", {}), **legacy_ifd}
if SAMPLEFORMAT in supplied_tags:
del supplied_tags[SAMPLEFORMAT]

for tag, value in itertools.chain(ifd.items(), supplied_tags.items()):
# Libtiff can only process certain core items without adding
# them to the custom dictionary.
# Custom items are supported for int, float, unicode, string and byte
Expand All @@ -1729,6 +1731,9 @@ def _save(im, fp, filename):
else:
atts[tag] = value

if SAMPLEFORMAT in atts and len(atts[SAMPLEFORMAT]) == 1:
atts[SAMPLEFORMAT] = atts[SAMPLEFORMAT][0]

logger.debug("Converted items: %s" % sorted(atts.items()))

# libtiff always expects the bytes in native order.
Expand Down

0 comments on commit 1806cf5

Please sign in to comment.