Skip to content

Commit

Permalink
Merge pull request #5655 from radarhere/whiteiszero
Browse files Browse the repository at this point in the history
Allow saving 1 and L mode TIFF with PhotometricInterpretation 0
  • Loading branch information
hugovk committed Aug 14, 2021
2 parents 5db0969 + 9bf7dae commit 2d01f7d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 12 deletions.
9 changes: 9 additions & 0 deletions Tests/test_file_tiff.py
Expand Up @@ -447,6 +447,15 @@ def test_exif_frames(self):
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:
Expand Down
37 changes: 25 additions & 12 deletions src/PIL/TiffImagePlugin.py
Expand Up @@ -48,7 +48,7 @@
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

Expand Down Expand Up @@ -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":
Expand All @@ -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()
Expand Down Expand Up @@ -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

Expand All @@ -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]
Expand All @@ -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")
Expand Down Expand Up @@ -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":
Expand Down Expand Up @@ -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:
Expand All @@ -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

Expand Down

0 comments on commit 2d01f7d

Please sign in to comment.