Merge pull request #5655 from radarhere/whiteiszero

Allow saving 1 and L mode TIFF with PhotometricInterpretation 0
This commit is contained in:
Hugo van Kemenade 2021-08-14 20:41:08 +03:00 committed by GitHub
commit 2d01f7d022
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 12 deletions

View File

@ -447,6 +447,15 @@ class TestFileTiff:
im.seek(1)
assert im.getexif()[273] == (1408, 1907)
@pytest.mark.parametrize("mode", ("1", "L"))
def test_photometric(self, mode, tmp_path):
filename = str(tmp_path / "temp.tif")
im = hopper(mode)
im.save(filename, tiffinfo={262: 0})
with Image.open(filename) as reloaded:
assert reloaded.tag_v2[262] == 0
assert_image_equal(im, reloaded)
def test_seek(self):
filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im:

View File

@ -48,7 +48,7 @@ from collections.abc import MutableMapping
from fractions import Fraction
from numbers import Number, Rational
from . import Image, ImageFile, ImagePalette, TiffTags
from . import Image, ImageFile, ImageOps, ImagePalette, TiffTags
from ._binary import o8
from .TiffTags import TYPES
@ -1487,7 +1487,9 @@ def _save(im, fp, filename):
ifd = ImageFileDirectory_v2(prefix=prefix)
compression = im.encoderinfo.get("compression", im.info.get("compression"))
encoderinfo = im.encoderinfo
encoderconfig = im.encoderconfig
compression = encoderinfo.get("compression", im.info.get("compression"))
if compression is None:
compression = "raw"
elif compression == "tiff_jpeg":
@ -1505,7 +1507,7 @@ def _save(im, fp, filename):
ifd[IMAGELENGTH] = im.size[1]
# write any arbitrary tags passed in as an ImageFileDirectory
info = im.encoderinfo.get("tiffinfo", {})
info = encoderinfo.get("tiffinfo", {})
logger.debug("Tiffinfo Keys: %s" % list(info))
if isinstance(info, ImageFileDirectory_v1):
info = info.to_v2()
@ -1534,7 +1536,7 @@ def _save(im, fp, filename):
# preserve ICC profile (should also work when saving other formats
# which support profiles as TIFF) -- 2008-06-06 Florian Hoech
icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile"))
icc = encoderinfo.get("icc_profile", im.info.get("icc_profile"))
if icc:
ifd[ICCPROFILE] = icc
@ -1550,10 +1552,10 @@ def _save(im, fp, filename):
(ARTIST, "artist"),
(COPYRIGHT, "copyright"),
]:
if name in im.encoderinfo:
ifd[key] = im.encoderinfo[name]
if name in encoderinfo:
ifd[key] = encoderinfo[name]
dpi = im.encoderinfo.get("dpi")
dpi = encoderinfo.get("dpi")
if dpi:
ifd[RESOLUTION_UNIT] = 2
ifd[X_RESOLUTION] = dpi[0]
@ -1568,7 +1570,18 @@ def _save(im, fp, filename):
if format != 1:
ifd[SAMPLEFORMAT] = format
ifd[PHOTOMETRIC_INTERPRETATION] = photo
if PHOTOMETRIC_INTERPRETATION not in ifd:
ifd[PHOTOMETRIC_INTERPRETATION] = photo
elif im.mode in ("1", "L") and ifd[PHOTOMETRIC_INTERPRETATION] == 0:
if im.mode == "1":
inverted_im = im.copy()
px = inverted_im.load()
for y in range(inverted_im.height):
for x in range(inverted_im.width):
px[x, y] = 0 if px[x, y] == 255 else 255
im = inverted_im
else:
im = ImageOps.invert(im)
if im.mode in ["P", "PA"]:
lut = im.im.getpalette("RGB", "RGB;L")
@ -1605,8 +1618,8 @@ def _save(im, fp, filename):
ifd.setdefault(tag, value)
if libtiff:
if "quality" in im.encoderinfo:
quality = im.encoderinfo["quality"]
if "quality" in encoderinfo:
quality = encoderinfo["quality"]
if not isinstance(quality, int) or quality < 0 or quality > 100:
raise ValueError("Invalid quality setting")
if compression != "jpeg":
@ -1695,7 +1708,7 @@ def _save(im, fp, filename):
tags = list(atts.items())
tags.sort()
a = (rawmode, compression, _fp, filename, tags, types)
e = Image._getencoder(im.mode, "libtiff", a, im.encoderconfig)
e = Image._getencoder(im.mode, "libtiff", a, encoderconfig)
e.setimage(im.im, (0, 0) + im.size)
while True:
# undone, change to self.decodermaxblock:
@ -1715,7 +1728,7 @@ def _save(im, fp, filename):
)
# -- helper for multi-page save --
if "_debug_multipage" in im.encoderinfo:
if "_debug_multipage" in encoderinfo:
# just to access o32 and o16 (using correct byte order)
im._debug_multipage = ifd