Pillow/Tests/test_file_libtiff.py

872 lines
30 KiB
Python
Raw Normal View History

from __future__ import print_function
2014-06-10 13:10:47 +04:00
import base64
import distutils.version
2014-11-16 07:38:52 +03:00
import io
import itertools
import logging
import os
from collections import namedtuple
from ctypes import c_float
from PIL import Image, TiffImagePlugin, TiffTags, features
from PIL._util import py3
from .helper import PillowTestCase, hopper
logger = logging.getLogger(__name__)
class LibTiffTestCase(PillowTestCase):
2014-06-10 13:10:47 +04:00
def setUp(self):
2019-06-13 18:54:11 +03:00
if not features.check("libtiff"):
2014-06-10 13:10:47 +04:00
self.skipTest("tiff support not available")
2014-06-10 13:10:47 +04:00
def _assert_noerr(self, im):
"""Helper tests that assert basic sanity about the g4 tiff reading"""
# 1 bit
self.assertEqual(im.mode, "1")
2014-06-10 13:10:47 +04:00
# Does the data actually load
im.load()
im.getdata()
2014-06-10 13:10:47 +04:00
try:
2019-06-13 18:54:11 +03:00
self.assertEqual(im._compression, "group4")
2018-06-11 09:00:57 +03:00
except AttributeError:
2014-06-10 13:10:47 +04:00
print("No _compression")
2015-04-24 02:26:52 +03:00
print(dir(im))
2014-06-10 13:10:47 +04:00
# can we write it back out, in a different form.
out = self.tempfile("temp.png")
im.save(out)
2016-11-23 17:24:40 +03:00
out_bytes = io.BytesIO()
2019-06-13 18:54:11 +03:00
im.save(out_bytes, format="tiff", compression="group4")
2017-04-20 14:14:23 +03:00
class TestFileLibTiff(LibTiffTestCase):
2014-06-10 13:10:47 +04:00
def test_g4_tiff(self):
"""Test the ordinary file path load path"""
2015-04-02 11:45:24 +03:00
test_file = "Tests/images/hopper_g4_500.tif"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
2014-06-10 13:10:47 +04:00
def test_g4_large(self):
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/pport_g4.tif"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self._assert_noerr(im)
2014-06-10 13:10:47 +04:00
def test_g4_tiff_file(self):
"""Testing the string load path"""
2015-04-02 11:45:24 +03:00
test_file = "Tests/images/hopper_g4_500.tif"
2019-06-13 18:54:11 +03:00
with open(test_file, "rb") as f:
2014-06-10 13:10:47 +04:00
im = Image.open(f)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
def test_g4_tiff_bytesio(self):
"""Testing the stringio loading code path"""
2015-04-02 11:45:24 +03:00
test_file = "Tests/images/hopper_g4_500.tif"
2014-11-16 07:38:52 +03:00
s = io.BytesIO()
2019-06-13 18:54:11 +03:00
with open(test_file, "rb") as f:
2014-06-10 13:10:47 +04:00
s.write(f.read())
s.seek(0)
im = Image.open(s)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
def test_g4_non_disk_file_object(self):
"""Testing loading from non-disk non-BytesIO file object"""
test_file = "Tests/images/hopper_g4_500.tif"
s = io.BytesIO()
with open(test_file, "rb") as f:
s.write(f.read())
s.seek(0)
r = io.BufferedReader(s)
im = Image.open(r)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
2014-06-10 13:10:47 +04:00
def test_g4_eq_png(self):
""" Checking that we're actually getting the data that we expect"""
2019-06-13 18:54:11 +03:00
png = Image.open("Tests/images/hopper_bw_500.png")
g4 = Image.open("Tests/images/hopper_g4_500.tif")
2014-06-10 13:10:47 +04:00
self.assert_image_equal(g4, png)
# see https://github.com/python-pillow/Pillow/issues/279
def test_g4_fillorder_eq_png(self):
""" Checking that we're actually getting the data that we expect"""
2019-06-13 18:54:11 +03:00
png = Image.open("Tests/images/g4-fillorder-test.png")
g4 = Image.open("Tests/images/g4-fillorder-test.tif")
2014-06-10 13:10:47 +04:00
self.assert_image_equal(g4, png)
def test_g4_write(self):
"""Checking to see that the saved image is the same as what we wrote"""
2015-04-02 11:45:24 +03:00
test_file = "Tests/images/hopper_g4_500.tif"
orig = Image.open(test_file)
2014-06-10 13:10:47 +04:00
out = self.tempfile("temp.tif")
rot = orig.transpose(Image.ROTATE_90)
self.assertEqual(rot.size, (500, 500))
rot.save(out)
reread = Image.open(out)
self.assertEqual(reread.size, (500, 500))
self._assert_noerr(reread)
self.assert_image_equal(reread, rot)
2019-06-13 18:54:11 +03:00
self.assertEqual(reread.info["compression"], "group4")
2014-06-10 13:10:47 +04:00
2019-06-13 18:54:11 +03:00
self.assertEqual(reread.info["compression"], orig.info["compression"])
2014-06-10 13:10:47 +04:00
self.assertNotEqual(orig.tobytes(), reread.tobytes())
def test_adobe_deflate_tiff(self):
2015-04-02 11:45:24 +03:00
test_file = "Tests/images/tiff_adobe_deflate.tif"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (278, 374))
self.assertEqual(im.tile[0][:3], ("libtiff", (0, 0, 278, 374), 0))
2014-06-10 13:10:47 +04:00
im.load()
2019-06-13 18:54:11 +03:00
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
2014-06-10 13:10:47 +04:00
def test_write_metadata(self):
""" Test metadata writing through libtiff """
for legacy_api in [False, True]:
2019-06-13 18:54:11 +03:00
img = Image.open("Tests/images/hopper_g4.tif")
f = self.tempfile("temp.tiff")
img.save(f, tiffinfo=img.tag)
if legacy_api:
original = img.tag.named()
else:
original = img.tag_v2.named()
# PhotometricInterpretation is set from SAVE_INFO,
# not the original image.
2019-06-13 18:54:11 +03:00
ignored = [
"StripByteCounts",
"RowsPerStrip",
"PageNumber",
"PhotometricInterpretation",
]
loaded = Image.open(f)
if legacy_api:
reloaded = loaded.tag.named()
else:
reloaded = loaded.tag_v2.named()
2019-06-13 18:54:11 +03:00
for tag, value in itertools.chain(reloaded.items(), original.items()):
if tag not in ignored:
val = original[tag]
2019-06-13 18:54:11 +03:00
if tag.endswith("Resolution"):
if legacy_api:
self.assertEqual(
c_float(val[0][0] / val[0][1]).value,
c_float(value[0][0] / value[0][1]).value,
2019-06-13 18:54:11 +03:00
msg="%s didn't roundtrip" % tag,
)
else:
self.assertEqual(
2019-06-13 18:54:11 +03:00
c_float(val).value,
c_float(value).value,
msg="%s didn't roundtrip" % tag,
)
else:
2019-06-13 18:54:11 +03:00
self.assertEqual(val, value, msg="%s didn't roundtrip" % tag)
2014-06-10 13:10:47 +04:00
2015-12-14 23:24:01 +03:00
# https://github.com/python-pillow/Pillow/issues/1561
2019-06-13 18:54:11 +03:00
requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"]
2015-12-14 23:24:01 +03:00
for field in requested_fields:
self.assertIn(field, reloaded, "%s not in metadata" % field)
2015-12-14 23:24:01 +03:00
2016-01-01 16:30:40 +03:00
def test_additional_metadata(self):
# these should not crash. Seriously dummy data, most of it doesn't make
# any sense, so we're running up against limits where we're asking
# libtiff to do stupid things.
2016-02-05 01:57:13 +03:00
2016-01-01 16:30:40 +03:00
# Get the list of the ones that we should be able to write
2019-06-13 18:54:11 +03:00
core_items = {
tag: info
for tag, info in ((s, TiffTags.lookup(s)) for s in TiffTags.LIBTIFF_CORE)
if info.type is not None
}
2016-02-05 01:57:13 +03:00
2016-08-04 09:40:12 +03:00
# Exclude ones that have special meaning
# that we're already testing them
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/hopper_g4.tif")
for tag in im.tag_v2:
2016-01-01 16:30:40 +03:00
try:
del core_items[tag]
2018-06-11 09:00:57 +03:00
except KeyError:
2016-02-05 01:57:13 +03:00
pass
2016-01-01 16:30:40 +03:00
# Type codes:
# 2: "ascii",
# 3: "short",
# 4: "long",
# 5: "rational",
# 12: "double",
# Type: dummy value
2019-06-13 18:54:11 +03:00
values = {
2: "test",
3: 1,
4: 2 ** 20,
5: TiffImagePlugin.IFDRational(100, 1),
12: 1.05,
}
2016-01-01 16:30:40 +03:00
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
for tag, info in core_items.items():
if info.length == 1:
new_ifd[tag] = values[info.type]
if info.length == 0:
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
else:
2019-06-13 18:54:11 +03:00
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
2016-01-01 16:30:40 +03:00
2016-02-05 01:57:13 +03:00
# Extra samples really doesn't make sense in this application.
del new_ifd[338]
2016-01-01 16:30:40 +03:00
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out, tiffinfo=new_ifd)
2016-02-05 01:57:13 +03:00
TiffImagePlugin.WRITE_LIBTIFF = False
2016-01-01 16:30:40 +03:00
2018-10-25 11:45:13 +03:00
def test_custom_metadata(self):
tc = namedtuple("test_case", "value,type,supported_by_default")
2018-10-25 11:45:13 +03:00
custom = {
37000 + k: v
for k, v in enumerate(
[
tc(4, TiffTags.SHORT, True),
tc(123456789, TiffTags.LONG, True),
tc(-4, TiffTags.SIGNED_BYTE, False),
tc(-4, TiffTags.SIGNED_SHORT, False),
tc(-123456789, TiffTags.SIGNED_LONG, False),
tc(TiffImagePlugin.IFDRational(4, 7), TiffTags.RATIONAL, True),
tc(4.25, TiffTags.FLOAT, True),
tc(4.25, TiffTags.DOUBLE, True),
tc("custom tag value", TiffTags.ASCII, True),
tc(u"custom tag value", TiffTags.ASCII, True),
tc(b"custom tag value", TiffTags.BYTE, True),
tc((4, 5, 6), TiffTags.SHORT, True),
tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
tc((-4, 9, 10), TiffTags.SIGNED_BYTE, False),
tc((-4, 5, 6), TiffTags.SIGNED_SHORT, False),
tc(
(-123456789, 9, 34, 234, 219387, -92432323),
TiffTags.SIGNED_LONG,
False,
),
tc((4.25, 5.25), TiffTags.FLOAT, True),
tc((4.25, 5.25), TiffTags.DOUBLE, True),
# array of TIFF_BYTE requires bytes instead of tuple for backwards
# compatibility
tc(bytes([4]), TiffTags.BYTE, True),
tc(bytes((4, 9, 10)), TiffTags.BYTE, True),
]
)
2018-10-25 11:45:13 +03:00
}
libtiff_version = TiffImagePlugin._libtiff_version()
libtiffs = [False]
2019-06-13 18:54:11 +03:00
if distutils.version.StrictVersion(
libtiff_version
) >= distutils.version.StrictVersion("4.0"):
libtiffs.append(True)
for libtiff in libtiffs:
2018-10-25 11:45:13 +03:00
TiffImagePlugin.WRITE_LIBTIFF = libtiff
2019-02-22 15:17:26 +03:00
def check_tags(tiffinfo):
im = hopper()
2018-10-25 11:45:13 +03:00
2019-02-22 15:17:26 +03:00
out = self.tempfile("temp.tif")
im.save(out, tiffinfo=tiffinfo)
2018-10-25 11:45:13 +03:00
2019-02-22 15:17:26 +03:00
reloaded = Image.open(out)
for tag, value in tiffinfo.items():
reloaded_value = reloaded.tag_v2[tag]
if (
isinstance(reloaded_value, TiffImagePlugin.IFDRational)
and libtiff
):
# libtiff does not support real RATIONALS
self.assertAlmostEqual(float(reloaded_value), float(value))
continue
2019-02-22 15:17:26 +03:00
if libtiff and isinstance(value, bytes):
value = value.decode()
self.assertEqual(reloaded_value, value)
# Test with types
ifd = TiffImagePlugin.ImageFileDirectory_v2()
for tag, tagdata in custom.items():
ifd[tag] = tagdata.value
ifd.tagtype[tag] = tagdata.type
2019-02-22 15:17:26 +03:00
check_tags(ifd)
# Test without types. This only works for some types, int for example are
# always encoded as LONG and not SIGNED_LONG.
check_tags(
{
tag: tagdata.value
for tag, tagdata in custom.items()
if tagdata.supported_by_default
}
)
2019-02-22 15:17:26 +03:00
TiffImagePlugin.WRITE_LIBTIFF = False
2018-10-25 11:45:13 +03:00
2016-12-13 23:49:47 +03:00
def test_int_dpi(self):
# issue #1765
2019-06-13 18:54:11 +03:00
im = hopper("RGB")
out = self.tempfile("temp.tif")
2016-12-13 23:49:47 +03:00
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out, dpi=(72, 72))
TiffImagePlugin.WRITE_LIBTIFF = False
reloaded = Image.open(out)
2019-06-13 18:54:11 +03:00
self.assertEqual(reloaded.info["dpi"], (72.0, 72.0))
2016-12-13 23:49:47 +03:00
2014-06-10 13:10:47 +04:00
def test_g3_compression(self):
2019-06-13 18:54:11 +03:00
i = Image.open("Tests/images/hopper_g4_500.tif")
2014-06-10 13:10:47 +04:00
out = self.tempfile("temp.tif")
2019-06-13 18:54:11 +03:00
i.save(out, compression="group3")
2014-06-10 13:10:47 +04:00
reread = Image.open(out)
2019-06-13 18:54:11 +03:00
self.assertEqual(reread.info["compression"], "group3")
2014-06-10 13:10:47 +04:00
self.assert_image_equal(reread, i)
def test_little_endian(self):
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/16bit.deflate.tif")
2014-06-10 13:10:47 +04:00
self.assertEqual(im.getpixel((0, 0)), 480)
2019-06-13 18:54:11 +03:00
self.assertEqual(im.mode, "I;16")
2014-06-10 13:10:47 +04:00
b = im.tobytes()
# Bytes are in image native order (little endian)
if py3:
2019-06-13 18:54:11 +03:00
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
2014-06-10 13:10:47 +04:00
else:
2019-06-13 18:54:11 +03:00
self.assertEqual(b[0], b"\xe0")
self.assertEqual(b[1], b"\x01")
2014-06-10 13:10:47 +04:00
out = self.tempfile("temp.tif")
# out = "temp.le.tif"
im.save(out)
reread = Image.open(out)
2019-06-13 18:54:11 +03:00
self.assertEqual(reread.info["compression"], im.info["compression"])
2014-06-10 13:10:47 +04:00
self.assertEqual(reread.getpixel((0, 0)), 480)
# UNDONE - libtiff defaults to writing in native endian, so
# on big endian, we'll get back mode = 'I;16B' here.
def test_big_endian(self):
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/16bit.MM.deflate.tif")
2014-06-10 13:10:47 +04:00
self.assertEqual(im.getpixel((0, 0)), 480)
2019-06-13 18:54:11 +03:00
self.assertEqual(im.mode, "I;16B")
2014-06-10 13:10:47 +04:00
b = im.tobytes()
# Bytes are in image native order (big endian)
if py3:
2019-06-13 18:54:11 +03:00
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
2014-06-10 13:10:47 +04:00
else:
2019-06-13 18:54:11 +03:00
self.assertEqual(b[0], b"\x01")
self.assertEqual(b[1], b"\xe0")
2014-06-10 13:10:47 +04:00
out = self.tempfile("temp.tif")
im.save(out)
reread = Image.open(out)
2019-06-13 18:54:11 +03:00
self.assertEqual(reread.info["compression"], im.info["compression"])
2014-06-10 13:10:47 +04:00
self.assertEqual(reread.getpixel((0, 0)), 480)
def test_g4_string_info(self):
"""Tests String data in info directory"""
2015-04-02 11:45:24 +03:00
test_file = "Tests/images/hopper_g4_500.tif"
orig = Image.open(test_file)
2014-06-10 13:10:47 +04:00
out = self.tempfile("temp.tif")
2019-06-13 18:54:11 +03:00
orig.tag[269] = "temp.tif"
2014-06-10 13:10:47 +04:00
orig.save(out)
reread = Image.open(out)
2019-06-13 18:54:11 +03:00
self.assertEqual("temp.tif", reread.tag_v2[269])
self.assertEqual("temp.tif", reread.tag[269][0])
2014-06-10 13:10:47 +04:00
def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
TiffImagePlugin.READ_LIBTIFF = True
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/12bit.cropped.tif")
2014-06-10 13:10:47 +04:00
im.load()
TiffImagePlugin.READ_LIBTIFF = False
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
2019-06-13 18:54:11 +03:00
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
2014-06-10 13:10:47 +04:00
def test_blur(self):
# test case from irc, how to do blur on b/w image
# and save to compressed tif.
from PIL import ImageFilter
2019-06-13 18:54:11 +03:00
out = self.tempfile("temp.tif")
im = Image.open("Tests/images/pport_g4.tif")
im = im.convert("L")
2014-06-10 13:10:47 +04:00
im = im.filter(ImageFilter.GaussianBlur(4))
2019-06-13 18:54:11 +03:00
im.save(out, compression="tiff_adobe_deflate")
2014-06-10 13:10:47 +04:00
im2 = Image.open(out)
im2.load()
2013-10-22 21:09:25 +04:00
2014-06-10 13:10:47 +04:00
self.assert_image_equal(im, im2)
2014-06-10 13:10:47 +04:00
def test_compressions(self):
# Test various tiff compressions and assert similar image content but reduced
# file sizes.
2019-06-13 18:54:11 +03:00
im = hopper("RGB")
out = self.tempfile("temp.tif")
im.save(out)
size_raw = os.path.getsize(out)
2019-06-13 18:54:11 +03:00
for compression in ("packbits", "tiff_lzw"):
2014-06-10 13:10:47 +04:00
im.save(out, compression=compression)
size_compressed = os.path.getsize(out)
2014-06-10 13:10:47 +04:00
im2 = Image.open(out)
self.assert_image_equal(im, im2)
2013-11-06 08:53:18 +04:00
2019-06-13 18:54:11 +03:00
im.save(out, compression="jpeg")
size_jpeg = os.path.getsize(out)
im2 = Image.open(out)
2014-06-10 13:10:47 +04:00
self.assert_image_similar(im, im2, 30)
im.save(out, compression="jpeg", quality=30)
size_jpeg_30 = os.path.getsize(out)
im3 = Image.open(out)
self.assert_image_similar(im2, im3, 30)
2019-06-30 11:13:02 +03:00
self.assertGreater(size_raw, size_compressed)
self.assertGreater(size_compressed, size_jpeg)
self.assertGreater(size_jpeg, size_jpeg_30)
def test_quality(self):
im = hopper("RGB")
out = self.tempfile("temp.tif")
self.assertRaises(ValueError, im.save, out, compression="tiff_lzw", quality=50)
self.assertRaises(ValueError, im.save, out, compression="jpeg", quality=-1)
self.assertRaises(ValueError, im.save, out, compression="jpeg", quality=101)
self.assertRaises(ValueError, im.save, out, compression="jpeg", quality="good")
im.save(out, compression="jpeg", quality=0)
im.save(out, compression="jpeg", quality=100)
2014-06-10 13:10:47 +04:00
def test_cmyk_save(self):
2019-06-13 18:54:11 +03:00
im = hopper("CMYK")
out = self.tempfile("temp.tif")
2014-06-10 13:10:47 +04:00
2019-06-13 18:54:11 +03:00
im.save(out, compression="tiff_adobe_deflate")
2014-06-10 13:10:47 +04:00
im2 = Image.open(out)
self.assert_image_equal(im, im2)
def xtest_bw_compression_w_rgb(self):
2014-06-10 13:10:47 +04:00
""" This test passes, but when running all tests causes a failure due
to output on stderr from the error thrown by libtiff. We need to
capture that but not now"""
2019-06-13 18:54:11 +03:00
im = hopper("RGB")
out = self.tempfile("temp.tif")
2019-06-13 18:54:11 +03:00
self.assertRaises(IOError, im.save, out, compression="tiff_ccitt")
self.assertRaises(IOError, im.save, out, compression="group3")
self.assertRaises(IOError, im.save, out, compression="group4")
2014-06-10 13:10:47 +04:00
def test_fp_leak(self):
2014-09-23 17:16:04 +04:00
im = Image.open("Tests/images/hopper_g4_500.tif")
2014-06-10 13:10:47 +04:00
fn = im.fp.fileno()
2014-06-10 13:10:47 +04:00
os.fstat(fn)
im.load() # this should close it.
2017-09-01 14:05:40 +03:00
self.assertRaises(OSError, os.fstat, fn)
2014-06-10 13:10:47 +04:00
im = None # this should force even more closed.
2017-09-01 14:05:40 +03:00
self.assertRaises(OSError, os.fstat, fn)
self.assertRaises(OSError, os.close, fn)
2014-08-21 08:43:46 +04:00
def test_multipage(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/multipage.tiff")
2014-08-21 08:43:46 +04:00
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
im.seek(0)
self.assertEqual(im.size, (10, 10))
2019-06-13 18:54:11 +03:00
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
2014-08-21 08:43:46 +04:00
self.assertTrue(im.tag.next)
im.seek(1)
self.assertEqual(im.size, (10, 10))
2019-06-13 18:54:11 +03:00
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
2014-08-21 08:43:46 +04:00
self.assertTrue(im.tag.next)
im.seek(2)
self.assertFalse(im.tag.next)
self.assertEqual(im.size, (20, 20))
2019-06-13 18:54:11 +03:00
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
2014-08-21 08:43:46 +04:00
TiffImagePlugin.READ_LIBTIFF = False
2016-11-17 15:43:11 +03:00
def test_multipage_nframes(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/multipage.tiff")
2016-11-17 15:43:11 +03:00
frames = im.n_frames
self.assertEqual(frames, 3)
2018-10-01 13:22:18 +03:00
for _ in range(frames):
2016-11-17 15:43:11 +03:00
im.seek(0)
# Should not raise ValueError: I/O operation on closed file
im.load()
TiffImagePlugin.READ_LIBTIFF = False
2014-08-21 08:43:46 +04:00
def test__next(self):
TiffImagePlugin.READ_LIBTIFF = True
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/hopper.tif")
2014-08-21 08:43:46 +04:00
self.assertFalse(im.tag.next)
im.load()
self.assertFalse(im.tag.next)
2014-10-29 21:07:20 +03:00
def test_4bit(self):
# Arrange
test_file = "Tests/images/hopper_gray_4bpp.tif"
original = hopper("L")
# Act
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open(test_file)
TiffImagePlugin.READ_LIBTIFF = False
# Assert
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self):
test_files = (
(
2016-08-04 09:40:12 +03:00
24.8, # epsilon
( # group
"Tests/images/tiff_gray_2_4_bpp/hopper2.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
2019-06-13 18:54:11 +03:00
),
),
(
2016-08-04 09:40:12 +03:00
7.3, # epsilon
( # group
"Tests/images/tiff_gray_2_4_bpp/hopper4.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
2019-06-13 18:54:11 +03:00
),
),
)
original = hopper("L")
for epsilon, group in test_files:
im = Image.open(group[0])
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
for file in group[1:]:
im2 = Image.open(file)
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
2014-11-16 07:38:52 +03:00
def test_save_bytesio(self):
# PR 1011
# Test TIFF saving to io.BytesIO() object.
2014-11-16 07:38:52 +03:00
TiffImagePlugin.WRITE_LIBTIFF = True
TiffImagePlugin.READ_LIBTIFF = True
# Generate test image
pilim = hopper()
def save_bytesio(compression=None):
2014-11-16 07:38:52 +03:00
buffer_io = io.BytesIO()
pilim.save(buffer_io, format="tiff", compression=compression)
buffer_io.seek(0)
pilim_load = Image.open(buffer_io)
self.assert_image_similar(pilim, pilim_load, 0)
save_bytesio()
2019-06-13 18:54:11 +03:00
save_bytesio("raw")
2014-11-16 07:38:52 +03:00
save_bytesio("packbits")
save_bytesio("tiff_lzw")
2014-11-16 07:38:52 +03:00
TiffImagePlugin.WRITE_LIBTIFF = False
TiffImagePlugin.READ_LIBTIFF = False
2014-10-29 21:07:20 +03:00
def test_crashing_metadata(self):
# issue 1597
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/rdf.tif")
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
# this shouldn't crash
2019-06-13 18:54:11 +03:00
im.save(out, format="TIFF")
TiffImagePlugin.WRITE_LIBTIFF = False
def test_page_number_x_0(self):
# Issue 973
# Test TIFF with tag 297 (Page Number) having value of 0 0.
# The first number is the current page number.
# The second is the total number of pages, zero means not available.
outfile = self.tempfile("temp.tif")
# Created by printing a page in Chrome to PDF, then:
# /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
# -dNOPAUSE /tmp/test.pdf -c quit
infile = "Tests/images/total-pages-zero.tif"
im = Image.open(infile)
# Should not divide by zero
im.save(outfile)
2016-09-30 00:29:19 +03:00
def test_fd_duplication(self):
# https://github.com/python-pillow/Pillow/issues/1651
tmpfile = self.tempfile("temp.tif")
2019-06-13 18:54:11 +03:00
with open(tmpfile, "wb") as f:
with open("Tests/images/g4-multi.tiff", "rb") as src:
2016-09-30 00:29:19 +03:00
f.write(src.read())
im = Image.open(tmpfile)
2018-06-15 12:55:48 +03:00
im.n_frames
2016-09-30 00:29:19 +03:00
im.close()
# Should not raise PermissionError.
os.remove(tmpfile)
2016-09-30 00:29:19 +03:00
def test_read_icc(self):
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
2019-06-13 18:54:11 +03:00
icc = img.info.get("icc_profile")
2018-08-04 21:08:40 +03:00
self.assertIsNotNone(icc)
TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
2019-06-13 18:54:11 +03:00
icc_libtiff = img.info.get("icc_profile")
2018-08-04 21:08:40 +03:00
self.assertIsNotNone(icc_libtiff)
TiffImagePlugin.READ_LIBTIFF = False
self.assertEqual(icc, icc_libtiff)
def test_multipage_compression(self):
2019-06-13 18:54:11 +03:00
im = Image.open("Tests/images/compression.tif")
im.seek(0)
2019-06-13 18:54:11 +03:00
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.seek(1)
2019-06-13 18:54:11 +03:00
self.assertEqual(im._compression, "packbits")
self.assertEqual(im.size, (10, 10))
im.load()
im.seek(0)
2019-06-13 18:54:11 +03:00
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.load()
def test_save_tiff_with_jpegtables(self):
# Arrange
outfile = self.tempfile("temp.tif")
# Created with ImageMagick: convert hopper.jpg hopper_jpg.tif
# Contains JPEGTables (347) tag
infile = "Tests/images/hopper_jpg.tif"
im = Image.open(infile)
# Act / Assert
# Should not raise UnicodeDecodeError or anything else
im.save(outfile)
2019-05-08 22:08:17 +03:00
def test_16bit_RGB_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGB.tiff")
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
2019-06-13 18:54:11 +03:00
[
(
2019-06-23 07:01:51 +03:00
"libtiff",
2019-06-13 18:54:11 +03:00
(0, 0, 100, 40),
0,
2019-06-23 07:01:51 +03:00
("RGB;16N", "tiff_adobe_deflate", False, 8),
2019-06-13 18:54:11 +03:00
)
],
2019-05-08 22:08:17 +03:00
)
im.load()
2019-06-13 18:54:11 +03:00
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
2019-05-08 22:08:17 +03:00
def test_16bit_RGBa_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGBa.tiff")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (100, 40))
2018-06-24 15:32:25 +03:00
self.assertEqual(
im.tile,
[("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236))],
2018-06-24 15:32:25 +03:00
)
im.load()
2019-06-13 18:54:11 +03:00
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
def test_gimp_tiff(self):
# Read TIFF JPEG images from GIMP [@PIL168]
codecs = dir(Image.core)
if "jpeg_decoder" not in codecs:
self.skipTest("jpeg support not available")
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (256, 256))
self.assertEqual(
im.tile, [("libtiff", (0, 0, 256, 256), 0, ("RGB", "jpeg", False, 5122))]
)
im.load()
self.assert_image_equal_tofile(im, "Tests/images/pil168.png")
def test_sampleformat(self):
# https://github.com/python-pillow/Pillow/issues/1466
im = Image.open("Tests/images/copyleft.tiff")
2019-06-13 18:54:11 +03:00
self.assertEqual(im.mode, "RGB")
2019-06-13 18:54:11 +03:00
self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")
def test_lzw(self):
im = Image.open("Tests/images/hopper_lzw.tif")
2019-06-13 18:54:11 +03:00
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "TIFF")
im2 = hopper()
self.assert_image_similar(im, im2, 5)
def test_strip_cmyk_jpeg(self):
infile = "Tests/images/tiff_strip_cmyk_jpeg.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
2019-04-30 17:42:30 +03:00
def test_strip_cmyk_16l_jpeg(self):
infile = "Tests/images/tiff_strip_cmyk_16l_jpeg.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
def test_strip_ycbcr_jpeg_2x2_sampling(self):
infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
def test_strip_ycbcr_jpeg_1x1_sampling(self):
infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im, "Tests/images/flower2.jpg")
def test_tiled_cmyk_jpeg(self):
infile = "Tests/images/tiff_tiled_cmyk_jpeg.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
def test_tiled_ycbcr_jpeg_1x1_sampling(self):
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im, "Tests/images/flower2.jpg")
def test_tiled_ycbcr_jpeg_2x2_sampling(self):
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
def test_old_style_jpeg(self):
infile = "Tests/images/old-style-jpeg-compression.tif"
im = Image.open(infile)
2019-06-13 18:54:11 +03:00
self.assert_image_equal_tofile(
im, "Tests/images/old-style-jpeg-compression.png"
)
2019-09-13 15:36:26 +03:00
2019-09-18 15:07:17 +03:00
def test_no_rows_per_strip(self):
# This image does not have a RowsPerStrip TIFF tag
infile = "Tests/images/no_rows_per_strip.tif"
im = Image.open(infile)
im.load()
self.assertEqual(im.size, (950, 975))
2019-09-20 22:59:29 +03:00
2019-09-13 15:36:26 +03:00
def test_orientation(self):
base_im = Image.open("Tests/images/g4_orientation_1.tif")
for i in range(2, 9):
im = Image.open("Tests/images/g4_orientation_" + str(i) + ".tif")
im.load()
self.assert_image_similar(base_im, im, 0.7)
def test_sampleformat_not_corrupted(self):
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
# when saving to a new file.
# Pillow 6.0 fails with "OSError: cannot identify image file".
tiff = io.BytesIO(
base64.b64decode(
b"SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAAQAAAAEBBAABAAAAAQAA"
b"AAIBAwADAAAAwgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAA"
b"4AAAABUBAwABAAAAAwAAABYBBAABAAAAAQAAABcBBAABAAAACwAAABoBBQAB"
b"AAAAyAAAABsBBQABAAAA0AAAABwBAwABAAAAAQAAACgBAwABAAAAAQAAAFMB"
b"AwADAAAA2AAAAAAAAAAIAAgACAABAAAAAQAAAAEAAAABAAAAAQABAAEAAAB4"
b"nGNgYAAAAAMAAQ=="
)
)
out = io.BytesIO()
with Image.open(tiff) as im:
im.save(out, format="tiff")
out.seek(0)
with Image.open(out) as im:
im.load()