Pillow/Tests/test_file_png.py

676 lines
22 KiB
Python
Raw Normal View History

from .helper import unittest, PillowTestCase, PillowLeakTestCase, hopper
from PIL import Image, ImageFile, PngImagePlugin
2018-04-20 02:19:13 +03:00
from PIL._util import py3
2014-06-10 13:10:47 +04:00
from io import BytesIO
2013-08-20 16:17:17 +04:00
import zlib
import sys
2018-12-27 04:19:44 +03:00
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
codecs = dir(Image.core)
# sample png stream
2014-09-04 13:09:52 +04:00
TEST_PNG_FILE = "Tests/images/hopper.png"
# stuff to create inline PNG images
MAGIC = PngImagePlugin._MAGIC
2014-06-10 13:10:47 +04:00
def chunk(cid, *data):
2015-04-24 11:24:52 +03:00
test_file = BytesIO()
PngImagePlugin.putchunk(*(test_file, cid) + data)
return test_file.getvalue()
2018-03-03 12:54:00 +03:00
o32 = PngImagePlugin.o32
IHDR = chunk(b"IHDR", o32(1), o32(1), b'\x08\x02', b'\0\0\0')
IDAT = chunk(b"IDAT")
IEND = chunk(b"IEND")
HEAD = MAGIC + IHDR
TAIL = IDAT + IEND
2014-06-10 13:10:47 +04:00
def load(data):
return Image.open(BytesIO(data))
2014-06-10 13:10:47 +04:00
def roundtrip(im, **options):
out = BytesIO()
im.save(out, "PNG", **options)
out.seek(0)
return Image.open(out)
2014-06-10 13:10:47 +04:00
class TestFilePng(PillowTestCase):
def setUp(self):
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
2017-12-20 13:27:13 +03:00
def get_chunks(self, filename):
chunks = []
with open(filename, "rb") as fp:
fp.read(8)
2017-12-20 14:45:52 +03:00
with PngImagePlugin.PngStream(fp) as png:
while True:
cid, pos, length = png.read()
chunks.append(cid)
try:
s = png.call(cid, pos, length)
except EOFError:
break
png.crc(cid, s)
2017-12-20 13:27:13 +03:00
return chunks
2014-06-10 13:10:47 +04:00
def test_sanity(self):
2014-06-10 13:10:47 +04:00
# internal version number
self.assertRegex(Image.core.zlib_version, r"\d+\.\d+\.\d+(\.\d+)?$")
2015-04-24 11:24:52 +03:00
test_file = self.tempfile("temp.png")
2015-04-24 11:24:52 +03:00
hopper("RGB").save(test_file)
2015-04-24 11:24:52 +03:00
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PNG")
self.assertEqual(im.get_format_mimetype(), 'image/png')
2019-03-12 09:28:42 +03:00
for mode in ["1", "L", "P", "RGB", "I", "I;16"]:
im = hopper(mode)
im.save(test_file)
reloaded = Image.open(test_file)
if mode == "I;16":
reloaded = reloaded.convert(mode)
self.assert_image_equal(reloaded, im)
2015-07-03 08:03:25 +03:00
def test_invalid_file(self):
2015-07-03 09:22:56 +03:00
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
2017-09-01 14:05:40 +03:00
PngImagePlugin.PngImageFile, invalid_file)
2015-07-03 08:03:25 +03:00
2014-06-10 13:10:47 +04:00
def test_broken(self):
# Check reading of totally broken files. In this case, the test
# file was checked into Subversion as a text file.
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/broken.png"
2017-09-01 14:05:40 +03:00
self.assertRaises(IOError, Image.open, test_file)
2014-06-10 13:10:47 +04:00
def test_bad_text(self):
# Make sure PIL can read malformed tEXt chunks (@PIL152)
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'tEXt') + TAIL)
self.assertEqual(im.info, {})
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL)
self.assertEqual(im.info, {'spam': ''})
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL)
self.assertEqual(im.info, {'spam': ''})
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL)
self.assertEqual(im.info, {'spam': 'egg'})
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL)
self.assertEqual(im.info, {'spam': 'egg\x00'})
2014-06-10 13:10:47 +04:00
def test_bad_ztxt(self):
# Test reading malformed zTXt chunks (python-pillow/Pillow#318)
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'zTXt') + TAIL)
self.assertEqual(im.info, {})
2013-08-20 16:17:17 +04:00
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'zTXt', b'spam') + TAIL)
self.assertEqual(im.info, {'spam': ''})
2013-08-20 16:17:17 +04:00
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'zTXt', b'spam\0') + TAIL)
self.assertEqual(im.info, {'spam': ''})
2013-08-20 16:17:17 +04:00
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(b'zTXt', b'spam\0\0') + TAIL)
self.assertEqual(im.info, {'spam': ''})
2013-08-20 16:17:17 +04:00
2014-06-10 13:10:47 +04:00
im = load(HEAD + chunk(
b'zTXt', b'spam\0\0' + zlib.compress(b'egg')[:1]) + TAIL)
self.assertEqual(im.info, {'spam': ''})
2013-08-20 16:17:17 +04:00
2014-06-10 13:10:47 +04:00
im = load(
HEAD + chunk(b'zTXt', b'spam\0\0' + zlib.compress(b'egg')) + TAIL)
self.assertEqual(im.info, {'spam': 'egg'})
2013-08-20 16:17:17 +04:00
2014-07-23 12:09:06 +04:00
def test_bad_itxt(self):
im = load(HEAD + chunk(b'iTXt') + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam') + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0') + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\x02') + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\0\0foo\0') + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\0\0en\0Spam\0egg') + TAIL)
self.assertEqual(im.info, {"spam": "egg"})
self.assertEqual(im.info["spam"].lang, "en")
self.assertEqual(im.info["spam"].tkey, "Spam")
2014-08-28 15:44:19 +04:00
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\0en\0Spam\0' +
zlib.compress(b"egg")[:1]) + TAIL)
2015-04-24 02:26:52 +03:00
self.assertEqual(im.info, {'spam': ''})
2014-07-23 12:09:06 +04:00
2014-08-28 15:44:19 +04:00
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\1en\0Spam\0' +
zlib.compress(b"egg")) + TAIL)
2014-07-23 12:09:06 +04:00
self.assertEqual(im.info, {})
2014-08-28 15:44:19 +04:00
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\0en\0Spam\0' +
zlib.compress(b"egg")) + TAIL)
2014-07-23 12:09:06 +04:00
self.assertEqual(im.info, {"spam": "egg"})
self.assertEqual(im.info["spam"].lang, "en")
self.assertEqual(im.info["spam"].tkey, "Spam")
2014-06-10 13:10:47 +04:00
def test_interlace(self):
2013-08-20 16:17:17 +04:00
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/pil123p.png"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self.assert_image(im, "P", (162, 150))
self.assertTrue(im.info.get("interlace"))
2014-06-10 13:10:47 +04:00
im.load()
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/pil123rgba.png"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self.assert_image(im, "RGBA", (162, 150))
self.assertTrue(im.info.get("interlace"))
2014-06-10 13:10:47 +04:00
im.load()
2014-06-10 13:10:47 +04:00
def test_load_transparent_p(self):
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/pil123p.png"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self.assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (162, 150))
2016-10-02 13:31:53 +03:00
# image has 124 unique alpha values
2017-08-09 02:36:07 +03:00
self.assertEqual(len(im.getchannel('A').getcolors()), 124)
2014-06-10 13:10:47 +04:00
def test_load_transparent_rgb(self):
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/rgb_trns.png"
im = Image.open(test_file)
self.assertEqual(im.info["transparency"], (0, 255, 52))
2014-06-10 13:10:47 +04:00
self.assert_image(im, "RGB", (64, 64))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (64, 64))
2013-11-23 04:04:51 +04:00
2014-06-10 13:10:47 +04:00
# image has 876 transparent pixels
2017-08-09 02:36:07 +03:00
self.assertEqual(im.getchannel('A').getcolors()[0][0], 876)
2013-11-23 04:04:51 +04:00
2014-06-10 13:10:47 +04:00
def test_save_p_transparent_palette(self):
in_file = "Tests/images/pil123p.png"
im = Image.open(in_file)
2013-11-23 04:04:51 +04:00
2016-05-03 21:46:22 +03:00
# 'transparency' contains a byte string with the opacity for
# each palette entry
self.assertEqual(len(im.info["transparency"]), 256)
2015-04-24 11:24:52 +03:00
test_file = self.tempfile("temp.png")
im.save(test_file)
# check if saved image contains same transparency
im = Image.open(test_file)
self.assertEqual(len(im.info["transparency"]), 256)
self.assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (162, 150))
2016-05-03 21:46:22 +03:00
# image has 124 unique alpha values
2017-08-09 02:36:07 +03:00
self.assertEqual(len(im.getchannel('A').getcolors()), 124)
2014-06-10 13:10:47 +04:00
def test_save_p_single_transparency(self):
in_file = "Tests/images/p_trns_single.png"
im = Image.open(in_file)
# pixel value 164 is full transparent
self.assertEqual(im.info["transparency"], 164)
self.assertEqual(im.getpixel((31, 31)), 164)
test_file = self.tempfile("temp.png")
im.save(test_file)
# check if saved image contains same transparency
im = Image.open(test_file)
self.assertEqual(im.info["transparency"], 164)
self.assertEqual(im.getpixel((31, 31)), 164)
self.assert_image(im, "P", (64, 64))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (64, 64))
self.assertEqual(im.getpixel((31, 31)), (0, 255, 52, 0))
# image has 876 transparent pixels
2017-08-09 02:36:07 +03:00
self.assertEqual(im.getchannel('A').getcolors()[0][0], 876)
def test_save_p_transparent_black(self):
# check if solid black image with full transparency
# is supported (check for #1838)
im = Image.new("RGBA", (10, 10), (0, 0, 0, 0))
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
im = im.convert("P")
2015-04-24 11:24:52 +03:00
test_file = self.tempfile("temp.png")
im.save(test_file)
# check if saved image contains same transparency
im = Image.open(test_file)
self.assertEqual(len(im.info["transparency"]), 256)
self.assert_image(im, "P", (10, 10))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (10, 10))
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
def test_save_greyscale_transparency(self):
for mode, num_transparent in {
"1": 1994,
"L": 559,
"I": 559,
}.items():
in_file = "Tests/images/"+mode.lower()+"_trns.png"
im = Image.open(in_file)
self.assertEqual(im.mode, mode)
self.assertEqual(im.info["transparency"], 255)
im_rgba = im.convert('RGBA')
self.assertEqual(
im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
test_file = self.tempfile("temp.png")
im.save(test_file)
test_im = Image.open(test_file)
self.assertEqual(test_im.mode, mode)
self.assertEqual(test_im.info["transparency"], 255)
self.assert_image_equal(im, test_im)
test_im_rgba = test_im.convert('RGBA')
self.assertEqual(
test_im_rgba.getchannel('A').getcolors()[0][0], num_transparent)
2014-06-10 13:10:47 +04:00
def test_save_rgb_single_transparency(self):
in_file = "Tests/images/caption_6_33_22.png"
im = Image.open(in_file)
2015-04-24 11:24:52 +03:00
test_file = self.tempfile("temp.png")
im.save(test_file)
2014-06-10 13:10:47 +04:00
def test_load_verify(self):
# Check open/load/verify exception (@PIL150)
2014-09-04 13:09:52 +04:00
im = Image.open(TEST_PNG_FILE)
2018-11-13 14:13:55 +03:00
# Assert that there is no unclosed file warning
self.assert_warning(None, im.verify)
2014-09-04 13:09:52 +04:00
im = Image.open(TEST_PNG_FILE)
2014-06-10 13:10:47 +04:00
im.load()
2015-04-02 10:08:14 +03:00
self.assertRaises(RuntimeError, im.verify)
def test_verify_struct_error(self):
# Check open/load/verify exception (#1755)
# offsets to test, -10: breaks in i32() in read. (IOError)
# -13: breaks in crc, txt chunk.
# -14: malformed chunk
for offset in (-10, -13, -14):
2016-08-04 09:40:12 +03:00
with open(TEST_PNG_FILE, 'rb') as f:
test_file = f.read()[:offset]
im = Image.open(BytesIO(test_file))
self.assertIsNotNone(im.fp)
self.assertRaises((IOError, SyntaxError), im.verify)
def test_verify_ignores_crc_error(self):
# check ignores crc errors in ancillary chunks
chunk_data = chunk(b'tEXt', b'spam')
broken_crc_chunk_data = chunk_data[:-1] + b'q' # break CRC
image_data = HEAD + broken_crc_chunk_data + TAIL
2018-06-24 15:32:25 +03:00
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
BytesIO(image_data))
ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
im = load(image_data)
self.assertIsNotNone(im)
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_verify_not_ignores_crc_error_in_required_chunk(self):
# check does not ignore crc errors in required chunks
image_data = MAGIC + IHDR[:-1] + b'q' + TAIL
ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
2018-06-24 15:32:25 +03:00
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
BytesIO(image_data))
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False
2014-06-10 13:10:47 +04:00
def test_roundtrip_dpi(self):
# Check dpi roundtripping
2014-09-04 13:09:52 +04:00
im = Image.open(TEST_PNG_FILE)
2014-06-10 13:10:47 +04:00
im = roundtrip(im, dpi=(100, 100))
self.assertEqual(im.info["dpi"], (100, 100))
2019-03-30 07:03:57 +03:00
def test_load_dpi_rounding(self):
# Round up
im = Image.open(TEST_PNG_FILE)
self.assertEqual(im.info["dpi"], (96, 96))
# Round down
im = Image.open("Tests/images/icc_profile_none.png")
self.assertEqual(im.info["dpi"], (72, 72))
def test_save_dpi_rounding(self):
im = Image.open(TEST_PNG_FILE)
im = roundtrip(im, dpi=(72.2, 72.2))
self.assertEqual(im.info["dpi"], (72, 72))
im = roundtrip(im, dpi=(72.8, 72.8))
self.assertEqual(im.info["dpi"], (73, 73))
2014-06-10 13:10:47 +04:00
def test_roundtrip_text(self):
# Check text roundtripping
2014-09-04 13:09:52 +04:00
im = Image.open(TEST_PNG_FILE)
2014-06-10 13:10:47 +04:00
info = PngImagePlugin.PngInfo()
info.add_text("TXT", "VALUE")
info.add_text("ZIP", "VALUE", zip=True)
2014-06-10 13:10:47 +04:00
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
2014-07-23 18:27:51 +04:00
def test_roundtrip_itxt(self):
# Check iTXt roundtripping
im = Image.new("RGB", (32, 32))
info = PngImagePlugin.PngInfo()
info.add_itxt("spam", "Eggs", "en", "Spam")
2014-08-28 15:44:19 +04:00
info.add_text("eggs", PngImagePlugin.iTXt("Spam", "en", "Eggs"),
zip=True)
2014-07-23 18:27:51 +04:00
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"spam": "Eggs", "eggs": "Spam"})
self.assertEqual(im.text, {"spam": "Eggs", "eggs": "Spam"})
self.assertEqual(im.text["spam"].lang, "en")
self.assertEqual(im.text["spam"].tkey, "Spam")
self.assertEqual(im.text["eggs"].lang, "en")
self.assertEqual(im.text["eggs"].tkey, "Eggs")
def test_nonunicode_text(self):
# Check so that non-Unicode text is saved as a tEXt rather than iTXt
im = Image.new("RGB", (32, 32))
info = PngImagePlugin.PngInfo()
info.add_text("Text", "Ascii")
im = roundtrip(im, pnginfo=info)
self.assertIsInstance(im.info["Text"], str)
def test_unicode_text(self):
# Check preservation of non-ASCII characters on Python 3
# This cannot really be meaningfully tested on Python 2,
# since it didn't preserve charsets to begin with.
def rt_text(value):
im = Image.new("RGB", (32, 32))
info = PngImagePlugin.PngInfo()
info.add_text("Text", value)
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"Text": value})
if py3:
2014-08-28 15:44:19 +04:00
rt_text(" Aa" + chr(0xa0) + chr(0xc4) + chr(0xff)) # Latin1
rt_text(chr(0x400) + chr(0x472) + chr(0x4ff)) # Cyrillic
rt_text(chr(0x4e00) + chr(0x66f0) + # CJK
chr(0x9fba) + chr(0x3042) + chr(0xac00))
2014-08-28 15:44:19 +04:00
rt_text("A" + chr(0xc4) + chr(0x472) + chr(0x3042)) # Combined
2014-06-10 13:10:47 +04:00
def test_scary(self):
# Check reading of evil PNG file. For information, see:
# http://scary.beasts.org/security/CESA-2004-001.txt
# The first byte is removed from pngtest_bad.png
# to avoid classification as malware.
2014-06-10 13:10:47 +04:00
with open("Tests/images/pngtest_bad.png.bin", 'rb') as fd:
data = b'\x89' + fd.read()
2014-06-10 13:10:47 +04:00
pngfile = BytesIO(data)
2017-09-01 14:05:40 +03:00
self.assertRaises(IOError, Image.open, pngfile)
2014-06-10 13:10:47 +04:00
def test_trns_rgb(self):
# Check writing and reading of tRNS chunks for RGB images.
# Independent file sample provided by Sebastian Spaeth.
2015-04-24 11:24:52 +03:00
test_file = "Tests/images/caption_6_33_22.png"
im = Image.open(test_file)
2014-06-10 13:10:47 +04:00
self.assertEqual(im.info["transparency"], (248, 248, 248))
2014-06-10 13:10:47 +04:00
# check saving transparency by default
im = roundtrip(im)
self.assertEqual(im.info["transparency"], (248, 248, 248))
2014-06-10 13:10:47 +04:00
im = roundtrip(im, transparency=(0, 1, 2))
self.assertEqual(im.info["transparency"], (0, 1, 2))
2014-06-10 13:10:47 +04:00
def test_trns_p(self):
# Check writing a transparency of 0, issue #528
2014-09-04 13:09:52 +04:00
im = hopper('P')
2014-06-10 13:10:47 +04:00
im.info['transparency'] = 0
2014-06-10 13:10:47 +04:00
f = self.tempfile("temp.png")
im.save(f)
2014-06-10 13:10:47 +04:00
im2 = Image.open(f)
self.assertIn('transparency', im2.info)
2014-03-01 04:29:34 +04:00
self.assert_image_equal(im2.convert('RGBA'),
im.convert('RGBA'))
2014-03-01 04:29:34 +04:00
def test_trns_null(self):
# Check reading images with null tRNS value, issue #1239
test_file = "Tests/images/tRNS_null_1x1.png"
im = Image.open(test_file)
self.assertEqual(im.info["transparency"], 0)
2016-05-12 20:28:58 +03:00
def test_save_icc_profile(self):
im = Image.open("Tests/images/icc_profile_none.png")
self.assertIsNone(im.info['icc_profile'])
2016-05-12 20:28:58 +03:00
with_icc = Image.open("Tests/images/icc_profile.png")
expected_icc = with_icc.info['icc_profile']
im = roundtrip(im, icc_profile=expected_icc)
self.assertEqual(im.info['icc_profile'], expected_icc)
def test_discard_icc_profile(self):
im = Image.open('Tests/images/icc_profile.png')
im = roundtrip(im, icc_profile=None)
2014-06-10 13:10:47 +04:00
self.assertNotIn('icc_profile', im.info)
2014-06-10 13:10:47 +04:00
def test_roundtrip_icc_profile(self):
2016-05-12 20:28:58 +03:00
im = Image.open('Tests/images/icc_profile.png')
expected_icc = im.info['icc_profile']
2014-06-10 13:10:47 +04:00
im = roundtrip(im)
self.assertEqual(im.info['icc_profile'], expected_icc)
2016-05-12 20:28:58 +03:00
def test_roundtrip_no_icc_profile(self):
im = Image.open("Tests/images/icc_profile_none.png")
self.assertIsNone(im.info['icc_profile'])
2016-05-12 20:28:58 +03:00
im = roundtrip(im)
self.assertNotIn('icc_profile', im.info)
def test_repr_png(self):
im = hopper()
2015-01-28 21:02:04 +03:00
repr_png = Image.open(BytesIO(im._repr_png_()))
self.assertEqual(repr_png.format, 'PNG')
self.assert_image_equal(im, repr_png)
def test_chunk_order(self):
im = Image.open("Tests/images/icc_profile.png")
test_file = self.tempfile("temp.png")
im.convert("P").save(test_file, dpi=(100, 100))
2017-12-20 13:27:13 +03:00
chunks = self.get_chunks(test_file)
# https://www.w3.org/TR/PNG/#5ChunkOrdering
# IHDR - shall be first
self.assertEqual(chunks.index(b"IHDR"), 0)
# PLTE - before first IDAT
self.assertLess(chunks.index(b"PLTE"), chunks.index(b"IDAT"))
# iCCP - before PLTE and IDAT
self.assertLess(chunks.index(b"iCCP"), chunks.index(b"PLTE"))
self.assertLess(chunks.index(b"iCCP"), chunks.index(b"IDAT"))
# tRNS - after PLTE, before IDAT
self.assertGreater(chunks.index(b"tRNS"), chunks.index(b"PLTE"))
self.assertLess(chunks.index(b"tRNS"), chunks.index(b"IDAT"))
# pHYs - before IDAT
self.assertLess(chunks.index(b"pHYs"), chunks.index(b"IDAT"))
2017-09-01 13:36:51 +03:00
def test_getchunks(self):
im = hopper()
chunks = PngImagePlugin.getchunks(im)
self.assertEqual(len(chunks), 3)
def test_textual_chunks_after_idat(self):
im = Image.open("Tests/images/hopper.png")
self.assertIn('comment', im.text.keys())
for k, v in {
'date:create': '2014-09-04T09:37:08+03:00',
'date:modify': '2014-09-04T09:37:08+03:00',
}.items():
self.assertEqual(im.text[k], v)
# Raises a SyntaxError in load_end
im = Image.open("Tests/images/broken_data_stream.png")
with self.assertRaises(IOError):
self.assertIsInstance(im.text, dict)
# Raises a UnicodeDecodeError in load_end
im = Image.open("Tests/images/truncated_image.png")
# The file is truncated
self.assertRaises(IOError, lambda: im.text)
ImageFile.LOAD_TRUNCATED_IMAGES = True
self.assertIsInstance(im.text, dict)
ImageFile.LOAD_TRUNCATED_IMAGES = False
2019-01-03 11:13:19 +03:00
# Raises an EOFError in load_end
im = Image.open("Tests/images/hopper_idat_after_image_end.png")
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
2019-02-23 05:30:38 +03:00
def test_exif(self):
im = Image.open("Tests/images/exif.png")
exif = im._getexif()
self.assertEqual(exif[274], 1)
def test_exif_save(self):
im = Image.open("Tests/images/exif.png")
test_file = self.tempfile("temp.png")
im.save(test_file)
reloaded = Image.open(test_file)
exif = reloaded._getexif()
self.assertEqual(exif[274], 1)
def test_exif_from_jpg(self):
2019-02-23 05:30:38 +03:00
im = Image.open("Tests/images/pil_sample_rgb.jpg")
test_file = self.tempfile("temp.png")
im.save(test_file)
reloaded = Image.open(test_file)
exif = reloaded._getexif()
self.assertEqual(exif[305], "Adobe Photoshop CS Macintosh")
def test_exif_argument(self):
im = Image.open(TEST_PNG_FILE)
test_file = self.tempfile("temp.png")
im.save(test_file, exif=b"exifstring")
reloaded = Image.open(test_file)
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
2018-12-27 04:19:44 +03:00
@unittest.skipUnless(HAVE_WEBP and _webp.HAVE_WEBPANIM,
"WebP support not installed with animation")
def test_apng(self):
im = Image.open("Tests/images/iss634.apng")
self.assertEqual(im.get_format_mimetype(), 'image/apng')
# This also tests reading unknown PNG chunks (fcTL and fdAT) in load_end
2018-12-27 04:19:44 +03:00
expected = Image.open("Tests/images/iss634.webp")
self.assert_image_similar(im, expected, 0.23)
2014-01-22 08:50:54 +04:00
2018-03-19 11:36:07 +03:00
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
class TestTruncatedPngPLeaks(PillowLeakTestCase):
mem_limit = 2*1024 # max increase in K
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs
def setUp(self):
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
def test_leak_load(self):
with open('Tests/images/hopper.png', 'rb') as f:
DATA = BytesIO(f.read(16 * 1024))
ImageFile.LOAD_TRUNCATED_IMAGES = True
with Image.open(DATA) as im:
im.load()
def core():
with Image.open(DATA) as im:
im.load()
try:
self._test_leak(core)
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False