mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 18:56:17 +03:00
commit
f5cd8b4b0d
|
@ -4,5 +4,5 @@ from PIL import Image
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
if sys.maxsize < 2**32:
|
if sys.maxsize < 2 ** 32:
|
||||||
im = Image.new('L', (999999, 999999), 0)
|
im = Image.new("L", (999999, 999999), 0)
|
||||||
|
|
|
@ -26,18 +26,21 @@ def timer(func, label, *args):
|
||||||
starttime = time.time()
|
starttime = time.time()
|
||||||
for x in range(iterations):
|
for x in range(iterations):
|
||||||
func(*args)
|
func(*args)
|
||||||
if time.time()-starttime > 10:
|
if time.time() - starttime > 10:
|
||||||
print("%s: breaking at %s iterations, %.6f per iteration" % (
|
print(
|
||||||
label, x+1, (time.time()-starttime)/(x+1.0)))
|
"%s: breaking at %s iterations, %.6f per iteration"
|
||||||
|
% (label, x + 1, (time.time() - starttime) / (x + 1.0))
|
||||||
|
)
|
||||||
break
|
break
|
||||||
if x == iterations-1:
|
if x == iterations - 1:
|
||||||
endtime = time.time()
|
endtime = time.time()
|
||||||
print("%s: %.4f s %.6f per iteration" % (
|
print(
|
||||||
label, endtime-starttime, (endtime-starttime)/(x+1.0)))
|
"%s: %.4f s %.6f per iteration"
|
||||||
|
% (label, endtime - starttime, (endtime - starttime) / (x + 1.0))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BenchCffiAccess(PillowTestCase):
|
class BenchCffiAccess(PillowTestCase):
|
||||||
|
|
||||||
def test_direct(self):
|
def test_direct(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -48,11 +51,11 @@ class BenchCffiAccess(PillowTestCase):
|
||||||
self.assertEqual(caccess[(0, 0)], access[(0, 0)])
|
self.assertEqual(caccess[(0, 0)], access[(0, 0)])
|
||||||
|
|
||||||
print("Size: %sx%s" % im.size)
|
print("Size: %sx%s" % im.size)
|
||||||
timer(iterate_get, 'PyAccess - get', im.size, access)
|
timer(iterate_get, "PyAccess - get", im.size, access)
|
||||||
timer(iterate_set, 'PyAccess - set', im.size, access)
|
timer(iterate_set, "PyAccess - set", im.size, access)
|
||||||
timer(iterate_get, 'C-api - get', im.size, caccess)
|
timer(iterate_get, "C-api - get", im.size, caccess)
|
||||||
timer(iterate_set, 'C-api - set', im.size, caccess)
|
timer(iterate_set, "C-api - set", im.size, caccess)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -2,6 +2,7 @@ from . import helper
|
||||||
import timeit
|
import timeit
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, ".")
|
sys.path.insert(0, ".")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,5 +12,5 @@ class TestFliOverflow(PillowTestCase):
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -6,7 +6,6 @@ from PIL._util import py3
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
if py3:
|
if py3:
|
||||||
Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00',
|
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00", "latin-1")))
|
||||||
'latin-1')))
|
|
||||||
else:
|
else:
|
||||||
Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00')))
|
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00")))
|
||||||
|
|
|
@ -9,11 +9,11 @@ min_iterations = 100
|
||||||
max_iterations = 10000
|
max_iterations = 10000
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
class TestImagingLeaks(PillowTestCase):
|
class TestImagingLeaks(PillowTestCase):
|
||||||
|
|
||||||
def _get_mem_usage(self):
|
def _get_mem_usage(self):
|
||||||
from resource import getpagesize, getrusage, RUSAGE_SELF
|
from resource import getpagesize, getrusage, RUSAGE_SELF
|
||||||
|
|
||||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||||
return mem * getpagesize() / 1024 / 1024
|
return mem * getpagesize() / 1024 / 1024
|
||||||
|
|
||||||
|
@ -25,20 +25,22 @@ class TestImagingLeaks(PillowTestCase):
|
||||||
if i < min_iterations:
|
if i < min_iterations:
|
||||||
mem_limit = mem + 1
|
mem_limit = mem + 1
|
||||||
continue
|
continue
|
||||||
msg = 'memory usage limit exceeded after %d iterations' % (i + 1)
|
msg = "memory usage limit exceeded after %d iterations" % (i + 1)
|
||||||
self.assertLessEqual(mem, mem_limit, msg)
|
self.assertLessEqual(mem, mem_limit, msg)
|
||||||
|
|
||||||
def test_leak_putdata(self):
|
def test_leak_putdata(self):
|
||||||
im = Image.new('RGB', (25, 25))
|
im = Image.new("RGB", (25, 25))
|
||||||
self._test_leak(min_iterations, max_iterations,
|
self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
|
||||||
im.putdata, im.getdata())
|
|
||||||
|
|
||||||
def test_leak_getlist(self):
|
def test_leak_getlist(self):
|
||||||
im = Image.new('P', (25, 25))
|
im = Image.new("P", (25, 25))
|
||||||
self._test_leak(min_iterations, max_iterations,
|
self._test_leak(
|
||||||
# Pass a new list at each iteration.
|
min_iterations,
|
||||||
lambda: im.point(range(256)))
|
max_iterations,
|
||||||
|
# Pass a new list at each iteration.
|
||||||
|
lambda: im.point(range(256)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -6,10 +6,16 @@ from PIL._util import py3
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
if py3:
|
if py3:
|
||||||
Image.open(BytesIO(bytes(
|
Image.open(
|
||||||
'\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang',
|
BytesIO(
|
||||||
'latin-1')))
|
bytes(
|
||||||
|
"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang",
|
||||||
|
"latin-1",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
Image.open(BytesIO(bytes(
|
Image.open(
|
||||||
'\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang')))
|
BytesIO(bytes("\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang"))
|
||||||
|
)
|
||||||
|
|
|
@ -4,21 +4,22 @@ from PIL import Image
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
# Limits for testing the leak
|
# Limits for testing the leak
|
||||||
mem_limit = 1024*1048576
|
mem_limit = 1024 * 1048576
|
||||||
stack_size = 8*1048576
|
stack_size = 8 * 1048576
|
||||||
iterations = int((mem_limit/stack_size)*2)
|
iterations = int((mem_limit / stack_size) * 2)
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
test_file = "Tests/images/rgb_trns_ycbc.jp2"
|
test_file = "Tests/images/rgb_trns_ycbc.jp2"
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
class TestJpegLeaks(PillowTestCase):
|
class TestJpegLeaks(PillowTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
|
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
|
||||||
self.skipTest('JPEG 2000 support not available')
|
self.skipTest("JPEG 2000 support not available")
|
||||||
|
|
||||||
def test_leak_load(self):
|
def test_leak_load(self):
|
||||||
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||||
|
|
||||||
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||||
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||||
for _ in range(iterations):
|
for _ in range(iterations):
|
||||||
|
@ -27,6 +28,7 @@ class TestJpegLeaks(PillowTestCase):
|
||||||
|
|
||||||
def test_leak_save(self):
|
def test_leak_save(self):
|
||||||
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||||
|
|
||||||
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||||
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||||
for _ in range(iterations):
|
for _ in range(iterations):
|
||||||
|
@ -38,5 +40,5 @@ class TestJpegLeaks(PillowTestCase):
|
||||||
test_output.read()
|
test_output.read()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -5,11 +5,11 @@ from .helper import unittest, PillowTestCase
|
||||||
class TestJ2kEncodeOverflow(PillowTestCase):
|
class TestJ2kEncodeOverflow(PillowTestCase):
|
||||||
def test_j2k_overflow(self):
|
def test_j2k_overflow(self):
|
||||||
|
|
||||||
im = Image.new('RGBA', (1024, 131584))
|
im = Image.new("RGBA", (1024, 131584))
|
||||||
target = self.tempfile('temp.jpc')
|
target = self.tempfile("temp.jpc")
|
||||||
with self.assertRaises(IOError):
|
with self.assertRaises(IOError):
|
||||||
im.save(target)
|
im.save(target)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -14,7 +14,7 @@ valgrind --tool=massif python test-installed.py -s -v Tests/check_jpeg_leaks.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
class TestJpegLeaks(PillowTestCase):
|
class TestJpegLeaks(PillowTestCase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -74,9 +74,11 @@ post-patch:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_qtables_leak(self):
|
def test_qtables_leak(self):
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
|
|
||||||
standard_l_qtable = [int(s) for s in """
|
standard_l_qtable = [
|
||||||
|
int(s)
|
||||||
|
for s in """
|
||||||
16 11 10 16 24 40 51 61
|
16 11 10 16 24 40 51 61
|
||||||
12 12 14 19 26 58 60 55
|
12 12 14 19 26 58 60 55
|
||||||
14 13 16 24 40 57 69 56
|
14 13 16 24 40 57 69 56
|
||||||
|
@ -85,9 +87,14 @@ post-patch:
|
||||||
24 35 55 64 81 104 113 92
|
24 35 55 64 81 104 113 92
|
||||||
49 64 78 87 103 121 120 101
|
49 64 78 87 103 121 120 101
|
||||||
72 92 95 98 112 100 103 99
|
72 92 95 98 112 100 103 99
|
||||||
""".split(None)]
|
""".split(
|
||||||
|
None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
standard_chrominance_qtable = [int(s) for s in """
|
standard_chrominance_qtable = [
|
||||||
|
int(s)
|
||||||
|
for s in """
|
||||||
17 18 24 47 99 99 99 99
|
17 18 24 47 99 99 99 99
|
||||||
18 21 26 66 99 99 99 99
|
18 21 26 66 99 99 99 99
|
||||||
24 26 56 99 99 99 99 99
|
24 26 56 99 99 99 99 99
|
||||||
|
@ -96,10 +103,12 @@ post-patch:
|
||||||
99 99 99 99 99 99 99 99
|
99 99 99 99 99 99 99 99
|
||||||
99 99 99 99 99 99 99 99
|
99 99 99 99 99 99 99 99
|
||||||
99 99 99 99 99 99 99 99
|
99 99 99 99 99 99 99 99
|
||||||
""".split(None)]
|
""".split(
|
||||||
|
None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
qtables = [standard_l_qtable,
|
qtables = [standard_l_qtable, standard_chrominance_qtable]
|
||||||
standard_chrominance_qtable]
|
|
||||||
|
|
||||||
for _ in range(iterations):
|
for _ in range(iterations):
|
||||||
test_output = BytesIO()
|
test_output = BytesIO()
|
||||||
|
@ -161,8 +170,8 @@ post patch:
|
||||||
0 11.33
|
0 11.33
|
||||||
|
|
||||||
"""
|
"""
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
exif = b'12345678'*4096
|
exif = b"12345678" * 4096
|
||||||
|
|
||||||
for _ in range(iterations):
|
for _ in range(iterations):
|
||||||
test_output = BytesIO()
|
test_output = BytesIO()
|
||||||
|
@ -195,12 +204,12 @@ base case:
|
||||||
0 +----------------------------------------------------------------------->Gi
|
0 +----------------------------------------------------------------------->Gi
|
||||||
0 7.882
|
0 7.882
|
||||||
"""
|
"""
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
|
|
||||||
for _ in range(iterations):
|
for _ in range(iterations):
|
||||||
test_output = BytesIO()
|
test_output = BytesIO()
|
||||||
im.save(test_output, "JPEG")
|
im.save(test_output, "JPEG")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -22,12 +22,11 @@ YDIM = 32769
|
||||||
XDIM = 48000
|
XDIM = 48000
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64-bit system")
|
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
||||||
class LargeMemoryTest(PillowTestCase):
|
class LargeMemoryTest(PillowTestCase):
|
||||||
|
|
||||||
def _write_png(self, xdim, ydim):
|
def _write_png(self, xdim, ydim):
|
||||||
f = self.tempfile('temp.png')
|
f = self.tempfile("temp.png")
|
||||||
im = Image.new('L', (xdim, ydim), 0)
|
im = Image.new("L", (xdim, ydim), 0)
|
||||||
im.save(f)
|
im.save(f)
|
||||||
|
|
||||||
def test_large(self):
|
def test_large(self):
|
||||||
|
@ -44,5 +43,5 @@ class LargeMemoryTest(PillowTestCase):
|
||||||
Image.fromarray(arr)
|
Image.fromarray(arr)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -11,6 +11,7 @@ from .helper import unittest, PillowTestCase
|
||||||
# Raspberry Pis).
|
# Raspberry Pis).
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpy as np
|
import numpy as np
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -20,14 +21,13 @@ YDIM = 32769
|
||||||
XDIM = 48000
|
XDIM = 48000
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64-bit system")
|
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
||||||
class LargeMemoryNumpyTest(PillowTestCase):
|
class LargeMemoryNumpyTest(PillowTestCase):
|
||||||
|
|
||||||
def _write_png(self, xdim, ydim):
|
def _write_png(self, xdim, ydim):
|
||||||
dtype = np.uint8
|
dtype = np.uint8
|
||||||
a = np.zeros((xdim, ydim), dtype=dtype)
|
a = np.zeros((xdim, ydim), dtype=dtype)
|
||||||
f = self.tempfile('temp.png')
|
f = self.tempfile("temp.png")
|
||||||
im = Image.fromarray(a, 'L')
|
im = Image.fromarray(a, "L")
|
||||||
im.save(f)
|
im.save(f)
|
||||||
|
|
||||||
def test_large(self):
|
def test_large(self):
|
||||||
|
@ -39,5 +39,5 @@ class LargeMemoryNumpyTest(PillowTestCase):
|
||||||
self._write_png(XDIM, XDIM)
|
self._write_png(XDIM, XDIM)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -15,5 +15,5 @@ class TestLibtiffSegfault(PillowTestCase):
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -17,10 +17,10 @@ class TestPngDos(PillowTestCase):
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||||
|
|
||||||
for s in im.text.values():
|
for s in im.text.values():
|
||||||
self.assertLess(len(s), 1024*1024, "Text chunk larger than 1M")
|
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||||
|
|
||||||
for s in im.info.values():
|
for s in im.info.values():
|
||||||
self.assertLess(len(s), 1024*1024, "Text chunk larger than 1M")
|
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||||
|
|
||||||
def test_dos_text(self):
|
def test_dos_text(self):
|
||||||
|
|
||||||
|
@ -32,20 +32,20 @@ class TestPngDos(PillowTestCase):
|
||||||
return
|
return
|
||||||
|
|
||||||
for s in im.text.values():
|
for s in im.text.values():
|
||||||
self.assertLess(len(s), 1024*1024, "Text chunk larger than 1M")
|
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||||
|
|
||||||
def test_dos_total_memory(self):
|
def test_dos_total_memory(self):
|
||||||
im = Image.new('L', (1, 1))
|
im = Image.new("L", (1, 1))
|
||||||
compressed_data = zlib.compress(b'a'*1024*1023)
|
compressed_data = zlib.compress(b"a" * 1024 * 1023)
|
||||||
|
|
||||||
info = PngImagePlugin.PngInfo()
|
info = PngImagePlugin.PngInfo()
|
||||||
|
|
||||||
for x in range(64):
|
for x in range(64):
|
||||||
info.add_text('t%s' % x, compressed_data, zip=True)
|
info.add_text("t%s" % x, compressed_data, zip=True)
|
||||||
info.add_itxt('i%s' % x, compressed_data, zip=True)
|
info.add_itxt("i%s" % x, compressed_data, zip=True)
|
||||||
|
|
||||||
b = BytesIO()
|
b = BytesIO()
|
||||||
im.save(b, 'PNG', pnginfo=info)
|
im.save(b, "PNG", pnginfo=info)
|
||||||
b.seek(0)
|
b.seek(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -57,9 +57,10 @@ class TestPngDos(PillowTestCase):
|
||||||
total_len = 0
|
total_len = 0
|
||||||
for txt in im2.text.values():
|
for txt in im2.text.values():
|
||||||
total_len += len(txt)
|
total_len += len(txt)
|
||||||
self.assertLess(total_len, 64*1024*1024,
|
self.assertLess(
|
||||||
"Total text chunks greater than 64M")
|
total_len, 64 * 1024 * 1024, "Total text chunks greater than 64M"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
136
Tests/helper.py
136
Tests/helper.py
|
@ -11,12 +11,13 @@ from PIL import Image, ImageMath
|
||||||
from PIL._util import py3
|
from PIL._util import py3
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
HAS_UPLOADER = False
|
HAS_UPLOADER = False
|
||||||
|
|
||||||
if os.environ.get('SHOW_ERRORS', None):
|
if os.environ.get("SHOW_ERRORS", None):
|
||||||
# local img.show for errors.
|
# local img.show for errors.
|
||||||
HAS_UPLOADER = True
|
HAS_UPLOADER = True
|
||||||
|
|
||||||
|
@ -25,9 +26,12 @@ if os.environ.get('SHOW_ERRORS', None):
|
||||||
def upload(self, a, b):
|
def upload(self, a, b):
|
||||||
a.show()
|
a.show()
|
||||||
b.show()
|
b.show()
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
import test_image_results
|
import test_image_results
|
||||||
|
|
||||||
HAS_UPLOADER = True
|
HAS_UPLOADER = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
@ -35,19 +39,18 @@ else:
|
||||||
|
|
||||||
def convert_to_comparable(a, b):
|
def convert_to_comparable(a, b):
|
||||||
new_a, new_b = a, b
|
new_a, new_b = a, b
|
||||||
if a.mode == 'P':
|
if a.mode == "P":
|
||||||
new_a = Image.new('L', a.size)
|
new_a = Image.new("L", a.size)
|
||||||
new_b = Image.new('L', b.size)
|
new_b = Image.new("L", b.size)
|
||||||
new_a.putdata(a.getdata())
|
new_a.putdata(a.getdata())
|
||||||
new_b.putdata(b.getdata())
|
new_b.putdata(b.getdata())
|
||||||
elif a.mode == 'I;16':
|
elif a.mode == "I;16":
|
||||||
new_a = a.convert('I')
|
new_a = a.convert("I")
|
||||||
new_b = b.convert('I')
|
new_b = b.convert("I")
|
||||||
return new_a, new_b
|
return new_a, new_b
|
||||||
|
|
||||||
|
|
||||||
class PillowTestCase(unittest.TestCase):
|
class PillowTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
unittest.TestCase.__init__(self, *args, **kwargs)
|
unittest.TestCase.__init__(self, *args, **kwargs)
|
||||||
# holds last result object passed to run method:
|
# holds last result object passed to run method:
|
||||||
|
@ -75,32 +78,32 @@ class PillowTestCase(unittest.TestCase):
|
||||||
def assert_deep_equal(self, a, b, msg=None):
|
def assert_deep_equal(self, a, b, msg=None):
|
||||||
try:
|
try:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(a), len(b),
|
len(a), len(b), msg or "got length %s, expected %s" % (len(a), len(b))
|
||||||
msg or "got length %s, expected %s" % (len(a), len(b)))
|
)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
all(x == y for x, y in zip(a, b)),
|
all(x == y for x, y in zip(a, b)), msg or "got %s, expected %s" % (a, b)
|
||||||
msg or "got %s, expected %s" % (a, b))
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.assertEqual(a, b, msg)
|
self.assertEqual(a, b, msg)
|
||||||
|
|
||||||
def assert_image(self, im, mode, size, msg=None):
|
def assert_image(self, im, mode, size, msg=None):
|
||||||
if mode is not None:
|
if mode is not None:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.mode, mode,
|
im.mode, mode, msg or "got mode %r, expected %r" % (im.mode, mode)
|
||||||
msg or "got mode %r, expected %r" % (im.mode, mode))
|
)
|
||||||
|
|
||||||
if size is not None:
|
if size is not None:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.size, size,
|
im.size, size, msg or "got size %r, expected %r" % (im.size, size)
|
||||||
msg or "got size %r, expected %r" % (im.size, size))
|
)
|
||||||
|
|
||||||
def assert_image_equal(self, a, b, msg=None):
|
def assert_image_equal(self, a, b, msg=None):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.mode, b.mode,
|
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
|
||||||
msg or "got mode %r, expected %r" % (a.mode, b.mode))
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.size, b.size,
|
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
|
||||||
msg or "got size %r, expected %r" % (a.size, b.size))
|
)
|
||||||
if a.tobytes() != b.tobytes():
|
if a.tobytes() != b.tobytes():
|
||||||
if HAS_UPLOADER:
|
if HAS_UPLOADER:
|
||||||
try:
|
try:
|
||||||
|
@ -120,26 +123,28 @@ class PillowTestCase(unittest.TestCase):
|
||||||
def assert_image_similar(self, a, b, epsilon, msg=None):
|
def assert_image_similar(self, a, b, epsilon, msg=None):
|
||||||
epsilon = float(epsilon)
|
epsilon = float(epsilon)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.mode, b.mode,
|
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
|
||||||
msg or "got mode %r, expected %r" % (a.mode, b.mode))
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.size, b.size,
|
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
|
||||||
msg or "got size %r, expected %r" % (a.size, b.size))
|
)
|
||||||
|
|
||||||
a, b = convert_to_comparable(a, b)
|
a, b = convert_to_comparable(a, b)
|
||||||
|
|
||||||
diff = 0
|
diff = 0
|
||||||
for ach, bch in zip(a.split(), b.split()):
|
for ach, bch in zip(a.split(), b.split()):
|
||||||
chdiff = ImageMath.eval("abs(a - b)", a=ach, b=bch).convert('L')
|
chdiff = ImageMath.eval("abs(a - b)", a=ach, b=bch).convert("L")
|
||||||
diff += sum(i * num for i, num in enumerate(chdiff.histogram()))
|
diff += sum(i * num for i, num in enumerate(chdiff.histogram()))
|
||||||
|
|
||||||
ave_diff = float(diff)/(a.size[0]*a.size[1])
|
ave_diff = float(diff) / (a.size[0] * a.size[1])
|
||||||
try:
|
try:
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
epsilon, ave_diff,
|
epsilon,
|
||||||
(msg or '') +
|
ave_diff,
|
||||||
" average pixel value difference %.4f > epsilon %.4f" % (
|
(msg or "")
|
||||||
ave_diff, epsilon))
|
+ " average pixel value difference %.4f > epsilon %.4f"
|
||||||
|
% (ave_diff, epsilon),
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if HAS_UPLOADER:
|
if HAS_UPLOADER:
|
||||||
try:
|
try:
|
||||||
|
@ -149,8 +154,7 @@ class PillowTestCase(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None,
|
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, mode=None):
|
||||||
mode=None):
|
|
||||||
with Image.open(filename) as img:
|
with Image.open(filename) as img:
|
||||||
if mode:
|
if mode:
|
||||||
img = img.convert(mode)
|
img = img.convert(mode)
|
||||||
|
@ -168,9 +172,9 @@ class PillowTestCase(unittest.TestCase):
|
||||||
|
|
||||||
# Verify some things.
|
# Verify some things.
|
||||||
if warn_class is None:
|
if warn_class is None:
|
||||||
self.assertEqual(len(w), 0,
|
self.assertEqual(
|
||||||
"Expected no warnings, got %s" %
|
len(w), 0, "Expected no warnings, got %s" % [v.category for v in w]
|
||||||
[v.category for v in w])
|
)
|
||||||
else:
|
else:
|
||||||
self.assertGreaterEqual(len(w), 1)
|
self.assertGreaterEqual(len(w), 1)
|
||||||
found = False
|
found = False
|
||||||
|
@ -192,27 +196,26 @@ class PillowTestCase(unittest.TestCase):
|
||||||
|
|
||||||
value = True
|
value = True
|
||||||
for i, target in enumerate(targets):
|
for i, target in enumerate(targets):
|
||||||
value *= (target - threshold <= actuals[i] <= target + threshold)
|
value *= target - threshold <= actuals[i] <= target + threshold
|
||||||
|
|
||||||
self.assertTrue(value,
|
self.assertTrue(value, msg + ": " + repr(actuals) + " != " + repr(targets))
|
||||||
msg + ': ' + repr(actuals) + ' != ' + repr(targets))
|
|
||||||
|
|
||||||
def skipKnownBadTest(self, msg=None, platform=None,
|
def skipKnownBadTest(self, msg=None, platform=None, travis=None, interpreter=None):
|
||||||
travis=None, interpreter=None):
|
|
||||||
# Skip if platform/travis matches, and
|
# Skip if platform/travis matches, and
|
||||||
# PILLOW_RUN_KNOWN_BAD is not true in the environment.
|
# PILLOW_RUN_KNOWN_BAD is not true in the environment.
|
||||||
if os.environ.get('PILLOW_RUN_KNOWN_BAD', False):
|
if os.environ.get("PILLOW_RUN_KNOWN_BAD", False):
|
||||||
print(os.environ.get('PILLOW_RUN_KNOWN_BAD', False))
|
print(os.environ.get("PILLOW_RUN_KNOWN_BAD", False))
|
||||||
return
|
return
|
||||||
|
|
||||||
skip = True
|
skip = True
|
||||||
if platform is not None:
|
if platform is not None:
|
||||||
skip = sys.platform.startswith(platform)
|
skip = sys.platform.startswith(platform)
|
||||||
if travis is not None:
|
if travis is not None:
|
||||||
skip = skip and (travis == bool(os.environ.get('TRAVIS', False)))
|
skip = skip and (travis == bool(os.environ.get("TRAVIS", False)))
|
||||||
if interpreter is not None:
|
if interpreter is not None:
|
||||||
skip = skip and (interpreter == 'pypy' and
|
skip = skip and (
|
||||||
hasattr(sys, 'pypy_version_info'))
|
interpreter == "pypy" and hasattr(sys, "pypy_version_info")
|
||||||
|
)
|
||||||
if skip:
|
if skip:
|
||||||
self.skipTest(msg or "Known Bad Test")
|
self.skipTest(msg or "Known Bad Test")
|
||||||
|
|
||||||
|
@ -234,7 +237,7 @@ class PillowTestCase(unittest.TestCase):
|
||||||
raise IOError()
|
raise IOError()
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
class PillowLeakTestCase(PillowTestCase):
|
class PillowLeakTestCase(PillowTestCase):
|
||||||
# requires unix/macOS
|
# requires unix/macOS
|
||||||
iterations = 100 # count
|
iterations = 100 # count
|
||||||
|
@ -249,8 +252,9 @@ class PillowLeakTestCase(PillowTestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from resource import getrusage, RUSAGE_SELF
|
from resource import getrusage, RUSAGE_SELF
|
||||||
|
|
||||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == "darwin":
|
||||||
# man 2 getrusage:
|
# man 2 getrusage:
|
||||||
# ru_maxrss
|
# ru_maxrss
|
||||||
# This is the maximum resident set size utilized (in bytes).
|
# This is the maximum resident set size utilized (in bytes).
|
||||||
|
@ -266,8 +270,8 @@ class PillowLeakTestCase(PillowTestCase):
|
||||||
start_mem = self._get_mem_usage()
|
start_mem = self._get_mem_usage()
|
||||||
for cycle in range(self.iterations):
|
for cycle in range(self.iterations):
|
||||||
core()
|
core()
|
||||||
mem = (self._get_mem_usage() - start_mem)
|
mem = self._get_mem_usage() - start_mem
|
||||||
msg = 'memory usage limit exceeded in iteration %d' % cycle
|
msg = "memory usage limit exceeded in iteration %d" % cycle
|
||||||
self.assertLess(mem, self.mem_limit, msg)
|
self.assertLess(mem, self.mem_limit, msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -281,11 +285,13 @@ if not py3:
|
||||||
|
|
||||||
def fromstring(data):
|
def fromstring(data):
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
return Image.open(BytesIO(data))
|
return Image.open(BytesIO(data))
|
||||||
|
|
||||||
|
|
||||||
def tostring(im, string_format, **options):
|
def tostring(im, string_format, **options):
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
im.save(out, string_format, **options)
|
im.save(out, string_format, **options)
|
||||||
return out.getvalue()
|
return out.getvalue()
|
||||||
|
@ -318,7 +324,8 @@ def command_succeeds(cmd):
|
||||||
command succeeds, or False if an OSError was raised by subprocess.Popen.
|
command succeeds, or False if an OSError was raised by subprocess.Popen.
|
||||||
"""
|
"""
|
||||||
import subprocess
|
import subprocess
|
||||||
with open(os.devnull, 'wb') as f:
|
|
||||||
|
with open(os.devnull, "wb") as f:
|
||||||
try:
|
try:
|
||||||
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)
|
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -327,40 +334,41 @@ def command_succeeds(cmd):
|
||||||
|
|
||||||
|
|
||||||
def djpeg_available():
|
def djpeg_available():
|
||||||
return command_succeeds(['djpeg', '-version'])
|
return command_succeeds(["djpeg", "-version"])
|
||||||
|
|
||||||
|
|
||||||
def cjpeg_available():
|
def cjpeg_available():
|
||||||
return command_succeeds(['cjpeg', '-version'])
|
return command_succeeds(["cjpeg", "-version"])
|
||||||
|
|
||||||
|
|
||||||
def netpbm_available():
|
def netpbm_available():
|
||||||
return (command_succeeds(["ppmquant", "--version"]) and
|
return command_succeeds(["ppmquant", "--version"]) and command_succeeds(
|
||||||
command_succeeds(["ppmtogif", "--version"]))
|
["ppmtogif", "--version"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def imagemagick_available():
|
def imagemagick_available():
|
||||||
return IMCONVERT and command_succeeds([IMCONVERT, '-version'])
|
return IMCONVERT and command_succeeds([IMCONVERT, "-version"])
|
||||||
|
|
||||||
|
|
||||||
def on_appveyor():
|
def on_appveyor():
|
||||||
return 'APPVEYOR' in os.environ
|
return "APPVEYOR" in os.environ
|
||||||
|
|
||||||
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == "win32":
|
||||||
IMCONVERT = os.environ.get('MAGICK_HOME', '')
|
IMCONVERT = os.environ.get("MAGICK_HOME", "")
|
||||||
if IMCONVERT:
|
if IMCONVERT:
|
||||||
IMCONVERT = os.path.join(IMCONVERT, 'convert.exe')
|
IMCONVERT = os.path.join(IMCONVERT, "convert.exe")
|
||||||
else:
|
else:
|
||||||
IMCONVERT = 'convert'
|
IMCONVERT = "convert"
|
||||||
|
|
||||||
|
|
||||||
def distro():
|
def distro():
|
||||||
if os.path.exists('/etc/os-release'):
|
if os.path.exists("/etc/os-release"):
|
||||||
with open('/etc/os-release', 'r') as f:
|
with open("/etc/os-release", "r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
if 'ID=' in line:
|
if "ID=" in line:
|
||||||
return line.strip().split('=')[1]
|
return line.strip().split("=")[1]
|
||||||
|
|
||||||
|
|
||||||
class cached_property(object):
|
class cached_property(object):
|
||||||
|
|
|
@ -5,6 +5,7 @@ import os
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, ".")
|
sys.path.insert(0, ".")
|
||||||
|
|
||||||
for file in glob.glob("src/PIL/*.py"):
|
for file in glob.glob("src/PIL/*.py"):
|
||||||
|
|
|
@ -4,21 +4,33 @@ from __future__ import print_function
|
||||||
|
|
||||||
modes = [
|
modes = [
|
||||||
"1",
|
"1",
|
||||||
"L", "LA", "La",
|
"L",
|
||||||
"I", "I;16", "I;16L", "I;16B", "I;32L", "I;32B",
|
"LA",
|
||||||
|
"La",
|
||||||
|
"I",
|
||||||
|
"I;16",
|
||||||
|
"I;16L",
|
||||||
|
"I;16B",
|
||||||
|
"I;32L",
|
||||||
|
"I;32B",
|
||||||
"F",
|
"F",
|
||||||
"P", "PA",
|
"P",
|
||||||
"RGB", "RGBA", "RGBa", "RGBX",
|
"PA",
|
||||||
|
"RGB",
|
||||||
|
"RGBA",
|
||||||
|
"RGBa",
|
||||||
|
"RGBX",
|
||||||
"CMYK",
|
"CMYK",
|
||||||
"YCbCr",
|
"YCbCr",
|
||||||
"LAB", "HSV",
|
"LAB",
|
||||||
]
|
"HSV",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def hash(s, i):
|
def hash(s, i):
|
||||||
# djb2 hash: multiply by 33 and xor character
|
# djb2 hash: multiply by 33 and xor character
|
||||||
for c in s:
|
for c in s:
|
||||||
i = (((i << 5) + i) ^ ord(c)) & 0xffffffff
|
i = (((i << 5) + i) ^ ord(c)) & 0xFFFFFFFF
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import PIL.Image
|
||||||
|
|
||||||
|
|
||||||
class TestSanity(PillowTestCase):
|
class TestSanity(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
# Make sure we have the binary extension
|
# Make sure we have the binary extension
|
||||||
|
@ -13,7 +12,7 @@ class TestSanity(PillowTestCase):
|
||||||
|
|
||||||
# Create an image and do stuff with it.
|
# Create an image and do stuff with it.
|
||||||
im = PIL.Image.new("1", (100, 100))
|
im = PIL.Image.new("1", (100, 100))
|
||||||
self.assertEqual((im.mode, im.size), ('1', (100, 100)))
|
self.assertEqual((im.mode, im.size), ("1", (100, 100)))
|
||||||
self.assertEqual(len(im.tobytes()), 1300)
|
self.assertEqual(len(im.tobytes()), 1300)
|
||||||
|
|
||||||
# Create images in all remaining major modes.
|
# Create images in all remaining major modes.
|
||||||
|
|
|
@ -4,21 +4,20 @@ from PIL import _binary
|
||||||
|
|
||||||
|
|
||||||
class TestBinary(PillowTestCase):
|
class TestBinary(PillowTestCase):
|
||||||
|
|
||||||
def test_standard(self):
|
def test_standard(self):
|
||||||
self.assertEqual(_binary.i8(b'*'), 42)
|
self.assertEqual(_binary.i8(b"*"), 42)
|
||||||
self.assertEqual(_binary.o8(42), b'*')
|
self.assertEqual(_binary.o8(42), b"*")
|
||||||
|
|
||||||
def test_little_endian(self):
|
def test_little_endian(self):
|
||||||
self.assertEqual(_binary.i16le(b'\xff\xff\x00\x00'), 65535)
|
self.assertEqual(_binary.i16le(b"\xff\xff\x00\x00"), 65535)
|
||||||
self.assertEqual(_binary.i32le(b'\xff\xff\x00\x00'), 65535)
|
self.assertEqual(_binary.i32le(b"\xff\xff\x00\x00"), 65535)
|
||||||
|
|
||||||
self.assertEqual(_binary.o16le(65535), b'\xff\xff')
|
self.assertEqual(_binary.o16le(65535), b"\xff\xff")
|
||||||
self.assertEqual(_binary.o32le(65535), b'\xff\xff\x00\x00')
|
self.assertEqual(_binary.o32le(65535), b"\xff\xff\x00\x00")
|
||||||
|
|
||||||
def test_big_endian(self):
|
def test_big_endian(self):
|
||||||
self.assertEqual(_binary.i16be(b'\x00\x00\xff\xff'), 0)
|
self.assertEqual(_binary.i16be(b"\x00\x00\xff\xff"), 0)
|
||||||
self.assertEqual(_binary.i32be(b'\x00\x00\xff\xff'), 65535)
|
self.assertEqual(_binary.i32be(b"\x00\x00\xff\xff"), 65535)
|
||||||
|
|
||||||
self.assertEqual(_binary.o16be(65535), b'\xff\xff')
|
self.assertEqual(_binary.o16be(65535), b"\xff\xff")
|
||||||
self.assertEqual(_binary.o32be(65535), b'\x00\x00\xff\xff')
|
self.assertEqual(_binary.o32be(65535), b"\x00\x00\xff\xff")
|
||||||
|
|
|
@ -4,19 +4,22 @@ from .helper import PillowTestCase
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os
|
import os
|
||||||
|
|
||||||
base = os.path.join('Tests', 'images', 'bmp')
|
base = os.path.join("Tests", "images", "bmp")
|
||||||
|
|
||||||
|
|
||||||
class TestBmpReference(PillowTestCase):
|
class TestBmpReference(PillowTestCase):
|
||||||
|
def get_files(self, d, ext=".bmp"):
|
||||||
def get_files(self, d, ext='.bmp'):
|
return [
|
||||||
return [os.path.join(base, d, f) for f
|
os.path.join(base, d, f)
|
||||||
in os.listdir(os.path.join(base, d)) if ext in f]
|
for f in os.listdir(os.path.join(base, d))
|
||||||
|
if ext in f
|
||||||
|
]
|
||||||
|
|
||||||
def test_bad(self):
|
def test_bad(self):
|
||||||
""" These shouldn't crash/dos, but they shouldn't return anything
|
""" These shouldn't crash/dos, but they shouldn't return anything
|
||||||
either """
|
either """
|
||||||
for f in self.get_files('b'):
|
for f in self.get_files("b"):
|
||||||
|
|
||||||
def open(f):
|
def open(f):
|
||||||
try:
|
try:
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
|
@ -41,13 +44,12 @@ class TestBmpReference(PillowTestCase):
|
||||||
"pal8os2sp.bmp",
|
"pal8os2sp.bmp",
|
||||||
"rgb32bf-xbgr.bmp",
|
"rgb32bf-xbgr.bmp",
|
||||||
]
|
]
|
||||||
for f in self.get_files('q'):
|
for f in self.get_files("q"):
|
||||||
try:
|
try:
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
im.load()
|
im.load()
|
||||||
if os.path.basename(f) not in supported:
|
if os.path.basename(f) not in supported:
|
||||||
print("Please add %s to the partially supported"
|
print("Please add %s to the partially supported bmp specs." % f)
|
||||||
" bmp specs." % f)
|
|
||||||
except Exception: # as msg:
|
except Exception: # as msg:
|
||||||
if os.path.basename(f) in supported:
|
if os.path.basename(f) in supported:
|
||||||
raise
|
raise
|
||||||
|
@ -57,49 +59,52 @@ class TestBmpReference(PillowTestCase):
|
||||||
html directory that we can compare against. """
|
html directory that we can compare against. """
|
||||||
|
|
||||||
# Target files, if they're not just replacing the extension
|
# Target files, if they're not just replacing the extension
|
||||||
file_map = {'pal1wb.bmp': 'pal1.png',
|
file_map = {
|
||||||
'pal4rle.bmp': 'pal4.png',
|
"pal1wb.bmp": "pal1.png",
|
||||||
'pal8-0.bmp': 'pal8.png',
|
"pal4rle.bmp": "pal4.png",
|
||||||
'pal8rle.bmp': 'pal8.png',
|
"pal8-0.bmp": "pal8.png",
|
||||||
'pal8topdown.bmp': 'pal8.png',
|
"pal8rle.bmp": "pal8.png",
|
||||||
'pal8nonsquare.bmp': 'pal8nonsquare-v.png',
|
"pal8topdown.bmp": "pal8.png",
|
||||||
'pal8os2.bmp': 'pal8.png',
|
"pal8nonsquare.bmp": "pal8nonsquare-v.png",
|
||||||
'pal8os2sp.bmp': 'pal8.png',
|
"pal8os2.bmp": "pal8.png",
|
||||||
'pal8os2v2.bmp': 'pal8.png',
|
"pal8os2sp.bmp": "pal8.png",
|
||||||
'pal8os2v2-16.bmp': 'pal8.png',
|
"pal8os2v2.bmp": "pal8.png",
|
||||||
'pal8v4.bmp': 'pal8.png',
|
"pal8os2v2-16.bmp": "pal8.png",
|
||||||
'pal8v5.bmp': 'pal8.png',
|
"pal8v4.bmp": "pal8.png",
|
||||||
'rgb16-565pal.bmp': 'rgb16-565.png',
|
"pal8v5.bmp": "pal8.png",
|
||||||
'rgb24pal.bmp': 'rgb24.png',
|
"rgb16-565pal.bmp": "rgb16-565.png",
|
||||||
'rgb32.bmp': 'rgb24.png',
|
"rgb24pal.bmp": "rgb24.png",
|
||||||
'rgb32bf.bmp': 'rgb24.png'
|
"rgb32.bmp": "rgb24.png",
|
||||||
}
|
"rgb32bf.bmp": "rgb24.png",
|
||||||
|
}
|
||||||
|
|
||||||
def get_compare(f):
|
def get_compare(f):
|
||||||
name = os.path.split(f)[1]
|
name = os.path.split(f)[1]
|
||||||
if name in file_map:
|
if name in file_map:
|
||||||
return os.path.join(base, 'html', file_map[name])
|
return os.path.join(base, "html", file_map[name])
|
||||||
name = os.path.splitext(name)[0]
|
name = os.path.splitext(name)[0]
|
||||||
return os.path.join(base, 'html', "%s.png" % name)
|
return os.path.join(base, "html", "%s.png" % name)
|
||||||
|
|
||||||
for f in self.get_files('g'):
|
for f in self.get_files("g"):
|
||||||
try:
|
try:
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
im.load()
|
im.load()
|
||||||
compare = Image.open(get_compare(f))
|
compare = Image.open(get_compare(f))
|
||||||
compare.load()
|
compare.load()
|
||||||
if im.mode == 'P':
|
if im.mode == "P":
|
||||||
# assert image similar doesn't really work
|
# assert image similar doesn't really work
|
||||||
# with paletized image, since the palette might
|
# with paletized image, since the palette might
|
||||||
# be differently ordered for an equivalent image.
|
# be differently ordered for an equivalent image.
|
||||||
im = im.convert('RGBA')
|
im = im.convert("RGBA")
|
||||||
compare = im.convert('RGBA')
|
compare = im.convert("RGBA")
|
||||||
self.assert_image_similar(im, compare, 5)
|
self.assert_image_similar(im, compare, 5)
|
||||||
|
|
||||||
except Exception as msg:
|
except Exception as msg:
|
||||||
# there are three here that are unsupported:
|
# there are three here that are unsupported:
|
||||||
unsupported = (os.path.join(base, 'g', 'rgb32bf.bmp'),
|
unsupported = (
|
||||||
os.path.join(base, 'g', 'pal8rle.bmp'),
|
os.path.join(base, "g", "rgb32bf.bmp"),
|
||||||
os.path.join(base, 'g', 'pal4rle.bmp'))
|
os.path.join(base, "g", "pal8rle.bmp"),
|
||||||
|
os.path.join(base, "g", "pal4rle.bmp"),
|
||||||
|
)
|
||||||
if f not in unsupported:
|
if f not in unsupported:
|
||||||
self.fail("Unsupported Image %s: %s" % (f, msg))
|
self.fail("Unsupported Image %s: %s" % (f, msg))
|
||||||
|
|
|
@ -4,6 +4,7 @@ from PIL import Image, ImageFilter
|
||||||
|
|
||||||
|
|
||||||
sample = Image.new("L", (7, 5))
|
sample = Image.new("L", (7, 5))
|
||||||
|
# fmt: off
|
||||||
sample.putdata(sum([
|
sample.putdata(sum([
|
||||||
[210, 50, 20, 10, 220, 230, 80],
|
[210, 50, 20, 10, 220, 230, 80],
|
||||||
[190, 210, 20, 180, 170, 40, 110],
|
[190, 210, 20, 180, 170, 40, 110],
|
||||||
|
@ -11,10 +12,10 @@ sample.putdata(sum([
|
||||||
[220, 40, 230, 80, 130, 250, 40],
|
[220, 40, 230, 80, 130, 250, 40],
|
||||||
[250, 0, 80, 30, 60, 20, 110],
|
[250, 0, 80, 30, 60, 20, 110],
|
||||||
], []))
|
], []))
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
class TestBoxBlurApi(PillowTestCase):
|
class TestBoxBlurApi(PillowTestCase):
|
||||||
|
|
||||||
def test_imageops_box_blur(self):
|
def test_imageops_box_blur(self):
|
||||||
i = sample.filter(ImageFilter.BoxBlur(1))
|
i = sample.filter(ImageFilter.BoxBlur(1))
|
||||||
self.assertEqual(i.mode, sample.mode)
|
self.assertEqual(i.mode, sample.mode)
|
||||||
|
@ -23,7 +24,6 @@ class TestBoxBlurApi(PillowTestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestBoxBlur(PillowTestCase):
|
class TestBoxBlur(PillowTestCase):
|
||||||
|
|
||||||
def box_blur(self, image, radius=1, n=1):
|
def box_blur(self, image, radius=1, n=1):
|
||||||
return image._new(image.im.box_blur(radius, n))
|
return image._new(image.im.box_blur(radius, n))
|
||||||
|
|
||||||
|
@ -32,8 +32,7 @@ class TestBoxBlur(PillowTestCase):
|
||||||
for data_row in data:
|
for data_row in data:
|
||||||
im_row = [next(it) for _ in range(im.size[0])]
|
im_row = [next(it) for _ in range(im.size[0])]
|
||||||
if any(
|
if any(
|
||||||
abs(data_v - im_v) > delta
|
abs(data_v - im_v) > delta for data_v, im_v in zip(data_row, im_row)
|
||||||
for data_v, im_v in zip(data_row, im_row)
|
|
||||||
):
|
):
|
||||||
self.assertEqual(im_row, data_row)
|
self.assertEqual(im_row, data_row)
|
||||||
self.assertRaises(StopIteration, next, it)
|
self.assertRaises(StopIteration, next, it)
|
||||||
|
@ -41,7 +40,7 @@ class TestBoxBlur(PillowTestCase):
|
||||||
def assertBlur(self, im, radius, data, passes=1, delta=0):
|
def assertBlur(self, im, radius, data, passes=1, delta=0):
|
||||||
# check grayscale image
|
# check grayscale image
|
||||||
self.assertImage(self.box_blur(im, radius, passes), data, delta)
|
self.assertImage(self.box_blur(im, radius, passes), data, delta)
|
||||||
rgba = Image.merge('RGBA', (im, im, im, im))
|
rgba = Image.merge("RGBA", (im, im, im, im))
|
||||||
for band in self.box_blur(rgba, radius, passes).split():
|
for band in self.box_blur(rgba, radius, passes).split():
|
||||||
self.assertImage(band, data, delta)
|
self.assertImage(band, data, delta)
|
||||||
|
|
||||||
|
@ -61,110 +60,135 @@ class TestBoxBlur(PillowTestCase):
|
||||||
|
|
||||||
def test_radius_0(self):
|
def test_radius_0(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 0,
|
sample,
|
||||||
|
0,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[210, 50, 20, 10, 220, 230, 80],
|
[210, 50, 20, 10, 220, 230, 80],
|
||||||
[190, 210, 20, 180, 170, 40, 110],
|
[190, 210, 20, 180, 170, 40, 110],
|
||||||
[120, 210, 250, 60, 220, 0, 220],
|
[120, 210, 250, 60, 220, 0, 220],
|
||||||
[220, 40, 230, 80, 130, 250, 40],
|
[220, 40, 230, 80, 130, 250, 40],
|
||||||
[250, 0, 80, 30, 60, 20, 110],
|
[250, 0, 80, 30, 60, 20, 110],
|
||||||
]
|
# fmt: on
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_0_02(self):
|
def test_radius_0_02(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 0.02,
|
sample,
|
||||||
|
0.02,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[206, 55, 20, 17, 215, 223, 83],
|
[206, 55, 20, 17, 215, 223, 83],
|
||||||
[189, 203, 31, 171, 169, 46, 110],
|
[189, 203, 31, 171, 169, 46, 110],
|
||||||
[125, 206, 241, 69, 210, 13, 210],
|
[125, 206, 241, 69, 210, 13, 210],
|
||||||
[215, 49, 221, 82, 131, 235, 48],
|
[215, 49, 221, 82, 131, 235, 48],
|
||||||
[244, 7, 80, 32, 60, 27, 107],
|
[244, 7, 80, 32, 60, 27, 107],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=2,
|
delta=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_0_05(self):
|
def test_radius_0_05(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 0.05,
|
sample,
|
||||||
|
0.05,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[202, 62, 22, 27, 209, 215, 88],
|
[202, 62, 22, 27, 209, 215, 88],
|
||||||
[188, 194, 44, 161, 168, 56, 111],
|
[188, 194, 44, 161, 168, 56, 111],
|
||||||
[131, 201, 229, 81, 198, 31, 198],
|
[131, 201, 229, 81, 198, 31, 198],
|
||||||
[209, 62, 209, 86, 133, 216, 59],
|
[209, 62, 209, 86, 133, 216, 59],
|
||||||
[237, 17, 80, 36, 60, 35, 103],
|
[237, 17, 80, 36, 60, 35, 103],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=2,
|
delta=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_0_1(self):
|
def test_radius_0_1(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 0.1,
|
sample,
|
||||||
|
0.1,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[196, 72, 24, 40, 200, 203, 93],
|
[196, 72, 24, 40, 200, 203, 93],
|
||||||
[187, 183, 62, 148, 166, 68, 111],
|
[187, 183, 62, 148, 166, 68, 111],
|
||||||
[139, 193, 213, 96, 182, 54, 182],
|
[139, 193, 213, 96, 182, 54, 182],
|
||||||
[201, 78, 193, 91, 133, 191, 73],
|
[201, 78, 193, 91, 133, 191, 73],
|
||||||
[227, 31, 80, 42, 61, 47, 99],
|
[227, 31, 80, 42, 61, 47, 99],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
delta=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_0_5(self):
|
def test_radius_0_5(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 0.5,
|
sample,
|
||||||
|
0.5,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[176, 101, 46, 83, 163, 165, 111],
|
[176, 101, 46, 83, 163, 165, 111],
|
||||||
[176, 149, 108, 122, 144, 120, 117],
|
[176, 149, 108, 122, 144, 120, 117],
|
||||||
[164, 171, 159, 141, 134, 119, 129],
|
[164, 171, 159, 141, 134, 119, 129],
|
||||||
[170, 136, 133, 114, 116, 124, 109],
|
[170, 136, 133, 114, 116, 124, 109],
|
||||||
[184, 95, 72, 70, 69, 81, 89],
|
[184, 95, 72, 70, 69, 81, 89],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
delta=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_1(self):
|
def test_radius_1(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 1,
|
sample,
|
||||||
|
1,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[170, 109, 63, 97, 146, 153, 116],
|
[170, 109, 63, 97, 146, 153, 116],
|
||||||
[168, 142, 112, 128, 126, 143, 121],
|
[168, 142, 112, 128, 126, 143, 121],
|
||||||
[169, 166, 142, 149, 126, 131, 114],
|
[169, 166, 142, 149, 126, 131, 114],
|
||||||
[159, 156, 109, 127, 94, 117, 112],
|
[159, 156, 109, 127, 94, 117, 112],
|
||||||
[164, 128, 63, 87, 76, 89, 90],
|
[164, 128, 63, 87, 76, 89, 90],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
delta=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_1_5(self):
|
def test_radius_1_5(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 1.5,
|
sample,
|
||||||
|
1.5,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[155, 120, 105, 112, 124, 137, 130],
|
[155, 120, 105, 112, 124, 137, 130],
|
||||||
[160, 136, 124, 125, 127, 134, 130],
|
[160, 136, 124, 125, 127, 134, 130],
|
||||||
[166, 147, 130, 125, 120, 121, 119],
|
[166, 147, 130, 125, 120, 121, 119],
|
||||||
[168, 145, 119, 109, 103, 105, 110],
|
[168, 145, 119, 109, 103, 105, 110],
|
||||||
[168, 134, 96, 85, 85, 89, 97],
|
[168, 134, 96, 85, 85, 89, 97],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
delta=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_bigger_then_half(self):
|
def test_radius_bigger_then_half(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 3,
|
sample,
|
||||||
|
3,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[144, 145, 142, 128, 114, 115, 117],
|
[144, 145, 142, 128, 114, 115, 117],
|
||||||
[148, 145, 137, 122, 109, 111, 112],
|
[148, 145, 137, 122, 109, 111, 112],
|
||||||
[152, 145, 131, 117, 103, 107, 108],
|
[152, 145, 131, 117, 103, 107, 108],
|
||||||
[156, 144, 126, 111, 97, 102, 103],
|
[156, 144, 126, 111, 97, 102, 103],
|
||||||
[160, 144, 121, 106, 92, 98, 99],
|
[160, 144, 121, 106, 92, 98, 99],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
delta=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_bigger_then_width(self):
|
def test_radius_bigger_then_width(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 10,
|
sample,
|
||||||
|
10,
|
||||||
[
|
[
|
||||||
[158, 153, 147, 141, 135, 129, 123],
|
[158, 153, 147, 141, 135, 129, 123],
|
||||||
[159, 153, 147, 141, 136, 130, 124],
|
[159, 153, 147, 141, 136, 130, 124],
|
||||||
|
@ -177,7 +201,8 @@ class TestBoxBlur(PillowTestCase):
|
||||||
|
|
||||||
def test_extreme_large_radius(self):
|
def test_extreme_large_radius(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 600,
|
sample,
|
||||||
|
600,
|
||||||
[
|
[
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
|
@ -190,13 +215,16 @@ class TestBoxBlur(PillowTestCase):
|
||||||
|
|
||||||
def test_two_passes(self):
|
def test_two_passes(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 1,
|
sample,
|
||||||
|
1,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[153, 123, 102, 109, 132, 135, 129],
|
[153, 123, 102, 109, 132, 135, 129],
|
||||||
[159, 138, 123, 121, 133, 131, 126],
|
[159, 138, 123, 121, 133, 131, 126],
|
||||||
[162, 147, 136, 124, 127, 121, 121],
|
[162, 147, 136, 124, 127, 121, 121],
|
||||||
[159, 140, 125, 108, 111, 106, 108],
|
[159, 140, 125, 108, 111, 106, 108],
|
||||||
[154, 126, 105, 87, 94, 93, 97],
|
[154, 126, 105, 87, 94, 93, 97],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
passes=2,
|
passes=2,
|
||||||
delta=1,
|
delta=1,
|
||||||
|
@ -204,13 +232,16 @@ class TestBoxBlur(PillowTestCase):
|
||||||
|
|
||||||
def test_three_passes(self):
|
def test_three_passes(self):
|
||||||
self.assertBlur(
|
self.assertBlur(
|
||||||
sample, 1,
|
sample,
|
||||||
|
1,
|
||||||
[
|
[
|
||||||
|
# fmt: off
|
||||||
[146, 131, 116, 118, 126, 131, 130],
|
[146, 131, 116, 118, 126, 131, 130],
|
||||||
[151, 138, 125, 123, 126, 128, 127],
|
[151, 138, 125, 123, 126, 128, 127],
|
||||||
[154, 143, 129, 123, 120, 120, 119],
|
[154, 143, 129, 123, 120, 120, 119],
|
||||||
[152, 139, 122, 113, 108, 108, 108],
|
[152, 139, 122, 113, 108, 108, 108],
|
||||||
[148, 132, 112, 102, 97, 99, 100],
|
[148, 132, 112, 102, 97, 99, 100],
|
||||||
|
# fmt: on
|
||||||
],
|
],
|
||||||
passes=3,
|
passes=3,
|
||||||
delta=1,
|
delta=1,
|
||||||
|
|
|
@ -20,185 +20,197 @@ class TestColorLut3DCoreAPI(PillowTestCase):
|
||||||
|
|
||||||
table = [
|
table = [
|
||||||
[
|
[
|
||||||
r / float(size1D-1) if size1D != 1 else 0,
|
r / float(size1D - 1) if size1D != 1 else 0,
|
||||||
g / float(size2D-1) if size2D != 1 else 0,
|
g / float(size2D - 1) if size2D != 1 else 0,
|
||||||
b / float(size3D-1) if size3D != 1 else 0,
|
b / float(size3D - 1) if size3D != 1 else 0,
|
||||||
r / float(size1D-1) if size1D != 1 else 0,
|
r / float(size1D - 1) if size1D != 1 else 0,
|
||||||
g / float(size2D-1) if size2D != 1 else 0,
|
g / float(size2D - 1) if size2D != 1 else 0,
|
||||||
][:channels]
|
][:channels]
|
||||||
for b in range(size3D)
|
for b in range(size3D)
|
||||||
for g in range(size2D)
|
for g in range(size2D)
|
||||||
for r in range(size1D)
|
for r in range(size1D)
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
channels, size1D, size2D, size3D,
|
channels,
|
||||||
[item for sublist in table for item in sublist])
|
size1D,
|
||||||
|
size2D,
|
||||||
|
size3D,
|
||||||
|
[item for sublist in table for item in sublist],
|
||||||
|
)
|
||||||
|
|
||||||
def test_wrong_args(self):
|
def test_wrong_args(self):
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "filter"):
|
with self.assertRaisesRegex(ValueError, "filter"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.CUBIC, *self.generate_identity_table(3, 3))
|
||||||
Image.CUBIC,
|
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "image mode"):
|
with self.assertRaisesRegex(ValueError, "image mode"):
|
||||||
im.im.color_lut_3d('wrong',
|
im.im.color_lut_3d(
|
||||||
Image.LINEAR,
|
"wrong", Image.LINEAR, *self.generate_identity_table(3, 3)
|
||||||
*self.generate_identity_table(3, 3))
|
)
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "table_channels"):
|
with self.assertRaisesRegex(ValueError, "table_channels"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(5, 3))
|
||||||
Image.LINEAR,
|
|
||||||
*self.generate_identity_table(5, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "table_channels"):
|
with self.assertRaisesRegex(ValueError, "table_channels"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(1, 3))
|
||||||
Image.LINEAR,
|
|
||||||
*self.generate_identity_table(1, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "table_channels"):
|
with self.assertRaisesRegex(ValueError, "table_channels"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(2, 3))
|
||||||
Image.LINEAR,
|
|
||||||
*self.generate_identity_table(2, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "Table size"):
|
with self.assertRaisesRegex(ValueError, "Table size"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d(
|
||||||
Image.LINEAR,
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (1, 3, 3))
|
||||||
*self.generate_identity_table(3, (1, 3, 3)))
|
)
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "Table size"):
|
with self.assertRaisesRegex(ValueError, "Table size"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d(
|
||||||
Image.LINEAR,
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (66, 3, 3))
|
||||||
*self.generate_identity_table(3, (66, 3, 3)))
|
)
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"):
|
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 7)
|
||||||
Image.LINEAR,
|
|
||||||
3, 2, 2, 2, [0, 0, 0] * 7)
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"):
|
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 9)
|
||||||
Image.LINEAR,
|
|
||||||
3, 2, 2, 2, [0, 0, 0] * 9)
|
|
||||||
|
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, "0"] * 8)
|
||||||
Image.LINEAR,
|
|
||||||
3, 2, 2, 2, [0, 0, "0"] * 8)
|
|
||||||
|
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
im.im.color_lut_3d('RGB',
|
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, 16)
|
||||||
Image.LINEAR,
|
|
||||||
3, 2, 2, 2, 16)
|
|
||||||
|
|
||||||
def test_correct_args(self):
|
def test_correct_args(self):
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
|
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(3, 3))
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
im.im.color_lut_3d('CMYK', Image.LINEAR,
|
im.im.color_lut_3d("CMYK", Image.LINEAR, *self.generate_identity_table(4, 3))
|
||||||
*self.generate_identity_table(4, 3))
|
|
||||||
|
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d(
|
||||||
*self.generate_identity_table(3, (2, 3, 3)))
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (2, 3, 3))
|
||||||
|
)
|
||||||
|
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d(
|
||||||
*self.generate_identity_table(3, (65, 3, 3)))
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (65, 3, 3))
|
||||||
|
)
|
||||||
|
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d(
|
||||||
*self.generate_identity_table(3, (3, 65, 3)))
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (3, 65, 3))
|
||||||
|
)
|
||||||
|
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d(
|
||||||
*self.generate_identity_table(3, (3, 3, 65)))
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (3, 3, 65))
|
||||||
|
)
|
||||||
|
|
||||||
def test_wrong_mode(self):
|
def test_wrong_mode(self):
|
||||||
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
||||||
im = Image.new('L', (10, 10), 0)
|
im = Image.new("L", (10, 10), 0)
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(3, 3))
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
im.im.color_lut_3d('L', Image.LINEAR,
|
im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3))
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
||||||
im = Image.new('L', (10, 10), 0)
|
im = Image.new("L", (10, 10), 0)
|
||||||
im.im.color_lut_3d('L', Image.LINEAR,
|
im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3))
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
im.im.color_lut_3d('RGBA', Image.LINEAR,
|
im.im.color_lut_3d(
|
||||||
*self.generate_identity_table(3, 3))
|
"RGBA", Image.LINEAR, *self.generate_identity_table(3, 3)
|
||||||
|
)
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
with self.assertRaisesRegex(ValueError, "wrong mode"):
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(4, 3))
|
||||||
*self.generate_identity_table(4, 3))
|
|
||||||
|
|
||||||
def test_correct_mode(self):
|
def test_correct_mode(self):
|
||||||
im = Image.new('RGBA', (10, 10), 0)
|
im = Image.new("RGBA", (10, 10), 0)
|
||||||
im.im.color_lut_3d('RGBA', Image.LINEAR,
|
im.im.color_lut_3d("RGBA", Image.LINEAR, *self.generate_identity_table(3, 3))
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
im = Image.new('RGBA', (10, 10), 0)
|
im = Image.new("RGBA", (10, 10), 0)
|
||||||
im.im.color_lut_3d('RGBA', Image.LINEAR,
|
im.im.color_lut_3d("RGBA", Image.LINEAR, *self.generate_identity_table(4, 3))
|
||||||
*self.generate_identity_table(4, 3))
|
|
||||||
|
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
im.im.color_lut_3d('HSV', Image.LINEAR,
|
im.im.color_lut_3d("HSV", Image.LINEAR, *self.generate_identity_table(3, 3))
|
||||||
*self.generate_identity_table(3, 3))
|
|
||||||
|
|
||||||
im = Image.new('RGB', (10, 10), 0)
|
im = Image.new("RGB", (10, 10), 0)
|
||||||
im.im.color_lut_3d('RGBA', Image.LINEAR,
|
im.im.color_lut_3d("RGBA", Image.LINEAR, *self.generate_identity_table(4, 3))
|
||||||
*self.generate_identity_table(4, 3))
|
|
||||||
|
|
||||||
def test_identities(self):
|
def test_identities(self):
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180)])
|
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
|
||||||
|
)
|
||||||
|
|
||||||
# Fast test with small cubes
|
# Fast test with small cubes
|
||||||
for size in [2, 3, 5, 7, 11, 16, 17]:
|
for size in [2, 3, 5, 7, 11, 16, 17]:
|
||||||
self.assert_image_equal(im, im._new(
|
self.assert_image_equal(
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im,
|
||||||
*self.generate_identity_table(3, size))))
|
im._new(
|
||||||
|
im.im.color_lut_3d(
|
||||||
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, size)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# Not so fast
|
# Not so fast
|
||||||
self.assert_image_equal(im, im._new(
|
self.assert_image_equal(
|
||||||
im.im.color_lut_3d('RGB', Image.LINEAR,
|
im,
|
||||||
*self.generate_identity_table(3, (2, 2, 65)))))
|
im._new(
|
||||||
|
im.im.color_lut_3d(
|
||||||
|
"RGB", Image.LINEAR, *self.generate_identity_table(3, (2, 2, 65))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_identities_4_channels(self):
|
def test_identities_4_channels(self):
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180)])
|
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
|
||||||
|
)
|
||||||
|
|
||||||
# Red channel copied to alpha
|
# Red channel copied to alpha
|
||||||
self.assert_image_equal(
|
self.assert_image_equal(
|
||||||
Image.merge('RGBA', (im.split()*2)[:4]),
|
Image.merge("RGBA", (im.split() * 2)[:4]),
|
||||||
im._new(im.im.color_lut_3d('RGBA', Image.LINEAR,
|
im._new(
|
||||||
*self.generate_identity_table(4, 17))))
|
im.im.color_lut_3d(
|
||||||
|
"RGBA", Image.LINEAR, *self.generate_identity_table(4, 17)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_copy_alpha_channel(self):
|
def test_copy_alpha_channel(self):
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGBA', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180),
|
"RGBA",
|
||||||
g.transpose(Image.ROTATE_270)])
|
[
|
||||||
|
g,
|
||||||
|
g.transpose(Image.ROTATE_90),
|
||||||
|
g.transpose(Image.ROTATE_180),
|
||||||
|
g.transpose(Image.ROTATE_270),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
self.assert_image_equal(im, im._new(
|
self.assert_image_equal(
|
||||||
im.im.color_lut_3d('RGBA', Image.LINEAR,
|
im,
|
||||||
*self.generate_identity_table(3, 17))))
|
im._new(
|
||||||
|
im.im.color_lut_3d(
|
||||||
|
"RGBA", Image.LINEAR, *self.generate_identity_table(3, 17)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_channels_order(self):
|
def test_channels_order(self):
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180)])
|
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
|
||||||
|
)
|
||||||
|
|
||||||
# Reverse channels by splitting and using table
|
# Reverse channels by splitting and using table
|
||||||
|
# fmt: off
|
||||||
self.assert_image_equal(
|
self.assert_image_equal(
|
||||||
Image.merge('RGB', im.split()[::-1]),
|
Image.merge('RGB', im.split()[::-1]),
|
||||||
im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
|
im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
|
||||||
|
@ -209,12 +221,15 @@ class TestColorLut3DCoreAPI(PillowTestCase):
|
||||||
1, 0, 0, 1, 0, 1,
|
1, 0, 0, 1, 0, 1,
|
||||||
1, 1, 0, 1, 1, 1,
|
1, 1, 0, 1, 1, 1,
|
||||||
])))
|
])))
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_overflow(self):
|
def test_overflow(self):
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180)])
|
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
|
||||||
|
)
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
|
transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
|
||||||
3, 2, 2, 2,
|
3, 2, 2, 2,
|
||||||
[
|
[
|
||||||
|
@ -224,6 +239,7 @@ class TestColorLut3DCoreAPI(PillowTestCase):
|
||||||
-1, -1, 2, 2, -1, 2,
|
-1, -1, 2, 2, -1, 2,
|
||||||
-1, 2, 2, 2, 2, 2,
|
-1, 2, 2, 2, 2, 2,
|
||||||
])).load()
|
])).load()
|
||||||
|
# fmt: on
|
||||||
self.assertEqual(transformed[0, 0], (0, 0, 255))
|
self.assertEqual(transformed[0, 0], (0, 0, 255))
|
||||||
self.assertEqual(transformed[50, 50], (0, 0, 255))
|
self.assertEqual(transformed[50, 50], (0, 0, 255))
|
||||||
self.assertEqual(transformed[255, 0], (0, 255, 255))
|
self.assertEqual(transformed[255, 0], (0, 255, 255))
|
||||||
|
@ -233,6 +249,7 @@ class TestColorLut3DCoreAPI(PillowTestCase):
|
||||||
self.assertEqual(transformed[255, 255], (255, 255, 0))
|
self.assertEqual(transformed[255, 255], (255, 255, 0))
|
||||||
self.assertEqual(transformed[205, 205], (255, 255, 0))
|
self.assertEqual(transformed[205, 205], (255, 255, 0))
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
|
transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
|
||||||
3, 2, 2, 2,
|
3, 2, 2, 2,
|
||||||
[
|
[
|
||||||
|
@ -242,6 +259,7 @@ class TestColorLut3DCoreAPI(PillowTestCase):
|
||||||
-3, -3, 5, 5, -3, 5,
|
-3, -3, 5, 5, -3, 5,
|
||||||
-3, 5, 5, 5, 5, 5,
|
-3, 5, 5, 5, 5, 5,
|
||||||
])).load()
|
])).load()
|
||||||
|
# fmt: on
|
||||||
self.assertEqual(transformed[0, 0], (0, 0, 255))
|
self.assertEqual(transformed[0, 0], (0, 0, 255))
|
||||||
self.assertEqual(transformed[50, 50], (0, 0, 255))
|
self.assertEqual(transformed[50, 50], (0, 0, 255))
|
||||||
self.assertEqual(transformed[255, 0], (0, 255, 255))
|
self.assertEqual(transformed[255, 0], (0, 255, 255))
|
||||||
|
@ -286,14 +304,15 @@ class TestColorLut3DFilter(PillowTestCase):
|
||||||
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
||||||
self.assertEqual(lut.name, "Color 3D LUT")
|
self.assertEqual(lut.name, "Color 3D LUT")
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
lut = ImageFilter.Color3DLUT((2, 2, 2), [
|
lut = ImageFilter.Color3DLUT((2, 2, 2), [
|
||||||
(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11),
|
(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11),
|
||||||
(12, 13, 14), (15, 16, 17), (18, 19, 20), (21, 22, 23)])
|
(12, 13, 14), (15, 16, 17), (18, 19, 20), (21, 22, 23)])
|
||||||
|
# fmt: on
|
||||||
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
||||||
self.assertEqual(lut.table, list(range(24)))
|
self.assertEqual(lut.table, list(range(24)))
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT((2, 2, 2), [(0, 1, 2, 3)] * 8,
|
lut = ImageFilter.Color3DLUT((2, 2, 2), [(0, 1, 2, 3)] * 8, channels=4)
|
||||||
channels=4)
|
|
||||||
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
||||||
self.assertEqual(lut.table, list(range(4)) * 8)
|
self.assertEqual(lut.table, list(range(4)) * 8)
|
||||||
|
|
||||||
|
@ -318,7 +337,7 @@ class TestColorLut3DFilter(PillowTestCase):
|
||||||
self.assertEqual(lut.table.shape, (table.size,))
|
self.assertEqual(lut.table.shape, (table.size,))
|
||||||
|
|
||||||
# Check application
|
# Check application
|
||||||
Image.new('RGB', (10, 10), 0).filter(lut)
|
Image.new("RGB", (10, 10), 0).filter(lut)
|
||||||
|
|
||||||
# Check copy
|
# Check copy
|
||||||
table[0] = 33
|
table[0] = 33
|
||||||
|
@ -332,40 +351,34 @@ class TestColorLut3DFilter(PillowTestCase):
|
||||||
|
|
||||||
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
||||||
def test_numpy_formats(self):
|
def test_numpy_formats(self):
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180)])
|
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
|
||||||
|
)
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
|
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
|
||||||
lambda r, g, b: (r, g, b))
|
|
||||||
lut.table = numpy.array(lut.table, dtype=numpy.float32)[:-1]
|
lut.table = numpy.array(lut.table, dtype=numpy.float32)[:-1]
|
||||||
with self.assertRaisesRegex(ValueError, "should have table_channels"):
|
with self.assertRaisesRegex(ValueError, "should have table_channels"):
|
||||||
im.filter(lut)
|
im.filter(lut)
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
|
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
|
||||||
lambda r, g, b: (r, g, b))
|
lut.table = numpy.array(lut.table, dtype=numpy.float32).reshape((7 * 9 * 11), 3)
|
||||||
lut.table = (numpy.array(lut.table, dtype=numpy.float32)
|
|
||||||
.reshape((7 * 9 * 11), 3))
|
|
||||||
with self.assertRaisesRegex(ValueError, "should have table_channels"):
|
with self.assertRaisesRegex(ValueError, "should have table_channels"):
|
||||||
im.filter(lut)
|
im.filter(lut)
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
|
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
|
||||||
lambda r, g, b: (r, g, b))
|
|
||||||
lut.table = numpy.array(lut.table, dtype=numpy.float16)
|
lut.table = numpy.array(lut.table, dtype=numpy.float16)
|
||||||
self.assert_image_equal(im, im.filter(lut))
|
self.assert_image_equal(im, im.filter(lut))
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
|
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
|
||||||
lambda r, g, b: (r, g, b))
|
|
||||||
lut.table = numpy.array(lut.table, dtype=numpy.float32)
|
lut.table = numpy.array(lut.table, dtype=numpy.float32)
|
||||||
self.assert_image_equal(im, im.filter(lut))
|
self.assert_image_equal(im, im.filter(lut))
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
|
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
|
||||||
lambda r, g, b: (r, g, b))
|
|
||||||
lut.table = numpy.array(lut.table, dtype=numpy.float64)
|
lut.table = numpy.array(lut.table, dtype=numpy.float64)
|
||||||
self.assert_image_equal(im, im.filter(lut))
|
self.assert_image_equal(im, im.filter(lut))
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
|
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
|
||||||
lambda r, g, b: (r, g, b))
|
|
||||||
lut.table = numpy.array(lut.table, dtype=numpy.int32)
|
lut.table = numpy.array(lut.table, dtype=numpy.int32)
|
||||||
im.filter(lut)
|
im.filter(lut)
|
||||||
lut.table = numpy.array(lut.table, dtype=numpy.int8)
|
lut.table = numpy.array(lut.table, dtype=numpy.int8)
|
||||||
|
@ -373,54 +386,65 @@ class TestColorLut3DFilter(PillowTestCase):
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8)
|
lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8)
|
||||||
self.assertEqual(repr(lut),
|
self.assertEqual(repr(lut), "<Color3DLUT from list size=2x2x2 channels=3>")
|
||||||
"<Color3DLUT from list size=2x2x2 channels=3>")
|
|
||||||
|
|
||||||
lut = ImageFilter.Color3DLUT(
|
lut = ImageFilter.Color3DLUT(
|
||||||
(3, 4, 5), array('f', [0, 0, 0, 0] * (3 * 4 * 5)),
|
(3, 4, 5),
|
||||||
channels=4, target_mode='YCbCr', _copy_table=False)
|
array("f", [0, 0, 0, 0] * (3 * 4 * 5)),
|
||||||
|
channels=4,
|
||||||
|
target_mode="YCbCr",
|
||||||
|
_copy_table=False,
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
repr(lut),
|
repr(lut), "<Color3DLUT from array size=3x4x5 channels=4 target_mode=YCbCr>"
|
||||||
"<Color3DLUT from array size=3x4x5 channels=4 target_mode=YCbCr>")
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestGenerateColorLut3D(PillowTestCase):
|
class TestGenerateColorLut3D(PillowTestCase):
|
||||||
def test_wrong_channels_count(self):
|
def test_wrong_channels_count(self):
|
||||||
with self.assertRaisesRegex(ValueError, "3 or 4 output channels"):
|
with self.assertRaisesRegex(ValueError, "3 or 4 output channels"):
|
||||||
ImageFilter.Color3DLUT.generate(
|
ImageFilter.Color3DLUT.generate(
|
||||||
5, channels=2, callback=lambda r, g, b: (r, g, b))
|
5, channels=2, callback=lambda r, g, b: (r, g, b)
|
||||||
|
)
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "should have either channels"):
|
with self.assertRaisesRegex(ValueError, "should have either channels"):
|
||||||
ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b, r))
|
ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b, r))
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, "should have either channels"):
|
with self.assertRaisesRegex(ValueError, "should have either channels"):
|
||||||
ImageFilter.Color3DLUT.generate(
|
ImageFilter.Color3DLUT.generate(
|
||||||
5, channels=4, callback=lambda r, g, b: (r, g, b))
|
5, channels=4, callback=lambda r, g, b: (r, g, b)
|
||||||
|
)
|
||||||
|
|
||||||
def test_3_channels(self):
|
def test_3_channels(self):
|
||||||
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
|
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
|
||||||
self.assertEqual(tuple(lut.size), (5, 5, 5))
|
self.assertEqual(tuple(lut.size), (5, 5, 5))
|
||||||
self.assertEqual(lut.name, "Color 3D LUT")
|
self.assertEqual(lut.name, "Color 3D LUT")
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[:24], [
|
self.assertEqual(lut.table[:24], [
|
||||||
0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.75, 0.0, 0.0,
|
0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.75, 0.0, 0.0,
|
||||||
1.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, 0.25, 0.0, 0.5, 0.25, 0.0])
|
1.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, 0.25, 0.0, 0.5, 0.25, 0.0])
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_4_channels(self):
|
def test_4_channels(self):
|
||||||
lut = ImageFilter.Color3DLUT.generate(
|
lut = ImageFilter.Color3DLUT.generate(
|
||||||
5, channels=4, callback=lambda r, g, b: (b, r, g, (r+g+b) / 2))
|
5, channels=4, callback=lambda r, g, b: (b, r, g, (r + g + b) / 2)
|
||||||
|
)
|
||||||
self.assertEqual(tuple(lut.size), (5, 5, 5))
|
self.assertEqual(tuple(lut.size), (5, 5, 5))
|
||||||
self.assertEqual(lut.name, "Color 3D LUT")
|
self.assertEqual(lut.name, "Color 3D LUT")
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[:24], [
|
self.assertEqual(lut.table[:24], [
|
||||||
0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.125, 0.0, 0.5, 0.0, 0.25,
|
0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.125, 0.0, 0.5, 0.0, 0.25,
|
||||||
0.0, 0.75, 0.0, 0.375, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0, 0.25, 0.125
|
0.0, 0.75, 0.0, 0.375, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0, 0.25, 0.125
|
||||||
])
|
])
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_apply(self):
|
def test_apply(self):
|
||||||
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
|
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
|
||||||
|
|
||||||
g = Image.linear_gradient('L')
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
|
im = Image.merge(
|
||||||
g.transpose(Image.ROTATE_180)])
|
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
|
||||||
|
)
|
||||||
self.assertEqual(im, im.filter(lut))
|
self.assertEqual(im, im.filter(lut))
|
||||||
|
|
||||||
|
|
||||||
|
@ -442,80 +466,96 @@ class TestTransformColorLut3D(PillowTestCase):
|
||||||
|
|
||||||
def test_target_mode(self):
|
def test_target_mode(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate(
|
||||||
2, lambda r, g, b: (r, g, b), target_mode='HSV')
|
2, lambda r, g, b: (r, g, b), target_mode="HSV"
|
||||||
|
)
|
||||||
|
|
||||||
lut = source.transform(lambda r, g, b: (r, g, b))
|
lut = source.transform(lambda r, g, b: (r, g, b))
|
||||||
self.assertEqual(lut.mode, 'HSV')
|
self.assertEqual(lut.mode, "HSV")
|
||||||
|
|
||||||
lut = source.transform(lambda r, g, b: (r, g, b), target_mode='RGB')
|
lut = source.transform(lambda r, g, b: (r, g, b), target_mode="RGB")
|
||||||
self.assertEqual(lut.mode, 'RGB')
|
self.assertEqual(lut.mode, "RGB")
|
||||||
|
|
||||||
def test_3_to_3_channels(self):
|
def test_3_to_3_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate((3, 4, 5), lambda r, g, b: (r, g, b))
|
||||||
(3, 4, 5), lambda r, g, b: (r, g, b))
|
lut = source.transform(lambda r, g, b: (r * r, g * g, b * b))
|
||||||
lut = source.transform(lambda r, g, b: (r*r, g*g, b*b))
|
|
||||||
self.assertEqual(tuple(lut.size), tuple(source.size))
|
self.assertEqual(tuple(lut.size), tuple(source.size))
|
||||||
self.assertEqual(len(lut.table), len(source.table))
|
self.assertEqual(len(lut.table), len(source.table))
|
||||||
self.assertNotEqual(lut.table, source.table)
|
self.assertNotEqual(lut.table, source.table)
|
||||||
self.assertEqual(lut.table[0:10], [
|
self.assertEqual(
|
||||||
0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
|
lut.table[0:10], [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
|
||||||
|
)
|
||||||
|
|
||||||
def test_3_to_4_channels(self):
|
def test_3_to_4_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b))
|
||||||
(6, 5, 4), lambda r, g, b: (r, g, b))
|
lut = source.transform(lambda r, g, b: (r * r, g * g, b * b, 1), channels=4)
|
||||||
lut = source.transform(lambda r, g, b: (r*r, g*g, b*b, 1), channels=4)
|
|
||||||
self.assertEqual(tuple(lut.size), tuple(source.size))
|
self.assertEqual(tuple(lut.size), tuple(source.size))
|
||||||
self.assertNotEqual(len(lut.table), len(source.table))
|
self.assertNotEqual(len(lut.table), len(source.table))
|
||||||
self.assertNotEqual(lut.table, source.table)
|
self.assertNotEqual(lut.table, source.table)
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[0:16], [
|
self.assertEqual(lut.table[0:16], [
|
||||||
0.0, 0.0, 0.0, 1, 0.2**2, 0.0, 0.0, 1,
|
0.0, 0.0, 0.0, 1, 0.2**2, 0.0, 0.0, 1,
|
||||||
0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1])
|
0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1])
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_4_to_3_channels(self):
|
def test_4_to_3_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate(
|
||||||
(3, 6, 5), lambda r, g, b: (r, g, b, 1), channels=4)
|
(3, 6, 5), lambda r, g, b: (r, g, b, 1), channels=4
|
||||||
lut = source.transform(lambda r, g, b, a: (a - r*r, a - g*g, a - b*b),
|
)
|
||||||
channels=3)
|
lut = source.transform(
|
||||||
|
lambda r, g, b, a: (a - r * r, a - g * g, a - b * b), channels=3
|
||||||
|
)
|
||||||
self.assertEqual(tuple(lut.size), tuple(source.size))
|
self.assertEqual(tuple(lut.size), tuple(source.size))
|
||||||
self.assertNotEqual(len(lut.table), len(source.table))
|
self.assertNotEqual(len(lut.table), len(source.table))
|
||||||
self.assertNotEqual(lut.table, source.table)
|
self.assertNotEqual(lut.table, source.table)
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[0:18], [
|
self.assertEqual(lut.table[0:18], [
|
||||||
1.0, 1.0, 1.0, 0.75, 1.0, 1.0, 0.0, 1.0, 1.0,
|
1.0, 1.0, 1.0, 0.75, 1.0, 1.0, 0.0, 1.0, 1.0,
|
||||||
1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0])
|
1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0])
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_4_to_4_channels(self):
|
def test_4_to_4_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate(
|
||||||
(6, 5, 4), lambda r, g, b: (r, g, b, 1), channels=4)
|
(6, 5, 4), lambda r, g, b: (r, g, b, 1), channels=4
|
||||||
lut = source.transform(lambda r, g, b, a: (r*r, g*g, b*b, a - 0.5))
|
)
|
||||||
|
lut = source.transform(lambda r, g, b, a: (r * r, g * g, b * b, a - 0.5))
|
||||||
self.assertEqual(tuple(lut.size), tuple(source.size))
|
self.assertEqual(tuple(lut.size), tuple(source.size))
|
||||||
self.assertEqual(len(lut.table), len(source.table))
|
self.assertEqual(len(lut.table), len(source.table))
|
||||||
self.assertNotEqual(lut.table, source.table)
|
self.assertNotEqual(lut.table, source.table)
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[0:16], [
|
self.assertEqual(lut.table[0:16], [
|
||||||
0.0, 0.0, 0.0, 0.5, 0.2**2, 0.0, 0.0, 0.5,
|
0.0, 0.0, 0.0, 0.5, 0.2**2, 0.0, 0.0, 0.5,
|
||||||
0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5])
|
0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5])
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_with_normals_3_channels(self):
|
def test_with_normals_3_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate(
|
||||||
(6, 5, 4), lambda r, g, b: (r*r, g*g, b*b))
|
(6, 5, 4), lambda r, g, b: (r * r, g * g, b * b)
|
||||||
|
)
|
||||||
lut = source.transform(
|
lut = source.transform(
|
||||||
lambda nr, ng, nb, r, g, b: (nr - r, ng - g, nb - b),
|
lambda nr, ng, nb, r, g, b: (nr - r, ng - g, nb - b), with_normals=True
|
||||||
with_normals=True)
|
)
|
||||||
self.assertEqual(tuple(lut.size), tuple(source.size))
|
self.assertEqual(tuple(lut.size), tuple(source.size))
|
||||||
self.assertEqual(len(lut.table), len(source.table))
|
self.assertEqual(len(lut.table), len(source.table))
|
||||||
self.assertNotEqual(lut.table, source.table)
|
self.assertNotEqual(lut.table, source.table)
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[0:18], [
|
self.assertEqual(lut.table[0:18], [
|
||||||
0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.24, 0.0, 0.0,
|
0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.24, 0.0, 0.0,
|
||||||
0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0])
|
0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0])
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def test_with_normals_4_channels(self):
|
def test_with_normals_4_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate(
|
source = ImageFilter.Color3DLUT.generate(
|
||||||
(3, 6, 5), lambda r, g, b: (r*r, g*g, b*b, 1), channels=4)
|
(3, 6, 5), lambda r, g, b: (r * r, g * g, b * b, 1), channels=4
|
||||||
|
)
|
||||||
lut = source.transform(
|
lut = source.transform(
|
||||||
lambda nr, ng, nb, r, g, b, a: (nr - r, ng - g, nb - b, a-0.5),
|
lambda nr, ng, nb, r, g, b, a: (nr - r, ng - g, nb - b, a - 0.5),
|
||||||
with_normals=True)
|
with_normals=True,
|
||||||
|
)
|
||||||
self.assertEqual(tuple(lut.size), tuple(source.size))
|
self.assertEqual(tuple(lut.size), tuple(source.size))
|
||||||
self.assertEqual(len(lut.table), len(source.table))
|
self.assertEqual(len(lut.table), len(source.table))
|
||||||
self.assertNotEqual(lut.table, source.table)
|
self.assertNotEqual(lut.table, source.table)
|
||||||
|
# fmt: off
|
||||||
self.assertEqual(lut.table[0:16], [
|
self.assertEqual(lut.table[0:16], [
|
||||||
0.0, 0.0, 0.0, 0.5, 0.25, 0.0, 0.0, 0.5,
|
0.0, 0.0, 0.0, 0.5, 0.25, 0.0, 0.0, 0.5,
|
||||||
0.0, 0.0, 0.0, 0.5, 0.0, 0.16, 0.0, 0.5])
|
0.0, 0.0, 0.0, 0.5, 0.0, 0.16, 0.0, 0.5])
|
||||||
|
# fmt: on
|
||||||
|
|
|
@ -6,39 +6,39 @@ from .helper import unittest, PillowTestCase
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
is_pypy = hasattr(sys, 'pypy_version_info')
|
is_pypy = hasattr(sys, "pypy_version_info")
|
||||||
|
|
||||||
|
|
||||||
class TestCoreStats(PillowTestCase):
|
class TestCoreStats(PillowTestCase):
|
||||||
def test_get_stats(self):
|
def test_get_stats(self):
|
||||||
# Create at least one image
|
# Create at least one image
|
||||||
Image.new('RGB', (10, 10))
|
Image.new("RGB", (10, 10))
|
||||||
|
|
||||||
stats = Image.core.get_stats()
|
stats = Image.core.get_stats()
|
||||||
self.assertIn('new_count', stats)
|
self.assertIn("new_count", stats)
|
||||||
self.assertIn('reused_blocks', stats)
|
self.assertIn("reused_blocks", stats)
|
||||||
self.assertIn('freed_blocks', stats)
|
self.assertIn("freed_blocks", stats)
|
||||||
self.assertIn('allocated_blocks', stats)
|
self.assertIn("allocated_blocks", stats)
|
||||||
self.assertIn('reallocated_blocks', stats)
|
self.assertIn("reallocated_blocks", stats)
|
||||||
self.assertIn('blocks_cached', stats)
|
self.assertIn("blocks_cached", stats)
|
||||||
|
|
||||||
def test_reset_stats(self):
|
def test_reset_stats(self):
|
||||||
Image.core.reset_stats()
|
Image.core.reset_stats()
|
||||||
|
|
||||||
stats = Image.core.get_stats()
|
stats = Image.core.get_stats()
|
||||||
self.assertEqual(stats['new_count'], 0)
|
self.assertEqual(stats["new_count"], 0)
|
||||||
self.assertEqual(stats['reused_blocks'], 0)
|
self.assertEqual(stats["reused_blocks"], 0)
|
||||||
self.assertEqual(stats['freed_blocks'], 0)
|
self.assertEqual(stats["freed_blocks"], 0)
|
||||||
self.assertEqual(stats['allocated_blocks'], 0)
|
self.assertEqual(stats["allocated_blocks"], 0)
|
||||||
self.assertEqual(stats['reallocated_blocks'], 0)
|
self.assertEqual(stats["reallocated_blocks"], 0)
|
||||||
self.assertEqual(stats['blocks_cached'], 0)
|
self.assertEqual(stats["blocks_cached"], 0)
|
||||||
|
|
||||||
|
|
||||||
class TestCoreMemory(PillowTestCase):
|
class TestCoreMemory(PillowTestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# Restore default values
|
# Restore default values
|
||||||
Image.core.set_alignment(1)
|
Image.core.set_alignment(1)
|
||||||
Image.core.set_block_size(1024*1024)
|
Image.core.set_block_size(1024 * 1024)
|
||||||
Image.core.set_blocks_max(0)
|
Image.core.set_blocks_max(0)
|
||||||
Image.core.clear_cache()
|
Image.core.clear_cache()
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class TestCoreMemory(PillowTestCase):
|
||||||
self.assertEqual(alignment, i)
|
self.assertEqual(alignment, i)
|
||||||
|
|
||||||
# Try to construct new image
|
# Try to construct new image
|
||||||
Image.new('RGB', (10, 10))
|
Image.new("RGB", (10, 10))
|
||||||
|
|
||||||
self.assertRaises(ValueError, Image.core.set_alignment, 0)
|
self.assertRaises(ValueError, Image.core.set_alignment, 0)
|
||||||
self.assertRaises(ValueError, Image.core.set_alignment, -1)
|
self.assertRaises(ValueError, Image.core.set_alignment, -1)
|
||||||
|
@ -66,13 +66,13 @@ class TestCoreMemory(PillowTestCase):
|
||||||
self.assertGreaterEqual(block_size, 4096)
|
self.assertGreaterEqual(block_size, 4096)
|
||||||
|
|
||||||
def test_set_block_size(self):
|
def test_set_block_size(self):
|
||||||
for i in [4096, 2*4096, 3*4096]:
|
for i in [4096, 2 * 4096, 3 * 4096]:
|
||||||
Image.core.set_block_size(i)
|
Image.core.set_block_size(i)
|
||||||
block_size = Image.core.get_block_size()
|
block_size = Image.core.get_block_size()
|
||||||
self.assertEqual(block_size, i)
|
self.assertEqual(block_size, i)
|
||||||
|
|
||||||
# Try to construct new image
|
# Try to construct new image
|
||||||
Image.new('RGB', (10, 10))
|
Image.new("RGB", (10, 10))
|
||||||
|
|
||||||
self.assertRaises(ValueError, Image.core.set_block_size, 0)
|
self.assertRaises(ValueError, Image.core.set_block_size, 0)
|
||||||
self.assertRaises(ValueError, Image.core.set_block_size, -1)
|
self.assertRaises(ValueError, Image.core.set_block_size, -1)
|
||||||
|
@ -82,13 +82,13 @@ class TestCoreMemory(PillowTestCase):
|
||||||
Image.core.reset_stats()
|
Image.core.reset_stats()
|
||||||
Image.core.set_blocks_max(0)
|
Image.core.set_blocks_max(0)
|
||||||
Image.core.set_block_size(4096)
|
Image.core.set_block_size(4096)
|
||||||
Image.new('RGB', (256, 256))
|
Image.new("RGB", (256, 256))
|
||||||
|
|
||||||
stats = Image.core.get_stats()
|
stats = Image.core.get_stats()
|
||||||
self.assertGreaterEqual(stats['new_count'], 1)
|
self.assertGreaterEqual(stats["new_count"], 1)
|
||||||
self.assertGreaterEqual(stats['allocated_blocks'], 64)
|
self.assertGreaterEqual(stats["allocated_blocks"], 64)
|
||||||
if not is_pypy:
|
if not is_pypy:
|
||||||
self.assertGreaterEqual(stats['freed_blocks'], 64)
|
self.assertGreaterEqual(stats["freed_blocks"], 64)
|
||||||
|
|
||||||
def test_get_blocks_max(self):
|
def test_get_blocks_max(self):
|
||||||
blocks_max = Image.core.get_blocks_max()
|
blocks_max = Image.core.get_blocks_max()
|
||||||
|
@ -102,7 +102,7 @@ class TestCoreMemory(PillowTestCase):
|
||||||
self.assertEqual(blocks_max, i)
|
self.assertEqual(blocks_max, i)
|
||||||
|
|
||||||
# Try to construct new image
|
# Try to construct new image
|
||||||
Image.new('RGB', (10, 10))
|
Image.new("RGB", (10, 10))
|
||||||
|
|
||||||
self.assertRaises(ValueError, Image.core.set_blocks_max, -1)
|
self.assertRaises(ValueError, Image.core.set_blocks_max, -1)
|
||||||
|
|
||||||
|
@ -111,15 +111,15 @@ class TestCoreMemory(PillowTestCase):
|
||||||
Image.core.reset_stats()
|
Image.core.reset_stats()
|
||||||
Image.core.set_blocks_max(128)
|
Image.core.set_blocks_max(128)
|
||||||
Image.core.set_block_size(4096)
|
Image.core.set_block_size(4096)
|
||||||
Image.new('RGB', (256, 256))
|
Image.new("RGB", (256, 256))
|
||||||
Image.new('RGB', (256, 256))
|
Image.new("RGB", (256, 256))
|
||||||
|
|
||||||
stats = Image.core.get_stats()
|
stats = Image.core.get_stats()
|
||||||
self.assertGreaterEqual(stats['new_count'], 2)
|
self.assertGreaterEqual(stats["new_count"], 2)
|
||||||
self.assertGreaterEqual(stats['allocated_blocks'], 64)
|
self.assertGreaterEqual(stats["allocated_blocks"], 64)
|
||||||
self.assertGreaterEqual(stats['reused_blocks'], 64)
|
self.assertGreaterEqual(stats["reused_blocks"], 64)
|
||||||
self.assertEqual(stats['freed_blocks'], 0)
|
self.assertEqual(stats["freed_blocks"], 0)
|
||||||
self.assertEqual(stats['blocks_cached'], 64)
|
self.assertEqual(stats["blocks_cached"], 64)
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy, "images are not collected")
|
@unittest.skipIf(is_pypy, "images are not collected")
|
||||||
def test_clear_cache_stats(self):
|
def test_clear_cache_stats(self):
|
||||||
|
@ -127,55 +127,55 @@ class TestCoreMemory(PillowTestCase):
|
||||||
Image.core.clear_cache()
|
Image.core.clear_cache()
|
||||||
Image.core.set_blocks_max(128)
|
Image.core.set_blocks_max(128)
|
||||||
Image.core.set_block_size(4096)
|
Image.core.set_block_size(4096)
|
||||||
Image.new('RGB', (256, 256))
|
Image.new("RGB", (256, 256))
|
||||||
Image.new('RGB', (256, 256))
|
Image.new("RGB", (256, 256))
|
||||||
# Keep 16 blocks in cache
|
# Keep 16 blocks in cache
|
||||||
Image.core.clear_cache(16)
|
Image.core.clear_cache(16)
|
||||||
|
|
||||||
stats = Image.core.get_stats()
|
stats = Image.core.get_stats()
|
||||||
self.assertGreaterEqual(stats['new_count'], 2)
|
self.assertGreaterEqual(stats["new_count"], 2)
|
||||||
self.assertGreaterEqual(stats['allocated_blocks'], 64)
|
self.assertGreaterEqual(stats["allocated_blocks"], 64)
|
||||||
self.assertGreaterEqual(stats['reused_blocks'], 64)
|
self.assertGreaterEqual(stats["reused_blocks"], 64)
|
||||||
self.assertGreaterEqual(stats['freed_blocks'], 48)
|
self.assertGreaterEqual(stats["freed_blocks"], 48)
|
||||||
self.assertEqual(stats['blocks_cached'], 16)
|
self.assertEqual(stats["blocks_cached"], 16)
|
||||||
|
|
||||||
def test_large_images(self):
|
def test_large_images(self):
|
||||||
Image.core.reset_stats()
|
Image.core.reset_stats()
|
||||||
Image.core.set_blocks_max(0)
|
Image.core.set_blocks_max(0)
|
||||||
Image.core.set_block_size(4096)
|
Image.core.set_block_size(4096)
|
||||||
Image.new('RGB', (2048, 16))
|
Image.new("RGB", (2048, 16))
|
||||||
Image.core.clear_cache()
|
Image.core.clear_cache()
|
||||||
|
|
||||||
stats = Image.core.get_stats()
|
stats = Image.core.get_stats()
|
||||||
self.assertGreaterEqual(stats['new_count'], 1)
|
self.assertGreaterEqual(stats["new_count"], 1)
|
||||||
self.assertGreaterEqual(stats['allocated_blocks'], 16)
|
self.assertGreaterEqual(stats["allocated_blocks"], 16)
|
||||||
self.assertGreaterEqual(stats['reused_blocks'], 0)
|
self.assertGreaterEqual(stats["reused_blocks"], 0)
|
||||||
self.assertEqual(stats['blocks_cached'], 0)
|
self.assertEqual(stats["blocks_cached"], 0)
|
||||||
if not is_pypy:
|
if not is_pypy:
|
||||||
self.assertGreaterEqual(stats['freed_blocks'], 16)
|
self.assertGreaterEqual(stats["freed_blocks"], 16)
|
||||||
|
|
||||||
|
|
||||||
class TestEnvVars(PillowTestCase):
|
class TestEnvVars(PillowTestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# Restore default values
|
# Restore default values
|
||||||
Image.core.set_alignment(1)
|
Image.core.set_alignment(1)
|
||||||
Image.core.set_block_size(1024*1024)
|
Image.core.set_block_size(1024 * 1024)
|
||||||
Image.core.set_blocks_max(0)
|
Image.core.set_blocks_max(0)
|
||||||
Image.core.clear_cache()
|
Image.core.clear_cache()
|
||||||
|
|
||||||
def test_units(self):
|
def test_units(self):
|
||||||
Image._apply_env_variables({'PILLOW_BLOCKS_MAX': '2K'})
|
Image._apply_env_variables({"PILLOW_BLOCKS_MAX": "2K"})
|
||||||
self.assertEqual(Image.core.get_blocks_max(), 2*1024)
|
self.assertEqual(Image.core.get_blocks_max(), 2 * 1024)
|
||||||
Image._apply_env_variables({'PILLOW_BLOCK_SIZE': '2m'})
|
Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"})
|
||||||
self.assertEqual(Image.core.get_block_size(), 2*1024*1024)
|
self.assertEqual(Image.core.get_block_size(), 2 * 1024 * 1024)
|
||||||
|
|
||||||
def test_warnings(self):
|
def test_warnings(self):
|
||||||
self.assert_warning(
|
self.assert_warning(
|
||||||
UserWarning, Image._apply_env_variables,
|
UserWarning, Image._apply_env_variables, {"PILLOW_ALIGNMENT": "15"}
|
||||||
{'PILLOW_ALIGNMENT': '15'})
|
)
|
||||||
self.assert_warning(
|
self.assert_warning(
|
||||||
UserWarning, Image._apply_env_variables,
|
UserWarning, Image._apply_env_variables, {"PILLOW_BLOCK_SIZE": "1024"}
|
||||||
{'PILLOW_BLOCK_SIZE': '1024'})
|
)
|
||||||
self.assert_warning(
|
self.assert_warning(
|
||||||
UserWarning, Image._apply_env_variables,
|
UserWarning, Image._apply_env_variables, {"PILLOW_BLOCKS_MAX": "wat"}
|
||||||
{'PILLOW_BLOCKS_MAX': 'wat'})
|
)
|
||||||
|
|
|
@ -8,7 +8,6 @@ ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS
|
||||||
|
|
||||||
|
|
||||||
class TestDecompressionBomb(PillowTestCase):
|
class TestDecompressionBomb(PillowTestCase):
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
|
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
|
||||||
|
|
||||||
|
@ -33,20 +32,17 @@ class TestDecompressionBomb(PillowTestCase):
|
||||||
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
|
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
|
||||||
self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1)
|
self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1)
|
||||||
|
|
||||||
self.assert_warning(Image.DecompressionBombWarning,
|
self.assert_warning(Image.DecompressionBombWarning, Image.open, TEST_FILE)
|
||||||
Image.open, TEST_FILE)
|
|
||||||
|
|
||||||
def test_exception(self):
|
def test_exception(self):
|
||||||
# Set limit to trigger exception on the test file
|
# Set limit to trigger exception on the test file
|
||||||
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
|
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
|
||||||
self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1)
|
self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1)
|
||||||
|
|
||||||
self.assertRaises(Image.DecompressionBombError,
|
self.assertRaises(Image.DecompressionBombError, lambda: Image.open(TEST_FILE))
|
||||||
lambda: Image.open(TEST_FILE))
|
|
||||||
|
|
||||||
|
|
||||||
class TestDecompressionCrop(PillowTestCase):
|
class TestDecompressionCrop(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.src = hopper()
|
self.src = hopper()
|
||||||
Image.MAX_IMAGE_PIXELS = self.src.height * self.src.width * 4 - 1
|
Image.MAX_IMAGE_PIXELS = self.src.height * self.src.width * 4 - 1
|
||||||
|
@ -58,21 +54,17 @@ class TestDecompressionCrop(PillowTestCase):
|
||||||
# Crops can extend the extents, therefore we should have the
|
# Crops can extend the extents, therefore we should have the
|
||||||
# same decompression bomb warnings on them.
|
# same decompression bomb warnings on them.
|
||||||
box = (0, 0, self.src.width * 2, self.src.height * 2)
|
box = (0, 0, self.src.width * 2, self.src.height * 2)
|
||||||
self.assert_warning(Image.DecompressionBombWarning,
|
self.assert_warning(Image.DecompressionBombWarning, self.src.crop, box)
|
||||||
self.src.crop, box)
|
|
||||||
|
|
||||||
def test_crop_decompression_checks(self):
|
def test_crop_decompression_checks(self):
|
||||||
|
|
||||||
im = Image.new("RGB", (100, 100))
|
im = Image.new("RGB", (100, 100))
|
||||||
|
|
||||||
good_values = ((-9999, -9999, -9990, -9990),
|
good_values = ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990))
|
||||||
(-999, -999, -990, -990))
|
|
||||||
|
|
||||||
warning_values = ((-160, -160, 99, 99),
|
warning_values = ((-160, -160, 99, 99), (160, 160, -99, -99))
|
||||||
(160, 160, -99, -99))
|
|
||||||
|
|
||||||
error_values = ((-99909, -99990, 99999, 99999),
|
error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))
|
||||||
(99909, 99990, -99999, -99999))
|
|
||||||
|
|
||||||
for value in good_values:
|
for value in good_values:
|
||||||
self.assertEqual(im.crop(value).size, (9, 9))
|
self.assertEqual(im.crop(value).size, (9, 9))
|
||||||
|
|
|
@ -8,41 +8,36 @@ from PIL import features
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
|
||||||
|
|
||||||
class TestFeatures(PillowTestCase):
|
class TestFeatures(PillowTestCase):
|
||||||
|
|
||||||
def test_check(self):
|
def test_check(self):
|
||||||
# Check the correctness of the convenience function
|
# Check the correctness of the convenience function
|
||||||
for module in features.modules:
|
for module in features.modules:
|
||||||
self.assertEqual(features.check_module(module),
|
self.assertEqual(features.check_module(module), features.check(module))
|
||||||
features.check(module))
|
|
||||||
for codec in features.codecs:
|
for codec in features.codecs:
|
||||||
self.assertEqual(features.check_codec(codec),
|
self.assertEqual(features.check_codec(codec), features.check(codec))
|
||||||
features.check(codec))
|
|
||||||
for feature in features.features:
|
for feature in features.features:
|
||||||
self.assertEqual(features.check_feature(feature),
|
self.assertEqual(features.check_feature(feature), features.check(feature))
|
||||||
features.check(feature))
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
||||||
def test_webp_transparency(self):
|
def test_webp_transparency(self):
|
||||||
self.assertEqual(features.check('transp_webp'),
|
self.assertEqual(
|
||||||
not _webp.WebPDecoderBuggyAlpha())
|
features.check("transp_webp"), not _webp.WebPDecoderBuggyAlpha()
|
||||||
self.assertEqual(features.check('transp_webp'),
|
)
|
||||||
_webp.HAVE_TRANSPARENCY)
|
self.assertEqual(features.check("transp_webp"), _webp.HAVE_TRANSPARENCY)
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
||||||
def test_webp_mux(self):
|
def test_webp_mux(self):
|
||||||
self.assertEqual(features.check('webp_mux'),
|
self.assertEqual(features.check("webp_mux"), _webp.HAVE_WEBPMUX)
|
||||||
_webp.HAVE_WEBPMUX)
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
||||||
def test_webp_anim(self):
|
def test_webp_anim(self):
|
||||||
self.assertEqual(features.check('webp_anim'),
|
self.assertEqual(features.check("webp_anim"), _webp.HAVE_WEBPANIM)
|
||||||
_webp.HAVE_WEBPANIM)
|
|
||||||
|
|
||||||
def test_check_modules(self):
|
def test_check_modules(self):
|
||||||
for feature in features.modules:
|
for feature in features.modules:
|
||||||
|
|
|
@ -5,11 +5,10 @@ import io
|
||||||
|
|
||||||
|
|
||||||
class TestFileBmp(PillowTestCase):
|
class TestFileBmp(PillowTestCase):
|
||||||
|
|
||||||
def roundtrip(self, im):
|
def roundtrip(self, im):
|
||||||
outfile = self.tempfile("temp.bmp")
|
outfile = self.tempfile("temp.bmp")
|
||||||
|
|
||||||
im.save(outfile, 'BMP')
|
im.save(outfile, "BMP")
|
||||||
|
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
reloaded.load()
|
reloaded.load()
|
||||||
|
@ -28,8 +27,7 @@ class TestFileBmp(PillowTestCase):
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, BmpImagePlugin.BmpImageFile, fp)
|
||||||
BmpImagePlugin.BmpImageFile, fp)
|
|
||||||
|
|
||||||
def test_save_to_bytes(self):
|
def test_save_to_bytes(self):
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
|
@ -62,27 +60,27 @@ class TestFileBmp(PillowTestCase):
|
||||||
im = Image.open("Tests/images/hopper.bmp")
|
im = Image.open("Tests/images/hopper.bmp")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
im.save(outfile, 'JPEG', dpi=im.info['dpi'])
|
im.save(outfile, "JPEG", dpi=im.info["dpi"])
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
reloaded.load()
|
reloaded.load()
|
||||||
self.assertEqual(im.info['dpi'], reloaded.info['dpi'])
|
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
|
||||||
self.assertEqual(im.size, reloaded.size)
|
self.assertEqual(im.size, reloaded.size)
|
||||||
self.assertEqual(reloaded.format, "JPEG")
|
self.assertEqual(reloaded.format, "JPEG")
|
||||||
|
|
||||||
def test_load_dpi_rounding(self):
|
def test_load_dpi_rounding(self):
|
||||||
# Round up
|
# Round up
|
||||||
im = Image.open('Tests/images/hopper.bmp')
|
im = Image.open("Tests/images/hopper.bmp")
|
||||||
self.assertEqual(im.info["dpi"], (96, 96))
|
self.assertEqual(im.info["dpi"], (96, 96))
|
||||||
|
|
||||||
# Round down
|
# Round down
|
||||||
im = Image.open('Tests/images/hopper_roundDown.bmp')
|
im = Image.open("Tests/images/hopper_roundDown.bmp")
|
||||||
self.assertEqual(im.info["dpi"], (72, 72))
|
self.assertEqual(im.info["dpi"], (72, 72))
|
||||||
|
|
||||||
def test_save_dpi_rounding(self):
|
def test_save_dpi_rounding(self):
|
||||||
outfile = self.tempfile("temp.bmp")
|
outfile = self.tempfile("temp.bmp")
|
||||||
im = Image.open('Tests/images/hopper.bmp')
|
im = Image.open("Tests/images/hopper.bmp")
|
||||||
|
|
||||||
im.save(outfile, dpi=(72.2, 72.2))
|
im.save(outfile, dpi=(72.2, 72.2))
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
|
@ -94,17 +92,17 @@ class TestFileBmp(PillowTestCase):
|
||||||
|
|
||||||
def test_load_dib(self):
|
def test_load_dib(self):
|
||||||
# test for #1293, Imagegrab returning Unsupported Bitfields Format
|
# test for #1293, Imagegrab returning Unsupported Bitfields Format
|
||||||
im = Image.open('Tests/images/clipboard.dib')
|
im = Image.open("Tests/images/clipboard.dib")
|
||||||
self.assertEqual(im.format, "DIB")
|
self.assertEqual(im.format, "DIB")
|
||||||
self.assertEqual(im.get_format_mimetype(), "image/bmp")
|
self.assertEqual(im.get_format_mimetype(), "image/bmp")
|
||||||
|
|
||||||
target = Image.open('Tests/images/clipboard_target.png')
|
target = Image.open("Tests/images/clipboard_target.png")
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
|
|
||||||
def test_save_dib(self):
|
def test_save_dib(self):
|
||||||
outfile = self.tempfile("temp.dib")
|
outfile = self.tempfile("temp.dib")
|
||||||
|
|
||||||
im = Image.open('Tests/images/clipboard.dib')
|
im = Image.open("Tests/images/clipboard.dib")
|
||||||
im.save(outfile)
|
im.save(outfile)
|
||||||
|
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
|
||||||
|
|
||||||
|
|
||||||
class TestFileBufrStub(PillowTestCase):
|
class TestFileBufrStub(PillowTestCase):
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Act
|
# Act
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
@ -23,8 +22,9 @@ class TestFileBufrStub(PillowTestCase):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(
|
||||||
BufrStubImagePlugin.BufrStubImageFile, invalid_file)
|
SyntaxError, BufrStubImagePlugin.BufrStubImageFile, invalid_file
|
||||||
|
)
|
||||||
|
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -7,7 +7,6 @@ TEST_FILE = "Tests/images/dummy.container"
|
||||||
|
|
||||||
|
|
||||||
class TestFileContainer(PillowTestCase):
|
class TestFileContainer(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
dir(Image)
|
dir(Image)
|
||||||
dir(ContainerIO)
|
dir(ContainerIO)
|
||||||
|
@ -106,14 +105,16 @@ class TestFileContainer(PillowTestCase):
|
||||||
|
|
||||||
def test_readlines(self):
|
def test_readlines(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
expected = ["This is line 1\n",
|
expected = [
|
||||||
"This is line 2\n",
|
"This is line 1\n",
|
||||||
"This is line 3\n",
|
"This is line 2\n",
|
||||||
"This is line 4\n",
|
"This is line 3\n",
|
||||||
"This is line 5\n",
|
"This is line 4\n",
|
||||||
"This is line 6\n",
|
"This is line 5\n",
|
||||||
"This is line 7\n",
|
"This is line 6\n",
|
||||||
"This is line 8\n"]
|
"This is line 7\n",
|
||||||
|
"This is line 8\n",
|
||||||
|
]
|
||||||
with open(TEST_FILE) as fh:
|
with open(TEST_FILE) as fh:
|
||||||
container = ContainerIO.ContainerIO(fh, 0, 120)
|
container = ContainerIO.ContainerIO(fh, 0, 120)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/deerstalker.cur"
|
||||||
|
|
||||||
|
|
||||||
class TestFileCur(PillowTestCase):
|
class TestFileCur(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
|
||||||
|
@ -20,8 +19,7 @@ class TestFileCur(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, CurImagePlugin.CurImageFile, invalid_file)
|
||||||
CurImagePlugin.CurImageFile, invalid_file)
|
|
||||||
|
|
||||||
no_cursors_file = "Tests/images/no_cursors.cur"
|
no_cursors_file = "Tests/images/no_cursors.cur"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ TEST_FILE = "Tests/images/hopper.dcx"
|
||||||
|
|
||||||
|
|
||||||
class TestFileDcx(PillowTestCase):
|
class TestFileDcx(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
||||||
|
@ -24,12 +23,12 @@ class TestFileDcx(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, DcxImagePlugin.DcxImageFile, fp)
|
||||||
DcxImagePlugin.DcxImageFile, fp)
|
|
||||||
|
|
||||||
def test_tell(self):
|
def test_tell(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -55,7 +54,7 @@ class TestFileDcx(PillowTestCase):
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_seek_too_far(self):
|
def test_seek_too_far(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -15,7 +15,7 @@ class TestFileDds(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity_dxt1(self):
|
def test_sanity_dxt1(self):
|
||||||
"""Check DXT1 images can be opened"""
|
"""Check DXT1 images can be opened"""
|
||||||
target = Image.open(TEST_FILE_DXT1.replace('.dds', '.png'))
|
target = Image.open(TEST_FILE_DXT1.replace(".dds", ".png"))
|
||||||
|
|
||||||
im = Image.open(TEST_FILE_DXT1)
|
im = Image.open(TEST_FILE_DXT1)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -24,12 +24,12 @@ class TestFileDds(PillowTestCase):
|
||||||
self.assertEqual(im.mode, "RGBA")
|
self.assertEqual(im.mode, "RGBA")
|
||||||
self.assertEqual(im.size, (256, 256))
|
self.assertEqual(im.size, (256, 256))
|
||||||
|
|
||||||
self.assert_image_equal(target.convert('RGBA'), im)
|
self.assert_image_equal(target.convert("RGBA"), im)
|
||||||
|
|
||||||
def test_sanity_dxt5(self):
|
def test_sanity_dxt5(self):
|
||||||
"""Check DXT5 images can be opened"""
|
"""Check DXT5 images can be opened"""
|
||||||
|
|
||||||
target = Image.open(TEST_FILE_DXT5.replace('.dds', '.png'))
|
target = Image.open(TEST_FILE_DXT5.replace(".dds", ".png"))
|
||||||
|
|
||||||
im = Image.open(TEST_FILE_DXT5)
|
im = Image.open(TEST_FILE_DXT5)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -43,7 +43,7 @@ class TestFileDds(PillowTestCase):
|
||||||
def test_sanity_dxt3(self):
|
def test_sanity_dxt3(self):
|
||||||
"""Check DXT3 images can be opened"""
|
"""Check DXT3 images can be opened"""
|
||||||
|
|
||||||
target = Image.open(TEST_FILE_DXT3.replace('.dds', '.png'))
|
target = Image.open(TEST_FILE_DXT3.replace(".dds", ".png"))
|
||||||
|
|
||||||
im = Image.open(TEST_FILE_DXT3)
|
im = Image.open(TEST_FILE_DXT3)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -57,7 +57,7 @@ class TestFileDds(PillowTestCase):
|
||||||
def test_dx10_bc7(self):
|
def test_dx10_bc7(self):
|
||||||
"""Check DX10 images can be opened"""
|
"""Check DX10 images can be opened"""
|
||||||
|
|
||||||
target = Image.open(TEST_FILE_DX10_BC7.replace('.dds', '.png'))
|
target = Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png"))
|
||||||
|
|
||||||
im = Image.open(TEST_FILE_DX10_BC7)
|
im = Image.open(TEST_FILE_DX10_BC7)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -69,13 +69,16 @@ class TestFileDds(PillowTestCase):
|
||||||
self.assert_image_equal(target, im)
|
self.assert_image_equal(target, im)
|
||||||
|
|
||||||
def test_unimplemented_dxgi_format(self):
|
def test_unimplemented_dxgi_format(self):
|
||||||
self.assertRaises(NotImplementedError, Image.open,
|
self.assertRaises(
|
||||||
"Tests/images/unimplemented_dxgi_format.dds")
|
NotImplementedError,
|
||||||
|
Image.open,
|
||||||
|
"Tests/images/unimplemented_dxgi_format.dds",
|
||||||
|
)
|
||||||
|
|
||||||
def test_uncompressed_rgb(self):
|
def test_uncompressed_rgb(self):
|
||||||
"""Check uncompressed RGB images can be opened"""
|
"""Check uncompressed RGB images can be opened"""
|
||||||
|
|
||||||
target = Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace('.dds', '.png'))
|
target = Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png"))
|
||||||
|
|
||||||
im = Image.open(TEST_FILE_UNCOMPRESSED_RGB)
|
im = Image.open(TEST_FILE_UNCOMPRESSED_RGB)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -110,7 +113,7 @@ class TestFileDds(PillowTestCase):
|
||||||
|
|
||||||
def test_short_header(self):
|
def test_short_header(self):
|
||||||
""" Check a short header"""
|
""" Check a short header"""
|
||||||
with open(TEST_FILE_DXT5, 'rb') as f:
|
with open(TEST_FILE_DXT5, "rb") as f:
|
||||||
img_file = f.read()
|
img_file = f.read()
|
||||||
|
|
||||||
def short_header():
|
def short_header():
|
||||||
|
@ -121,7 +124,7 @@ class TestFileDds(PillowTestCase):
|
||||||
def test_short_file(self):
|
def test_short_file(self):
|
||||||
""" Check that the appropriate error is thrown for a short file"""
|
""" Check that the appropriate error is thrown for a short file"""
|
||||||
|
|
||||||
with open(TEST_FILE_DXT5, 'rb') as f:
|
with open(TEST_FILE_DXT5, "rb") as f:
|
||||||
img_file = f.read()
|
img_file = f.read()
|
||||||
|
|
||||||
def short_file():
|
def short_file():
|
||||||
|
@ -131,5 +134,8 @@ class TestFileDds(PillowTestCase):
|
||||||
self.assertRaises(IOError, short_file)
|
self.assertRaises(IOError, short_file)
|
||||||
|
|
||||||
def test_unimplemented_pixel_format(self):
|
def test_unimplemented_pixel_format(self):
|
||||||
self.assertRaises(NotImplementedError, Image.open,
|
self.assertRaises(
|
||||||
"Tests/images/unimplemented_pixel_format.dds")
|
NotImplementedError,
|
||||||
|
Image.open,
|
||||||
|
"Tests/images/unimplemented_pixel_format.dds",
|
||||||
|
)
|
||||||
|
|
|
@ -21,7 +21,6 @@ file3 = "Tests/images/binary_preview_map.eps"
|
||||||
|
|
||||||
|
|
||||||
class TestFileEps(PillowTestCase):
|
class TestFileEps(PillowTestCase):
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
# Regular scale
|
# Regular scale
|
||||||
|
@ -53,8 +52,7 @@ class TestFileEps(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, EpsImagePlugin.EpsImageFile, invalid_file)
|
||||||
EpsImagePlugin.EpsImageFile, invalid_file)
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
def test_cmyk(self):
|
def test_cmyk(self):
|
||||||
|
@ -67,8 +65,8 @@ class TestFileEps(PillowTestCase):
|
||||||
cmyk_image.load()
|
cmyk_image.load()
|
||||||
self.assertEqual(cmyk_image.mode, "RGB")
|
self.assertEqual(cmyk_image.mode, "RGB")
|
||||||
|
|
||||||
if 'jpeg_decoder' in dir(Image.core):
|
if "jpeg_decoder" in dir(Image.core):
|
||||||
target = Image.open('Tests/images/pil_sample_rgb.jpg')
|
target = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||||
self.assert_image_similar(cmyk_image, target, 10)
|
self.assert_image_similar(cmyk_image, target, 10)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
|
@ -86,19 +84,19 @@ class TestFileEps(PillowTestCase):
|
||||||
def test_file_object(self):
|
def test_file_object(self):
|
||||||
# issue 479
|
# issue 479
|
||||||
image1 = Image.open(file1)
|
image1 = Image.open(file1)
|
||||||
with open(self.tempfile('temp_file.eps'), 'wb') as fh:
|
with open(self.tempfile("temp_file.eps"), "wb") as fh:
|
||||||
image1.save(fh, 'EPS')
|
image1.save(fh, "EPS")
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
def test_iobase_object(self):
|
def test_iobase_object(self):
|
||||||
# issue 479
|
# issue 479
|
||||||
image1 = Image.open(file1)
|
image1 = Image.open(file1)
|
||||||
with io.open(self.tempfile('temp_iobase.eps'), 'wb') as fh:
|
with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh:
|
||||||
image1.save(fh, 'EPS')
|
image1.save(fh, "EPS")
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
def test_bytesio_object(self):
|
def test_bytesio_object(self):
|
||||||
with open(file1, 'rb') as f:
|
with open(file1, "rb") as f:
|
||||||
img_bytes = io.BytesIO(f.read())
|
img_bytes = io.BytesIO(f.read())
|
||||||
|
|
||||||
img = Image.open(img_bytes)
|
img = Image.open(img_bytes)
|
||||||
|
@ -110,7 +108,7 @@ class TestFileEps(PillowTestCase):
|
||||||
|
|
||||||
def test_image_mode_not_supported(self):
|
def test_image_mode_not_supported(self):
|
||||||
im = hopper("RGBA")
|
im = hopper("RGBA")
|
||||||
tmpfile = self.tempfile('temp.eps')
|
tmpfile = self.tempfile("temp.eps")
|
||||||
self.assertRaises(ValueError, im.save, tmpfile)
|
self.assertRaises(ValueError, im.save, tmpfile)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
|
@ -195,33 +193,33 @@ class TestFileEps(PillowTestCase):
|
||||||
Image.open(file3)
|
Image.open(file3)
|
||||||
|
|
||||||
def _test_readline(self, t, ending):
|
def _test_readline(self, t, ending):
|
||||||
ending = "Failure with line ending: %s" % ("".join(
|
ending = "Failure with line ending: %s" % (
|
||||||
"%s" % ord(s)
|
"".join("%s" % ord(s) for s in ending)
|
||||||
for s in ending))
|
)
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'something', ending)
|
self.assertEqual(t.readline().strip("\r\n"), "something", ending)
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'else', ending)
|
self.assertEqual(t.readline().strip("\r\n"), "else", ending)
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'baz', ending)
|
self.assertEqual(t.readline().strip("\r\n"), "baz", ending)
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'bif', ending)
|
self.assertEqual(t.readline().strip("\r\n"), "bif", ending)
|
||||||
|
|
||||||
def _test_readline_io_psfile(self, test_string, ending):
|
def _test_readline_io_psfile(self, test_string, ending):
|
||||||
f = io.BytesIO(test_string.encode('latin-1'))
|
f = io.BytesIO(test_string.encode("latin-1"))
|
||||||
t = EpsImagePlugin.PSFile(f)
|
t = EpsImagePlugin.PSFile(f)
|
||||||
self._test_readline(t, ending)
|
self._test_readline(t, ending)
|
||||||
|
|
||||||
def _test_readline_file_psfile(self, test_string, ending):
|
def _test_readline_file_psfile(self, test_string, ending):
|
||||||
f = self.tempfile('temp.txt')
|
f = self.tempfile("temp.txt")
|
||||||
with open(f, 'wb') as w:
|
with open(f, "wb") as w:
|
||||||
w.write(test_string.encode('latin-1'))
|
w.write(test_string.encode("latin-1"))
|
||||||
|
|
||||||
with open(f, 'rb') as r:
|
with open(f, "rb") as r:
|
||||||
t = EpsImagePlugin.PSFile(r)
|
t = EpsImagePlugin.PSFile(r)
|
||||||
self._test_readline(t, ending)
|
self._test_readline(t, ending)
|
||||||
|
|
||||||
def test_readline(self):
|
def test_readline(self):
|
||||||
# check all the freaking line endings possible from the spec
|
# check all the freaking line endings possible from the spec
|
||||||
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
|
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
|
||||||
line_endings = ['\r\n', '\n', '\n\r', '\r']
|
line_endings = ["\r\n", "\n", "\n\r", "\r"]
|
||||||
strings = ['something', 'else', 'baz', 'bif']
|
strings = ["something", "else", "baz", "bif"]
|
||||||
|
|
||||||
for ending in line_endings:
|
for ending in line_endings:
|
||||||
s = ending.join(strings)
|
s = ending.join(strings)
|
||||||
|
@ -231,10 +229,12 @@ class TestFileEps(PillowTestCase):
|
||||||
def test_open_eps(self):
|
def test_open_eps(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/1104
|
# https://github.com/python-pillow/Pillow/issues/1104
|
||||||
# Arrange
|
# Arrange
|
||||||
FILES = ["Tests/images/illu10_no_preview.eps",
|
FILES = [
|
||||||
"Tests/images/illu10_preview.eps",
|
"Tests/images/illu10_no_preview.eps",
|
||||||
"Tests/images/illuCS6_no_preview.eps",
|
"Tests/images/illu10_preview.eps",
|
||||||
"Tests/images/illuCS6_preview.eps"]
|
"Tests/images/illuCS6_no_preview.eps",
|
||||||
|
"Tests/images/illuCS6_preview.eps",
|
||||||
|
]
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
for filename in FILES:
|
for filename in FILES:
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hopper.fits"
|
||||||
|
|
||||||
|
|
||||||
class TestFileFitsStub(PillowTestCase):
|
class TestFileFitsStub(PillowTestCase):
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Act
|
# Act
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
@ -23,8 +22,9 @@ class TestFileFitsStub(PillowTestCase):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(
|
||||||
FitsStubImagePlugin.FITSStubImageFile, invalid_file)
|
SyntaxError, FitsStubImagePlugin.FITSStubImageFile, invalid_file
|
||||||
|
)
|
||||||
|
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -42,5 +42,5 @@ class TestFileFitsStub(PillowTestCase):
|
||||||
# Act / Assert: stub cannot save without an implemented handler
|
# Act / Assert: stub cannot save without an implemented handler
|
||||||
self.assertRaises(IOError, im.save, dummy_filename)
|
self.assertRaises(IOError, im.save, dummy_filename)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
IOError,
|
IOError, FitsStubImagePlugin._save, im, dummy_fp, dummy_filename
|
||||||
FitsStubImagePlugin._save, im, dummy_fp, dummy_filename)
|
)
|
||||||
|
|
|
@ -11,7 +11,6 @@ animated_test_file = "Tests/images/a.fli"
|
||||||
|
|
||||||
|
|
||||||
class TestFileFli(PillowTestCase):
|
class TestFileFli(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(static_test_file)
|
im = Image.open(static_test_file)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -31,6 +30,7 @@ class TestFileFli(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(static_test_file)
|
im = Image.open(static_test_file)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_tell(self):
|
def test_tell(self):
|
||||||
|
@ -46,8 +46,7 @@ class TestFileFli(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
|
||||||
FliImagePlugin.FliImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(static_test_file)
|
im = Image.open(static_test_file)
|
||||||
|
@ -67,7 +66,7 @@ class TestFileFli(PillowTestCase):
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_seek_tell(self):
|
def test_seek_tell(self):
|
||||||
im = Image.open(animated_test_file)
|
im = Image.open(animated_test_file)
|
||||||
|
|
|
@ -10,14 +10,11 @@ else:
|
||||||
|
|
||||||
@unittest.skipUnless(olefile_installed, "olefile package not installed")
|
@unittest.skipUnless(olefile_installed, "olefile package not installed")
|
||||||
class TestFileFpx(PillowTestCase):
|
class TestFileFpx(PillowTestCase):
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
# Test an invalid OLE file
|
# Test an invalid OLE file
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, invalid_file)
|
||||||
FpxImagePlugin.FpxImageFile, invalid_file)
|
|
||||||
|
|
||||||
# Test a valid OLE file, but not an FPX file
|
# Test a valid OLE file, but not an FPX file
|
||||||
ole_file = "Tests/images/test-ole-file.doc"
|
ole_file = "Tests/images/test-ole-file.doc"
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, ole_file)
|
||||||
FpxImagePlugin.FpxImageFile, ole_file)
|
|
||||||
|
|
|
@ -3,14 +3,13 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestFileFtex(PillowTestCase):
|
class TestFileFtex(PillowTestCase):
|
||||||
|
|
||||||
def test_load_raw(self):
|
def test_load_raw(self):
|
||||||
im = Image.open('Tests/images/ftex_uncompressed.ftu')
|
im = Image.open("Tests/images/ftex_uncompressed.ftu")
|
||||||
target = Image.open('Tests/images/ftex_uncompressed.png')
|
target = Image.open("Tests/images/ftex_uncompressed.png")
|
||||||
|
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
|
|
||||||
def test_load_dxt1(self):
|
def test_load_dxt1(self):
|
||||||
im = Image.open('Tests/images/ftex_dxt1.ftc')
|
im = Image.open("Tests/images/ftex_dxt1.ftc")
|
||||||
target = Image.open('Tests/images/ftex_dxt1.png')
|
target = Image.open("Tests/images/ftex_dxt1.png")
|
||||||
self.assert_image_similar(im, target.convert('RGBA'), 15)
|
self.assert_image_similar(im, target.convert("RGBA"), 15)
|
||||||
|
|
|
@ -4,16 +4,14 @@ from PIL import Image, GbrImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFileGbr(PillowTestCase):
|
class TestFileGbr(PillowTestCase):
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file)
|
||||||
GbrImagePlugin.GbrImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_gbr_file(self):
|
def test_gbr_file(self):
|
||||||
im = Image.open('Tests/images/gbr.gbr')
|
im = Image.open("Tests/images/gbr.gbr")
|
||||||
|
|
||||||
target = Image.open('Tests/images/gbr.png')
|
target = Image.open("Tests/images/gbr.png")
|
||||||
|
|
||||||
self.assert_image_equal(target, im)
|
self.assert_image_equal(target, im)
|
||||||
|
|
|
@ -6,15 +6,13 @@ TEST_GD_FILE = "Tests/images/hopper.gd"
|
||||||
|
|
||||||
|
|
||||||
class TestFileGd(PillowTestCase):
|
class TestFileGd(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = GdImageFile.open(TEST_GD_FILE)
|
im = GdImageFile.open(TEST_GD_FILE)
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "GD")
|
self.assertEqual(im.format, "GD")
|
||||||
|
|
||||||
def test_bad_mode(self):
|
def test_bad_mode(self):
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, GdImageFile.open, TEST_GD_FILE, "bad mode")
|
||||||
GdImageFile.open, TEST_GD_FILE, 'bad mode')
|
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
|
@ -6,6 +6,7 @@ from io import BytesIO
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
@ -20,7 +21,6 @@ with open(TEST_GIF, "rb") as f:
|
||||||
|
|
||||||
|
|
||||||
class TestFileGif(PillowTestCase):
|
class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "gif_encoder" not in codecs or "gif_decoder" not in codecs:
|
if "gif_encoder" not in codecs or "gif_decoder" not in codecs:
|
||||||
self.skipTest("gif support not available") # can this happen?
|
self.skipTest("gif support not available") # can this happen?
|
||||||
|
@ -37,13 +37,13 @@ class TestFileGif(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(TEST_GIF)
|
im = Image.open(TEST_GIF)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, GifImagePlugin.GifImageFile, invalid_file)
|
||||||
GifImagePlugin.GifImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_optimize(self):
|
def test_optimize(self):
|
||||||
def test_grayscale(optimize):
|
def test_grayscale(optimize):
|
||||||
|
@ -70,19 +70,22 @@ class TestFileGif(PillowTestCase):
|
||||||
# Check for correctness after conversion back to RGB
|
# Check for correctness after conversion back to RGB
|
||||||
def check(colors, size, expected_palette_length):
|
def check(colors, size, expected_palette_length):
|
||||||
# make an image with empty colors in the start of the palette range
|
# make an image with empty colors in the start of the palette range
|
||||||
im = Image.frombytes('P', (colors, colors),
|
im = Image.frombytes(
|
||||||
bytes(bytearray(range(256-colors, 256))*colors))
|
"P",
|
||||||
|
(colors, colors),
|
||||||
|
bytes(bytearray(range(256 - colors, 256)) * colors),
|
||||||
|
)
|
||||||
im = im.resize((size, size))
|
im = im.resize((size, size))
|
||||||
outfile = BytesIO()
|
outfile = BytesIO()
|
||||||
im.save(outfile, 'GIF')
|
im.save(outfile, "GIF")
|
||||||
outfile.seek(0)
|
outfile.seek(0)
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
|
|
||||||
# check palette length
|
# check palette length
|
||||||
palette_length = max(i+1 for i, v in enumerate(reloaded.histogram()) if v)
|
palette_length = max(i + 1 for i, v in enumerate(reloaded.histogram()) if v)
|
||||||
self.assertEqual(expected_palette_length, palette_length)
|
self.assertEqual(expected_palette_length, palette_length)
|
||||||
|
|
||||||
self.assert_image_equal(im.convert('RGB'), reloaded.convert('RGB'))
|
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
|
||||||
|
|
||||||
# These do optimize the palette
|
# These do optimize the palette
|
||||||
check(128, 511, 128)
|
check(128, 511, 128)
|
||||||
|
@ -106,79 +109,76 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertEqual(im.mode, "L")
|
self.assertEqual(im.mode, "L")
|
||||||
|
|
||||||
def test_roundtrip(self):
|
def test_roundtrip(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = hopper()
|
im = hopper()
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assert_image_similar(reread.convert('RGB'), im, 50)
|
self.assert_image_similar(reread.convert("RGB"), im, 50)
|
||||||
|
|
||||||
def test_roundtrip2(self):
|
def test_roundtrip2(self):
|
||||||
# see https://github.com/python-pillow/Pillow/issues/403
|
# see https://github.com/python-pillow/Pillow/issues/403
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = Image.open(TEST_GIF)
|
im = Image.open(TEST_GIF)
|
||||||
im2 = im.copy()
|
im2 = im.copy()
|
||||||
im2.save(out)
|
im2.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assert_image_similar(reread.convert('RGB'), hopper(), 50)
|
self.assert_image_similar(reread.convert("RGB"), hopper(), 50)
|
||||||
|
|
||||||
def test_roundtrip_save_all(self):
|
def test_roundtrip_save_all(self):
|
||||||
# Single frame image
|
# Single frame image
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = hopper()
|
im = hopper()
|
||||||
im.save(out, save_all=True)
|
im.save(out, save_all=True)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assert_image_similar(reread.convert('RGB'), im, 50)
|
self.assert_image_similar(reread.convert("RGB"), im, 50)
|
||||||
|
|
||||||
# Multiframe image
|
# Multiframe image
|
||||||
im = Image.open("Tests/images/dispose_bgnd.gif")
|
im = Image.open("Tests/images/dispose_bgnd.gif")
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out, save_all=True)
|
im.save(out, save_all=True)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.n_frames, 5)
|
self.assertEqual(reread.n_frames, 5)
|
||||||
|
|
||||||
def test_headers_saving_for_animated_gifs(self):
|
def test_headers_saving_for_animated_gifs(self):
|
||||||
important_headers = ['background', 'version', 'duration', 'loop']
|
important_headers = ["background", "version", "duration", "loop"]
|
||||||
# Multiframe image
|
# Multiframe image
|
||||||
im = Image.open("Tests/images/dispose_bgnd.gif")
|
im = Image.open("Tests/images/dispose_bgnd.gif")
|
||||||
|
|
||||||
info = im.info.copy()
|
info = im.info.copy()
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out, save_all=True)
|
im.save(out, save_all=True)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
for header in important_headers:
|
for header in important_headers:
|
||||||
self.assertEqual(
|
self.assertEqual(info[header], reread.info[header])
|
||||||
info[header],
|
|
||||||
reread.info[header]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_palette_handling(self):
|
def test_palette_handling(self):
|
||||||
# see https://github.com/python-pillow/Pillow/issues/513
|
# see https://github.com/python-pillow/Pillow/issues/513
|
||||||
|
|
||||||
im = Image.open(TEST_GIF)
|
im = Image.open(TEST_GIF)
|
||||||
im = im.convert('RGB')
|
im = im.convert("RGB")
|
||||||
|
|
||||||
im = im.resize((100, 100), Image.LANCZOS)
|
im = im.resize((100, 100), Image.LANCZOS)
|
||||||
im2 = im.convert('P', palette=Image.ADAPTIVE, colors=256)
|
im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256)
|
||||||
|
|
||||||
f = self.tempfile('temp.gif')
|
f = self.tempfile("temp.gif")
|
||||||
im2.save(f, optimize=True)
|
im2.save(f, optimize=True)
|
||||||
|
|
||||||
reloaded = Image.open(f)
|
reloaded = Image.open(f)
|
||||||
|
|
||||||
self.assert_image_similar(im, reloaded.convert('RGB'), 10)
|
self.assert_image_similar(im, reloaded.convert("RGB"), 10)
|
||||||
|
|
||||||
def test_palette_434(self):
|
def test_palette_434(self):
|
||||||
# see https://github.com/python-pillow/Pillow/issues/434
|
# see https://github.com/python-pillow/Pillow/issues/434
|
||||||
|
|
||||||
def roundtrip(im, *args, **kwargs):
|
def roundtrip(im, *args, **kwargs):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.copy().save(out, *args, **kwargs)
|
im.copy().save(out, *args, **kwargs)
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
im = im.convert("RGB")
|
im = im.convert("RGB")
|
||||||
# check automatic P conversion
|
# check automatic P conversion
|
||||||
reloaded = roundtrip(im).convert('RGB')
|
reloaded = roundtrip(im).convert("RGB")
|
||||||
self.assert_image_equal(im, reloaded)
|
self.assert_image_equal(im, reloaded)
|
||||||
|
|
||||||
@unittest.skipUnless(netpbm_available(), "netpbm not available")
|
@unittest.skipUnless(netpbm_available(), "netpbm not available")
|
||||||
|
@ -240,10 +240,7 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assert_image_equal(im, expected)
|
self.assert_image_equal(im, expected)
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
for path, n_frames in [
|
for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]:
|
||||||
[TEST_GIF, 1],
|
|
||||||
['Tests/images/iss634.gif', 42]
|
|
||||||
]:
|
|
||||||
# Test is_animated before n_frames
|
# Test is_animated before n_frames
|
||||||
im = Image.open(path)
|
im = Image.open(path)
|
||||||
self.assertEqual(im.is_animated, n_frames != 1)
|
self.assertEqual(im.is_animated, n_frames != 1)
|
||||||
|
@ -262,7 +259,7 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_dispose_none(self):
|
def test_dispose_none(self):
|
||||||
img = Image.open("Tests/images/dispose_none.gif")
|
img = Image.open("Tests/images/dispose_none.gif")
|
||||||
|
@ -292,18 +289,15 @@ class TestFileGif(PillowTestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_save_dispose(self):
|
def test_save_dispose(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im_list = [
|
im_list = [
|
||||||
Image.new('L', (100, 100), '#000'),
|
Image.new("L", (100, 100), "#000"),
|
||||||
Image.new('L', (100, 100), '#111'),
|
Image.new("L", (100, 100), "#111"),
|
||||||
Image.new('L', (100, 100), '#222'),
|
Image.new("L", (100, 100), "#222"),
|
||||||
]
|
]
|
||||||
for method in range(0, 4):
|
for method in range(0, 4):
|
||||||
im_list[0].save(
|
im_list[0].save(
|
||||||
out,
|
out, save_all=True, append_images=im_list[1:], disposal=method
|
||||||
save_all=True,
|
|
||||||
append_images=im_list[1:],
|
|
||||||
disposal=method
|
|
||||||
)
|
)
|
||||||
img = Image.open(out)
|
img = Image.open(out)
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
|
@ -315,14 +309,14 @@ class TestFileGif(PillowTestCase):
|
||||||
out,
|
out,
|
||||||
save_all=True,
|
save_all=True,
|
||||||
append_images=im_list[1:],
|
append_images=im_list[1:],
|
||||||
disposal=tuple(range(len(im_list)))
|
disposal=tuple(range(len(im_list))),
|
||||||
)
|
)
|
||||||
|
|
||||||
img = Image.open(out)
|
img = Image.open(out)
|
||||||
|
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
img.seek(img.tell() + 1)
|
img.seek(img.tell() + 1)
|
||||||
self.assertEqual(img.disposal_method, i+1)
|
self.assertEqual(img.disposal_method, i + 1)
|
||||||
|
|
||||||
def test_iss634(self):
|
def test_iss634(self):
|
||||||
img = Image.open("Tests/images/iss634.gif")
|
img = Image.open("Tests/images/iss634.gif")
|
||||||
|
@ -330,42 +324,39 @@ class TestFileGif(PillowTestCase):
|
||||||
img.seek(img.tell() + 1)
|
img.seek(img.tell() + 1)
|
||||||
# all transparent pixels should be replaced with the color from the
|
# all transparent pixels should be replaced with the color from the
|
||||||
# first frame
|
# first frame
|
||||||
self.assertEqual(img.histogram()[img.info['transparency']], 0)
|
self.assertEqual(img.histogram()[img.info["transparency"]], 0)
|
||||||
|
|
||||||
def test_duration(self):
|
def test_duration(self):
|
||||||
duration = 1000
|
duration = 1000
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
|
|
||||||
# Check that the argument has priority over the info settings
|
# Check that the argument has priority over the info settings
|
||||||
im.info['duration'] = 100
|
im.info["duration"] = 100
|
||||||
im.save(out, duration=duration)
|
im.save(out, duration=duration)
|
||||||
|
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
self.assertEqual(reread.info['duration'], duration)
|
self.assertEqual(reread.info["duration"], duration)
|
||||||
|
|
||||||
def test_multiple_duration(self):
|
def test_multiple_duration(self):
|
||||||
duration_list = [1000, 2000, 3000]
|
duration_list = [1000, 2000, 3000]
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im_list = [
|
im_list = [
|
||||||
Image.new('L', (100, 100), '#000'),
|
Image.new("L", (100, 100), "#000"),
|
||||||
Image.new('L', (100, 100), '#111'),
|
Image.new("L", (100, 100), "#111"),
|
||||||
Image.new('L', (100, 100), '#222')
|
Image.new("L", (100, 100), "#222"),
|
||||||
]
|
]
|
||||||
|
|
||||||
# duration as list
|
# duration as list
|
||||||
im_list[0].save(
|
im_list[0].save(
|
||||||
out,
|
out, save_all=True, append_images=im_list[1:], duration=duration_list
|
||||||
save_all=True,
|
|
||||||
append_images=im_list[1:],
|
|
||||||
duration=duration_list
|
|
||||||
)
|
)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
for duration in duration_list:
|
for duration in duration_list:
|
||||||
self.assertEqual(reread.info['duration'], duration)
|
self.assertEqual(reread.info["duration"], duration)
|
||||||
try:
|
try:
|
||||||
reread.seek(reread.tell() + 1)
|
reread.seek(reread.tell() + 1)
|
||||||
except EOFError:
|
except EOFError:
|
||||||
|
@ -373,15 +364,12 @@ class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
# duration as tuple
|
# duration as tuple
|
||||||
im_list[0].save(
|
im_list[0].save(
|
||||||
out,
|
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
|
||||||
save_all=True,
|
|
||||||
append_images=im_list[1:],
|
|
||||||
duration=tuple(duration_list)
|
|
||||||
)
|
)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
for duration in duration_list:
|
for duration in duration_list:
|
||||||
self.assertEqual(reread.info['duration'], duration)
|
self.assertEqual(reread.info["duration"], duration)
|
||||||
try:
|
try:
|
||||||
reread.seek(reread.tell() + 1)
|
reread.seek(reread.tell() + 1)
|
||||||
except EOFError:
|
except EOFError:
|
||||||
|
@ -390,20 +378,17 @@ class TestFileGif(PillowTestCase):
|
||||||
def test_identical_frames(self):
|
def test_identical_frames(self):
|
||||||
duration_list = [1000, 1500, 2000, 4000]
|
duration_list = [1000, 1500, 2000, 4000]
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im_list = [
|
im_list = [
|
||||||
Image.new('L', (100, 100), '#000'),
|
Image.new("L", (100, 100), "#000"),
|
||||||
Image.new('L', (100, 100), '#000'),
|
Image.new("L", (100, 100), "#000"),
|
||||||
Image.new('L', (100, 100), '#000'),
|
Image.new("L", (100, 100), "#000"),
|
||||||
Image.new('L', (100, 100), '#111')
|
Image.new("L", (100, 100), "#111"),
|
||||||
]
|
]
|
||||||
|
|
||||||
# duration as list
|
# duration as list
|
||||||
im_list[0].save(
|
im_list[0].save(
|
||||||
out,
|
out, save_all=True, append_images=im_list[1:], duration=duration_list
|
||||||
save_all=True,
|
|
||||||
append_images=im_list[1:],
|
|
||||||
duration=duration_list
|
|
||||||
)
|
)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
|
@ -411,64 +396,63 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertEqual(reread.n_frames, 2)
|
self.assertEqual(reread.n_frames, 2)
|
||||||
|
|
||||||
# Assert that the new duration is the total of the identical frames
|
# Assert that the new duration is the total of the identical frames
|
||||||
self.assertEqual(reread.info['duration'], 4500)
|
self.assertEqual(reread.info["duration"], 4500)
|
||||||
|
|
||||||
def test_number_of_loops(self):
|
def test_number_of_loops(self):
|
||||||
number_of_loops = 2
|
number_of_loops = 2
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
im.save(out, loop=number_of_loops)
|
im.save(out, loop=number_of_loops)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.info['loop'], number_of_loops)
|
self.assertEqual(reread.info["loop"], number_of_loops)
|
||||||
|
|
||||||
def test_background(self):
|
def test_background(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
im.info['background'] = 1
|
im.info["background"] = 1
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.info['background'], im.info['background'])
|
self.assertEqual(reread.info["background"], im.info["background"])
|
||||||
|
|
||||||
if HAVE_WEBP and _webp.HAVE_WEBPANIM:
|
if HAVE_WEBP and _webp.HAVE_WEBPANIM:
|
||||||
im = Image.open("Tests/images/hopper.webp")
|
im = Image.open("Tests/images/hopper.webp")
|
||||||
self.assertIsInstance(im.info['background'], tuple)
|
self.assertIsInstance(im.info["background"], tuple)
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
||||||
def test_comment(self):
|
def test_comment(self):
|
||||||
im = Image.open(TEST_GIF)
|
im = Image.open(TEST_GIF)
|
||||||
self.assertEqual(im.info['comment'],
|
self.assertEqual(im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0")
|
||||||
b"File written by Adobe Photoshop\xa8 4.0")
|
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
im.info['comment'] = b"Test comment text"
|
im.info["comment"] = b"Test comment text"
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.info['comment'], im.info['comment'])
|
self.assertEqual(reread.info["comment"], im.info["comment"])
|
||||||
|
|
||||||
def test_comment_over_255(self):
|
def test_comment_over_255(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
comment = b"Test comment text"
|
comment = b"Test comment text"
|
||||||
while len(comment) < 256:
|
while len(comment) < 256:
|
||||||
comment += comment
|
comment += comment
|
||||||
im.info['comment'] = comment
|
im.info["comment"] = comment
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.info['comment'], comment)
|
self.assertEqual(reread.info["comment"], comment)
|
||||||
|
|
||||||
def test_zero_comment_subblocks(self):
|
def test_zero_comment_subblocks(self):
|
||||||
im = Image.open('Tests/images/hopper_zero_comment_subblocks.gif')
|
im = Image.open("Tests/images/hopper_zero_comment_subblocks.gif")
|
||||||
expected = Image.open(TEST_GIF)
|
expected = Image.open(TEST_GIF)
|
||||||
self.assert_image_equal(im, expected)
|
self.assert_image_equal(im, expected)
|
||||||
|
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
def assertVersionAfterSave(im, version):
|
def assertVersionAfterSave(im, version):
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
@ -476,11 +460,11 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertEqual(reread.info["version"], version)
|
self.assertEqual(reread.info["version"], version)
|
||||||
|
|
||||||
# Test that GIF87a is used by default
|
# Test that GIF87a is used by default
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
assertVersionAfterSave(im, b"GIF87a")
|
assertVersionAfterSave(im, b"GIF87a")
|
||||||
|
|
||||||
# Test setting the version to 89a
|
# Test setting the version to 89a
|
||||||
im = Image.new('L', (100, 100), '#000')
|
im = Image.new("L", (100, 100), "#000")
|
||||||
im.info["version"] = b"89a"
|
im.info["version"] = b"89a"
|
||||||
assertVersionAfterSave(im, b"GIF89a")
|
assertVersionAfterSave(im, b"GIF89a")
|
||||||
|
|
||||||
|
@ -497,12 +481,11 @@ class TestFileGif(PillowTestCase):
|
||||||
assertVersionAfterSave(im, b"GIF87a")
|
assertVersionAfterSave(im, b"GIF87a")
|
||||||
|
|
||||||
def test_append_images(self):
|
def test_append_images(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
# Test appending single frame images
|
# Test appending single frame images
|
||||||
im = Image.new('RGB', (100, 100), '#f00')
|
im = Image.new("RGB", (100, 100), "#f00")
|
||||||
ims = [Image.new('RGB', (100, 100), color) for color
|
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
|
||||||
in ['#0f0', '#00f']]
|
|
||||||
im.copy().save(out, save_all=True, append_images=ims)
|
im.copy().save(out, save_all=True, append_images=ims)
|
||||||
|
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
@ -512,6 +495,7 @@ class TestFileGif(PillowTestCase):
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
for im in ims:
|
||||||
yield im
|
yield im
|
||||||
|
|
||||||
im.save(out, save_all=True, append_images=imGenerator(ims))
|
im.save(out, save_all=True, append_images=imGenerator(ims))
|
||||||
|
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
@ -533,44 +517,43 @@ class TestFileGif(PillowTestCase):
|
||||||
# the top palette entry to trigger the bug.
|
# the top palette entry to trigger the bug.
|
||||||
|
|
||||||
data = bytes(bytearray(range(1, 254)))
|
data = bytes(bytearray(range(1, 254)))
|
||||||
palette = ImagePalette.ImagePalette("RGB", list(range(256))*3)
|
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||||
|
|
||||||
im = Image.new('L', (253, 1))
|
im = Image.new("L", (253, 1))
|
||||||
im.frombytes(data)
|
im.frombytes(data)
|
||||||
im.putpalette(palette)
|
im.putpalette(palette)
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out, transparency=253)
|
im.save(out, transparency=253)
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reloaded.info['transparency'], 253)
|
self.assertEqual(reloaded.info["transparency"], 253)
|
||||||
|
|
||||||
def test_rgb_transparency(self):
|
def test_rgb_transparency(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
# Single frame
|
# Single frame
|
||||||
im = Image.new('RGB', (1, 1))
|
im = Image.new("RGB", (1, 1))
|
||||||
im.info['transparency'] = (255, 0, 0)
|
im.info["transparency"] = (255, 0, 0)
|
||||||
self.assert_warning(UserWarning, im.save, out)
|
self.assert_warning(UserWarning, im.save, out)
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assertNotIn('transparency', reloaded.info)
|
self.assertNotIn("transparency", reloaded.info)
|
||||||
|
|
||||||
# Multiple frames
|
# Multiple frames
|
||||||
im = Image.new('RGB', (1, 1))
|
im = Image.new("RGB", (1, 1))
|
||||||
im.info['transparency'] = b""
|
im.info["transparency"] = b""
|
||||||
ims = [Image.new('RGB', (1, 1))]
|
ims = [Image.new("RGB", (1, 1))]
|
||||||
self.assert_warning(UserWarning,
|
self.assert_warning(UserWarning, im.save, out, save_all=True, append_images=ims)
|
||||||
im.save, out, save_all=True, append_images=ims)
|
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assertNotIn('transparency', reloaded.info)
|
self.assertNotIn("transparency", reloaded.info)
|
||||||
|
|
||||||
def test_bbox(self):
|
def test_bbox(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
im = Image.new('RGB', (100, 100), '#fff')
|
im = Image.new("RGB", (100, 100), "#fff")
|
||||||
ims = [Image.new("RGB", (100, 100), '#000')]
|
ims = [Image.new("RGB", (100, 100), "#000")]
|
||||||
im.save(out, save_all=True, append_images=ims)
|
im.save(out, save_all=True, append_images=ims)
|
||||||
|
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
@ -579,26 +562,26 @@ class TestFileGif(PillowTestCase):
|
||||||
def test_palette_save_L(self):
|
def test_palette_save_L(self):
|
||||||
# generate an L mode image with a separate palette
|
# generate an L mode image with a separate palette
|
||||||
|
|
||||||
im = hopper('P')
|
im = hopper("P")
|
||||||
im_l = Image.frombytes('L', im.size, im.tobytes())
|
im_l = Image.frombytes("L", im.size, im.tobytes())
|
||||||
palette = bytes(bytearray(im.getpalette()))
|
palette = bytes(bytearray(im.getpalette()))
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im_l.save(out, palette=palette)
|
im_l.save(out, palette=palette)
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
|
|
||||||
self.assert_image_equal(reloaded.convert('RGB'), im.convert('RGB'))
|
self.assert_image_equal(reloaded.convert("RGB"), im.convert("RGB"))
|
||||||
|
|
||||||
def test_palette_save_P(self):
|
def test_palette_save_P(self):
|
||||||
# pass in a different palette, then construct what the image
|
# pass in a different palette, then construct what the image
|
||||||
# would look like.
|
# would look like.
|
||||||
# Forcing a non-straight grayscale palette.
|
# Forcing a non-straight grayscale palette.
|
||||||
|
|
||||||
im = hopper('P')
|
im = hopper("P")
|
||||||
palette = bytes(bytearray([255-i//3 for i in range(768)]))
|
palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out, palette=palette)
|
im.save(out, palette=palette)
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
|
@ -609,10 +592,10 @@ class TestFileGif(PillowTestCase):
|
||||||
# pass in a different palette, as an ImagePalette.ImagePalette
|
# pass in a different palette, as an ImagePalette.ImagePalette
|
||||||
# effectively the same as test_palette_save_P
|
# effectively the same as test_palette_save_P
|
||||||
|
|
||||||
im = hopper('P')
|
im = hopper("P")
|
||||||
palette = ImagePalette.ImagePalette('RGB', list(range(256))[::-1]*3)
|
palette = ImagePalette.ImagePalette("RGB", list(range(256))[::-1] * 3)
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out, palette=palette)
|
im.save(out, palette=palette)
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
|
@ -622,22 +605,22 @@ class TestFileGif(PillowTestCase):
|
||||||
def test_save_I(self):
|
def test_save_I(self):
|
||||||
# Test saving something that would trigger the auto-convert to 'L'
|
# Test saving something that would trigger the auto-convert to 'L'
|
||||||
|
|
||||||
im = hopper('I')
|
im = hopper("I")
|
||||||
|
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assert_image_equal(reloaded.convert('L'), im.convert('L'))
|
self.assert_image_equal(reloaded.convert("L"), im.convert("L"))
|
||||||
|
|
||||||
def test_getdata(self):
|
def test_getdata(self):
|
||||||
# test getheader/getdata against legacy values
|
# test getheader/getdata against legacy values
|
||||||
# Create a 'P' image with holes in the palette
|
# Create a 'P' image with holes in the palette
|
||||||
im = Image._wedge().resize((16, 16))
|
im = Image._wedge().resize((16, 16))
|
||||||
im.putpalette(ImagePalette.ImagePalette('RGB'))
|
im.putpalette(ImagePalette.ImagePalette("RGB"))
|
||||||
im.info = {'background': 0}
|
im.info = {"background": 0}
|
||||||
|
|
||||||
passed_palette = bytes(bytearray([255-i//3 for i in range(768)]))
|
passed_palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
|
||||||
|
|
||||||
GifImagePlugin._FORCE_OPTIMIZE = True
|
GifImagePlugin._FORCE_OPTIMIZE = True
|
||||||
try:
|
try:
|
||||||
|
@ -645,10 +628,11 @@ class TestFileGif(PillowTestCase):
|
||||||
d = GifImagePlugin.getdata(im)
|
d = GifImagePlugin.getdata(im)
|
||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
# Enable to get target values on pre-refactor version
|
# Enable to get target values on pre-refactor version
|
||||||
# with open('Tests/images/gif_header_data.pkl', 'wb') as f:
|
# with open('Tests/images/gif_header_data.pkl', 'wb') as f:
|
||||||
# pickle.dump((h, d), f, 1)
|
# pickle.dump((h, d), f, 1)
|
||||||
with open('Tests/images/gif_header_data.pkl', 'rb') as f:
|
with open("Tests/images/gif_header_data.pkl", "rb") as f:
|
||||||
(h_target, d_target) = pickle.load(f)
|
(h_target, d_target) = pickle.load(f)
|
||||||
|
|
||||||
self.assertEqual(h, h_target)
|
self.assertEqual(h, h_target)
|
||||||
|
@ -658,14 +642,14 @@ class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
def test_lzw_bits(self):
|
def test_lzw_bits(self):
|
||||||
# see https://github.com/python-pillow/Pillow/issues/2811
|
# see https://github.com/python-pillow/Pillow/issues/2811
|
||||||
im = Image.open('Tests/images/issue_2811.gif')
|
im = Image.open("Tests/images/issue_2811.gif")
|
||||||
|
|
||||||
self.assertEqual(im.tile[0][3][0], 11) # LZW bits
|
self.assertEqual(im.tile[0][3][0], 11) # LZW bits
|
||||||
# codec error prepatch
|
# codec error prepatch
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
def test_extents(self):
|
def test_extents(self):
|
||||||
im = Image.open('Tests/images/test_extents.gif')
|
im = Image.open("Tests/images/test_extents.gif")
|
||||||
self.assertEqual(im.size, (100, 100))
|
self.assertEqual(im.size, (100, 100))
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
self.assertEqual(im.size, (150, 150))
|
self.assertEqual(im.size, (150, 150))
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import GimpGradientFile
|
||||||
|
|
||||||
|
|
||||||
class TestImage(PillowTestCase):
|
class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_linear_pos_le_middle(self):
|
def test_linear_pos_le_middle(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
middle = 0.5
|
middle = 0.5
|
||||||
|
@ -96,6 +95,7 @@ class TestImage(PillowTestCase):
|
||||||
def test_load_via_imagepalette(self):
|
def test_load_via_imagepalette(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ImagePalette
|
from PIL import ImagePalette
|
||||||
|
|
||||||
test_file = "Tests/images/gimp_gradient.ggr"
|
test_file = "Tests/images/gimp_gradient.ggr"
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
@ -109,6 +109,7 @@ class TestImage(PillowTestCase):
|
||||||
def test_load_1_3_via_imagepalette(self):
|
def test_load_1_3_via_imagepalette(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ImagePalette
|
from PIL import ImagePalette
|
||||||
|
|
||||||
# GIMP 1.3 gradient files contain a name field
|
# GIMP 1.3 gradient files contain a name field
|
||||||
test_file = "Tests/images/gimp_gradient_with_name.ggr"
|
test_file = "Tests/images/gimp_gradient_with_name.ggr"
|
||||||
|
|
||||||
|
|
|
@ -4,23 +4,22 @@ from PIL.GimpPaletteFile import GimpPaletteFile
|
||||||
|
|
||||||
|
|
||||||
class TestImage(PillowTestCase):
|
class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
with open('Tests/images/test.gpl', 'rb') as fp:
|
with open("Tests/images/test.gpl", "rb") as fp:
|
||||||
GimpPaletteFile(fp)
|
GimpPaletteFile(fp)
|
||||||
|
|
||||||
with open('Tests/images/hopper.jpg', 'rb') as fp:
|
with open("Tests/images/hopper.jpg", "rb") as fp:
|
||||||
self.assertRaises(SyntaxError, GimpPaletteFile, fp)
|
self.assertRaises(SyntaxError, GimpPaletteFile, fp)
|
||||||
|
|
||||||
with open('Tests/images/bad_palette_file.gpl', 'rb') as fp:
|
with open("Tests/images/bad_palette_file.gpl", "rb") as fp:
|
||||||
self.assertRaises(SyntaxError, GimpPaletteFile, fp)
|
self.assertRaises(SyntaxError, GimpPaletteFile, fp)
|
||||||
|
|
||||||
with open('Tests/images/bad_palette_entry.gpl', 'rb') as fp:
|
with open("Tests/images/bad_palette_entry.gpl", "rb") as fp:
|
||||||
self.assertRaises(ValueError, GimpPaletteFile, fp)
|
self.assertRaises(ValueError, GimpPaletteFile, fp)
|
||||||
|
|
||||||
def test_get_palette(self):
|
def test_get_palette(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
with open('Tests/images/custom_gimp_palette.gpl', 'rb') as fp:
|
with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp:
|
||||||
palette_file = GimpPaletteFile(fp)
|
palette_file = GimpPaletteFile(fp)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
|
||||||
|
|
||||||
|
|
||||||
class TestFileGribStub(PillowTestCase):
|
class TestFileGribStub(PillowTestCase):
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Act
|
# Act
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
@ -23,8 +22,9 @@ class TestFileGribStub(PillowTestCase):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(
|
||||||
GribStubImagePlugin.GribStubImageFile, invalid_file)
|
SyntaxError, GribStubImagePlugin.GribStubImageFile, invalid_file
|
||||||
|
)
|
||||||
|
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hdf5.h5"
|
||||||
|
|
||||||
|
|
||||||
class TestFileHdf5Stub(PillowTestCase):
|
class TestFileHdf5Stub(PillowTestCase):
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Act
|
# Act
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
@ -23,8 +22,9 @@ class TestFileHdf5Stub(PillowTestCase):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(
|
||||||
Hdf5StubImagePlugin.HDF5StubImageFile, invalid_file)
|
SyntaxError, Hdf5StubImagePlugin.HDF5StubImageFile, invalid_file
|
||||||
|
)
|
||||||
|
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -42,5 +42,5 @@ class TestFileHdf5Stub(PillowTestCase):
|
||||||
# Act / Assert: stub cannot save without an implemented handler
|
# Act / Assert: stub cannot save without an implemented handler
|
||||||
self.assertRaises(IOError, im.save, dummy_filename)
|
self.assertRaises(IOError, im.save, dummy_filename)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
IOError,
|
IOError, Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename
|
||||||
Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename)
|
)
|
||||||
|
|
|
@ -8,11 +8,10 @@ import sys
|
||||||
# sample icon file
|
# sample icon file
|
||||||
TEST_FILE = "Tests/images/pillow.icns"
|
TEST_FILE = "Tests/images/pillow.icns"
|
||||||
|
|
||||||
enable_jpeg2k = hasattr(Image.core, 'jp2klib_version')
|
enable_jpeg2k = hasattr(Image.core, "jp2klib_version")
|
||||||
|
|
||||||
|
|
||||||
class TestFileIcns(PillowTestCase):
|
class TestFileIcns(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
# Loading this icon by default should result in the largest size
|
# Loading this icon by default should result in the largest size
|
||||||
# (512x512@2x) being loaded
|
# (512x512@2x) being loaded
|
||||||
|
@ -25,7 +24,7 @@ class TestFileIcns(PillowTestCase):
|
||||||
self.assertEqual(im.size, (1024, 1024))
|
self.assertEqual(im.size, (1024, 1024))
|
||||||
self.assertEqual(im.format, "ICNS")
|
self.assertEqual(im.format, "ICNS")
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform != 'darwin', "requires macOS")
|
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
|
||||||
|
@ -38,12 +37,12 @@ class TestFileIcns(PillowTestCase):
|
||||||
self.assertEqual(reread.size, (1024, 1024))
|
self.assertEqual(reread.size, (1024, 1024))
|
||||||
self.assertEqual(reread.format, "ICNS")
|
self.assertEqual(reread.format, "ICNS")
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform != 'darwin', "requires macOS")
|
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
|
||||||
def test_save_append_images(self):
|
def test_save_append_images(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
|
||||||
temp_file = self.tempfile("temp.icns")
|
temp_file = self.tempfile("temp.icns")
|
||||||
provided_im = Image.new('RGBA', (32, 32), (255, 0, 0, 128))
|
provided_im = Image.new("RGBA", (32, 32), (255, 0, 0, 128))
|
||||||
im.save(temp_file, append_images=[provided_im])
|
im.save(temp_file, append_images=[provided_im])
|
||||||
|
|
||||||
reread = Image.open(temp_file)
|
reread = Image.open(temp_file)
|
||||||
|
@ -58,12 +57,12 @@ class TestFileIcns(PillowTestCase):
|
||||||
# Check that we can load all of the sizes, and that the final pixel
|
# Check that we can load all of the sizes, and that the final pixel
|
||||||
# dimensions are as expected
|
# dimensions are as expected
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
for w, h, r in im.info['sizes']:
|
for w, h, r in im.info["sizes"]:
|
||||||
wr = w * r
|
wr = w * r
|
||||||
hr = h * r
|
hr = h * r
|
||||||
im.size = (w, h, r)
|
im.size = (w, h, r)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, 'RGBA')
|
self.assertEqual(im.mode, "RGBA")
|
||||||
self.assertEqual(im.size, (wr, hr))
|
self.assertEqual(im.size, (wr, hr))
|
||||||
|
|
||||||
# Check that we cannot load an incorrect size
|
# Check that we cannot load an incorrect size
|
||||||
|
@ -73,14 +72,14 @@ class TestFileIcns(PillowTestCase):
|
||||||
def test_older_icon(self):
|
def test_older_icon(self):
|
||||||
# This icon was made with Icon Composer rather than iconutil; it still
|
# This icon was made with Icon Composer rather than iconutil; it still
|
||||||
# uses PNG rather than JP2, however (since it was made on 10.9).
|
# uses PNG rather than JP2, however (since it was made on 10.9).
|
||||||
im = Image.open('Tests/images/pillow2.icns')
|
im = Image.open("Tests/images/pillow2.icns")
|
||||||
for w, h, r in im.info['sizes']:
|
for w, h, r in im.info["sizes"]:
|
||||||
wr = w * r
|
wr = w * r
|
||||||
hr = h * r
|
hr = h * r
|
||||||
im2 = Image.open('Tests/images/pillow2.icns')
|
im2 = Image.open("Tests/images/pillow2.icns")
|
||||||
im2.size = (w, h, r)
|
im2.size = (w, h, r)
|
||||||
im2.load()
|
im2.load()
|
||||||
self.assertEqual(im2.mode, 'RGBA')
|
self.assertEqual(im2.mode, "RGBA")
|
||||||
self.assertEqual(im2.size, (wr, hr))
|
self.assertEqual(im2.size, (wr, hr))
|
||||||
|
|
||||||
def test_jp2_icon(self):
|
def test_jp2_icon(self):
|
||||||
|
@ -94,18 +93,18 @@ class TestFileIcns(PillowTestCase):
|
||||||
if not enable_jpeg2k:
|
if not enable_jpeg2k:
|
||||||
return
|
return
|
||||||
|
|
||||||
im = Image.open('Tests/images/pillow3.icns')
|
im = Image.open("Tests/images/pillow3.icns")
|
||||||
for w, h, r in im.info['sizes']:
|
for w, h, r in im.info["sizes"]:
|
||||||
wr = w * r
|
wr = w * r
|
||||||
hr = h * r
|
hr = h * r
|
||||||
im2 = Image.open('Tests/images/pillow3.icns')
|
im2 = Image.open("Tests/images/pillow3.icns")
|
||||||
im2.size = (w, h, r)
|
im2.size = (w, h, r)
|
||||||
im2.load()
|
im2.load()
|
||||||
self.assertEqual(im2.mode, 'RGBA')
|
self.assertEqual(im2.mode, "RGBA")
|
||||||
self.assertEqual(im2.size, (wr, hr))
|
self.assertEqual(im2.size, (wr, hr))
|
||||||
|
|
||||||
def test_getimage(self):
|
def test_getimage(self):
|
||||||
with open(TEST_FILE, 'rb') as fp:
|
with open(TEST_FILE, "rb") as fp:
|
||||||
icns_file = IcnsImagePlugin.IcnsFile(fp)
|
icns_file = IcnsImagePlugin.IcnsFile(fp)
|
||||||
|
|
||||||
im = icns_file.getimage()
|
im = icns_file.getimage()
|
||||||
|
@ -117,6 +116,5 @@ class TestFileIcns(PillowTestCase):
|
||||||
self.assertEqual(im.size, (512, 512))
|
self.assertEqual(im.size, (512, 512))
|
||||||
|
|
||||||
def test_not_an_icns_file(self):
|
def test_not_an_icns_file(self):
|
||||||
with io.BytesIO(b'invalid\n') as fp:
|
with io.BytesIO(b"invalid\n") as fp:
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, IcnsImagePlugin.IcnsFile, fp)
|
||||||
IcnsImagePlugin.IcnsFile, fp)
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ TEST_ICO_FILE = "Tests/images/hopper.ico"
|
||||||
|
|
||||||
|
|
||||||
class TestFileIco(PillowTestCase):
|
class TestFileIco(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_ICO_FILE)
|
im = Image.open(TEST_ICO_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -18,8 +17,7 @@ class TestFileIco(PillowTestCase):
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, IcoImagePlugin.IcoImageFile, fp)
|
||||||
IcoImagePlugin.IcoImageFile, fp)
|
|
||||||
|
|
||||||
def test_save_to_bytes(self):
|
def test_save_to_bytes(self):
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
|
@ -29,13 +27,12 @@ class TestFileIco(PillowTestCase):
|
||||||
# the default image
|
# the default image
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
reloaded = Image.open(output)
|
reloaded = Image.open(output)
|
||||||
self.assertEqual(reloaded.info['sizes'], {(32, 32), (64, 64)})
|
self.assertEqual(reloaded.info["sizes"], {(32, 32), (64, 64)})
|
||||||
|
|
||||||
self.assertEqual(im.mode, reloaded.mode)
|
self.assertEqual(im.mode, reloaded.mode)
|
||||||
self.assertEqual((64, 64), reloaded.size)
|
self.assertEqual((64, 64), reloaded.size)
|
||||||
self.assertEqual(reloaded.format, "ICO")
|
self.assertEqual(reloaded.format, "ICO")
|
||||||
self.assert_image_equal(reloaded,
|
self.assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS))
|
||||||
hopper().resize((64, 64), Image.LANCZOS))
|
|
||||||
|
|
||||||
# the other one
|
# the other one
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
|
@ -45,8 +42,7 @@ class TestFileIco(PillowTestCase):
|
||||||
self.assertEqual(im.mode, reloaded.mode)
|
self.assertEqual(im.mode, reloaded.mode)
|
||||||
self.assertEqual((32, 32), reloaded.size)
|
self.assertEqual((32, 32), reloaded.size)
|
||||||
self.assertEqual(reloaded.format, "ICO")
|
self.assertEqual(reloaded.format, "ICO")
|
||||||
self.assert_image_equal(reloaded,
|
self.assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
|
||||||
hopper().resize((32, 32), Image.LANCZOS))
|
|
||||||
|
|
||||||
def test_incorrect_size(self):
|
def test_incorrect_size(self):
|
||||||
im = Image.open(TEST_ICO_FILE)
|
im = Image.open(TEST_ICO_FILE)
|
||||||
|
@ -81,14 +77,15 @@ class TestFileIco(PillowTestCase):
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im_saved.info['sizes'],
|
im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)}
|
||||||
{(16, 16), (24, 24), (32, 32), (48, 48)})
|
)
|
||||||
|
|
||||||
def test_unexpected_size(self):
|
def test_unexpected_size(self):
|
||||||
# This image has been manually hexedited to state that it is 16x32
|
# This image has been manually hexedited to state that it is 16x32
|
||||||
# while the image within is still 16x16
|
# while the image within is still 16x16
|
||||||
im = self.assert_warning(UserWarning,
|
im = self.assert_warning(
|
||||||
Image.open, "Tests/images/hopper_unexpected.ico")
|
UserWarning, Image.open, "Tests/images/hopper_unexpected.ico"
|
||||||
|
)
|
||||||
self.assertEqual(im.size, (16, 16))
|
self.assertEqual(im.size, (16, 16))
|
||||||
|
|
||||||
def test_draw_reloaded(self):
|
def test_draw_reloaded(self):
|
||||||
|
@ -96,7 +93,7 @@ class TestFileIco(PillowTestCase):
|
||||||
outfile = self.tempfile("temp_saved_hopper_draw.ico")
|
outfile = self.tempfile("temp_saved_hopper_draw.ico")
|
||||||
|
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
draw.line((0, 0) + im.size, '#f00')
|
draw.line((0, 0) + im.size, "#f00")
|
||||||
im.save(outfile)
|
im.save(outfile)
|
||||||
|
|
||||||
im = Image.open(outfile)
|
im = Image.open(outfile)
|
||||||
|
|
|
@ -7,7 +7,6 @@ TEST_IM = "Tests/images/hopper.im"
|
||||||
|
|
||||||
|
|
||||||
class TestFileIm(PillowTestCase):
|
class TestFileIm(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_IM)
|
im = Image.open(TEST_IM)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -19,6 +18,7 @@ class TestFileIm(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(TEST_IM)
|
im = Image.open(TEST_IM)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_tell(self):
|
def test_tell(self):
|
||||||
|
@ -45,11 +45,11 @@ class TestFileIm(PillowTestCase):
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_roundtrip(self):
|
def test_roundtrip(self):
|
||||||
for mode in ["RGB", "P", "PA"]:
|
for mode in ["RGB", "P", "PA"]:
|
||||||
out = self.tempfile('temp.im')
|
out = self.tempfile("temp.im")
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
@ -57,15 +57,14 @@ class TestFileIm(PillowTestCase):
|
||||||
self.assert_image_equal(reread, im)
|
self.assert_image_equal(reread, im)
|
||||||
|
|
||||||
def test_save_unsupported_mode(self):
|
def test_save_unsupported_mode(self):
|
||||||
out = self.tempfile('temp.im')
|
out = self.tempfile("temp.im")
|
||||||
im = hopper("HSV")
|
im = hopper("HSV")
|
||||||
self.assertRaises(ValueError, im.save, out)
|
self.assertRaises(ValueError, im.save, out)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, ImImagePlugin.ImImageFile, invalid_file)
|
||||||
ImImagePlugin.ImImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_number(self):
|
def test_number(self):
|
||||||
self.assertEqual(1.2, ImImagePlugin.number("1.2"))
|
self.assertEqual(1.2, ImImagePlugin.number("1.2"))
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/iptc.jpg"
|
||||||
|
|
||||||
|
|
||||||
class TestFileIptc(PillowTestCase):
|
class TestFileIptc(PillowTestCase):
|
||||||
|
|
||||||
def test_getiptcinfo_jpg_none(self):
|
def test_getiptcinfo_jpg_none(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
@ -58,6 +57,7 @@ class TestFileIptc(PillowTestCase):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
sys.stdout = mystdout = StringIO()
|
sys.stdout = mystdout = StringIO()
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ TEST_FILE = "Tests/images/hopper.jpg"
|
||||||
|
|
||||||
|
|
||||||
class TestFileJpeg(PillowTestCase):
|
class TestFileJpeg(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
self.skipTest("jpeg support not available")
|
self.skipTest("jpeg support not available")
|
||||||
|
@ -29,14 +28,13 @@ class TestFileJpeg(PillowTestCase):
|
||||||
im.bytes = test_bytes # for testing only
|
im.bytes = test_bytes # for testing only
|
||||||
return im
|
return im
|
||||||
|
|
||||||
def gen_random_image(self, size, mode='RGB'):
|
def gen_random_image(self, size, mode="RGB"):
|
||||||
""" Generates a very hard to compress file
|
""" Generates a very hard to compress file
|
||||||
:param size: tuple
|
:param size: tuple
|
||||||
:param mode: optional image mode
|
:param mode: optional image mode
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return Image.frombytes(mode, size,
|
return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode)))
|
||||||
os.urandom(size[0]*size[1]*len(mode)))
|
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
|
@ -54,10 +52,11 @@ class TestFileJpeg(PillowTestCase):
|
||||||
# Test APP/COM reader (@PIL135)
|
# Test APP/COM reader (@PIL135)
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.applist[0],
|
im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")
|
||||||
("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00"))
|
)
|
||||||
self.assertEqual(im.applist[1], (
|
self.assertEqual(
|
||||||
"COM", b"File written by Adobe Photoshop\xa8 4.0\x00"))
|
im.applist[1], ("COM", b"File written by Adobe Photoshop\xa8 4.0\x00")
|
||||||
|
)
|
||||||
self.assertEqual(len(im.applist), 2)
|
self.assertEqual(len(im.applist), 2)
|
||||||
|
|
||||||
def test_cmyk(self):
|
def test_cmyk(self):
|
||||||
|
@ -72,8 +71,7 @@ class TestFileJpeg(PillowTestCase):
|
||||||
self.assertGreater(y, 0.8)
|
self.assertGreater(y, 0.8)
|
||||||
self.assertEqual(k, 0.0)
|
self.assertEqual(k, 0.0)
|
||||||
# the opposite corner is black
|
# the opposite corner is black
|
||||||
c, m, y, k = [x / 255.0 for x in im.getpixel((
|
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))]
|
||||||
im.size[0]-1, im.size[1]-1))]
|
|
||||||
self.assertGreater(k, 0.9)
|
self.assertGreater(k, 0.9)
|
||||||
# roundtrip, and check again
|
# roundtrip, and check again
|
||||||
im = self.roundtrip(im)
|
im = self.roundtrip(im)
|
||||||
|
@ -82,8 +80,7 @@ class TestFileJpeg(PillowTestCase):
|
||||||
self.assertGreater(m, 0.8)
|
self.assertGreater(m, 0.8)
|
||||||
self.assertGreater(y, 0.8)
|
self.assertGreater(y, 0.8)
|
||||||
self.assertEqual(k, 0.0)
|
self.assertEqual(k, 0.0)
|
||||||
c, m, y, k = [x / 255.0 for x in im.getpixel((
|
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))]
|
||||||
im.size[0]-1, im.size[1]-1))]
|
|
||||||
self.assertGreater(k, 0.9)
|
self.assertGreater(k, 0.9)
|
||||||
|
|
||||||
def test_dpi(self):
|
def test_dpi(self):
|
||||||
|
@ -91,6 +88,7 @@ class TestFileJpeg(PillowTestCase):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
|
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
|
||||||
return im.info.get("dpi")
|
return im.info.get("dpi")
|
||||||
|
|
||||||
self.assertEqual(test(72), (72, 72))
|
self.assertEqual(test(72), (72, 72))
|
||||||
self.assertEqual(test(300), (300, 300))
|
self.assertEqual(test(300), (300, 300))
|
||||||
self.assertEqual(test(100, 200), (100, 200))
|
self.assertEqual(test(100, 200), (100, 200))
|
||||||
|
@ -119,31 +117,38 @@ class TestFileJpeg(PillowTestCase):
|
||||||
# The ICC APP marker can store 65519 bytes per marker, so
|
# The ICC APP marker can store 65519 bytes per marker, so
|
||||||
# using a 4-byte test code should allow us to detect out of
|
# using a 4-byte test code should allow us to detect out of
|
||||||
# order issues.
|
# order issues.
|
||||||
icc_profile = (b"Test"*int(n/4+1))[:n]
|
icc_profile = (b"Test" * int(n / 4 + 1))[:n]
|
||||||
self.assertEqual(len(icc_profile), n) # sanity
|
self.assertEqual(len(icc_profile), n) # sanity
|
||||||
im1 = self.roundtrip(hopper(), icc_profile=icc_profile)
|
im1 = self.roundtrip(hopper(), icc_profile=icc_profile)
|
||||||
self.assertEqual(im1.info.get("icc_profile"), icc_profile or None)
|
self.assertEqual(im1.info.get("icc_profile"), icc_profile or None)
|
||||||
|
|
||||||
test(0)
|
test(0)
|
||||||
test(1)
|
test(1)
|
||||||
test(3)
|
test(3)
|
||||||
test(4)
|
test(4)
|
||||||
test(5)
|
test(5)
|
||||||
test(65533-14) # full JPEG marker block
|
test(65533 - 14) # full JPEG marker block
|
||||||
test(65533-14+1) # full block plus one byte
|
test(65533 - 14 + 1) # full block plus one byte
|
||||||
test(ImageFile.MAXBLOCK) # full buffer block
|
test(ImageFile.MAXBLOCK) # full buffer block
|
||||||
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
|
test(ImageFile.MAXBLOCK + 1) # full buffer block plus one byte
|
||||||
test(ImageFile.MAXBLOCK*4+3) # large block
|
test(ImageFile.MAXBLOCK * 4 + 3) # large block
|
||||||
|
|
||||||
def test_large_icc_meta(self):
|
def test_large_icc_meta(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/148
|
# https://github.com/python-pillow/Pillow/issues/148
|
||||||
# Sometimes the meta data on the icc_profile block is bigger than
|
# Sometimes the meta data on the icc_profile block is bigger than
|
||||||
# Image.MAXBLOCK or the image size.
|
# Image.MAXBLOCK or the image size.
|
||||||
im = Image.open('Tests/images/icc_profile_big.jpg')
|
im = Image.open("Tests/images/icc_profile_big.jpg")
|
||||||
f = self.tempfile("temp.jpg")
|
f = self.tempfile("temp.jpg")
|
||||||
icc_profile = im.info["icc_profile"]
|
icc_profile = im.info["icc_profile"]
|
||||||
# Should not raise IOError for image with icc larger than image size.
|
# Should not raise IOError for image with icc larger than image size.
|
||||||
im.save(f, format='JPEG', progressive=True, quality=95,
|
im.save(
|
||||||
icc_profile=icc_profile, optimize=True)
|
f,
|
||||||
|
format="JPEG",
|
||||||
|
progressive=True,
|
||||||
|
quality=95,
|
||||||
|
icc_profile=icc_profile,
|
||||||
|
optimize=True,
|
||||||
|
)
|
||||||
|
|
||||||
def test_optimize(self):
|
def test_optimize(self):
|
||||||
im1 = self.roundtrip(hopper())
|
im1 = self.roundtrip(hopper())
|
||||||
|
@ -156,9 +161,9 @@ class TestFileJpeg(PillowTestCase):
|
||||||
|
|
||||||
def test_optimize_large_buffer(self):
|
def test_optimize_large_buffer(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/148
|
# https://github.com/python-pillow/Pillow/issues/148
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
# this requires ~ 1.5x Image.MAXBLOCK
|
# this requires ~ 1.5x Image.MAXBLOCK
|
||||||
im = Image.new("RGB", (4096, 4096), 0xff3333)
|
im = Image.new("RGB", (4096, 4096), 0xFF3333)
|
||||||
im.save(f, format="JPEG", optimize=True)
|
im.save(f, format="JPEG", optimize=True)
|
||||||
|
|
||||||
def test_progressive(self):
|
def test_progressive(self):
|
||||||
|
@ -173,13 +178,13 @@ class TestFileJpeg(PillowTestCase):
|
||||||
self.assertGreaterEqual(im1.bytes, im3.bytes)
|
self.assertGreaterEqual(im1.bytes, im3.bytes)
|
||||||
|
|
||||||
def test_progressive_large_buffer(self):
|
def test_progressive_large_buffer(self):
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
# this requires ~ 1.5x Image.MAXBLOCK
|
# this requires ~ 1.5x Image.MAXBLOCK
|
||||||
im = Image.new("RGB", (4096, 4096), 0xff3333)
|
im = Image.new("RGB", (4096, 4096), 0xFF3333)
|
||||||
im.save(f, format="JPEG", progressive=True)
|
im.save(f, format="JPEG", progressive=True)
|
||||||
|
|
||||||
def test_progressive_large_buffer_highest_quality(self):
|
def test_progressive_large_buffer_highest_quality(self):
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
im = self.gen_random_image((255, 255))
|
im = self.gen_random_image((255, 255))
|
||||||
# this requires more bytes than pixels in the image
|
# this requires more bytes than pixels in the image
|
||||||
im.save(f, format="JPEG", progressive=True, quality=100)
|
im.save(f, format="JPEG", progressive=True, quality=100)
|
||||||
|
@ -187,30 +192,31 @@ class TestFileJpeg(PillowTestCase):
|
||||||
def test_progressive_cmyk_buffer(self):
|
def test_progressive_cmyk_buffer(self):
|
||||||
# Issue 2272, quality 90 cmyk image is tripping the large buffer bug.
|
# Issue 2272, quality 90 cmyk image is tripping the large buffer bug.
|
||||||
f = BytesIO()
|
f = BytesIO()
|
||||||
im = self.gen_random_image((256, 256), 'CMYK')
|
im = self.gen_random_image((256, 256), "CMYK")
|
||||||
im.save(f, format='JPEG', progressive=True, quality=94)
|
im.save(f, format="JPEG", progressive=True, quality=94)
|
||||||
|
|
||||||
def test_large_exif(self):
|
def test_large_exif(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/148
|
# https://github.com/python-pillow/Pillow/issues/148
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
im = hopper()
|
im = hopper()
|
||||||
im.save(f, 'JPEG', quality=90, exif=b"1"*65532)
|
im.save(f, "JPEG", quality=90, exif=b"1" * 65532)
|
||||||
|
|
||||||
def test_exif_typeerror(self):
|
def test_exif_typeerror(self):
|
||||||
im = Image.open('Tests/images/exif_typeerror.jpg')
|
im = Image.open("Tests/images/exif_typeerror.jpg")
|
||||||
# Should not raise a TypeError
|
# Should not raise a TypeError
|
||||||
im._getexif()
|
im._getexif()
|
||||||
|
|
||||||
def test_exif_gps(self):
|
def test_exif_gps(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.open('Tests/images/exif_gps.jpg')
|
im = Image.open("Tests/images/exif_gps.jpg")
|
||||||
gps_index = 34853
|
gps_index = 34853
|
||||||
expected_exif_gps = {
|
expected_exif_gps = {
|
||||||
0: b'\x00\x00\x00\x01',
|
0: b"\x00\x00\x00\x01",
|
||||||
2: (4294967295, 1),
|
2: (4294967295, 1),
|
||||||
5: b'\x01',
|
5: b"\x01",
|
||||||
30: 65535,
|
30: 65535,
|
||||||
29: '1999:99:99 99:99:99'}
|
29: "1999:99:99 99:99:99",
|
||||||
|
}
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
exif = im._getexif()
|
exif = im._getexif()
|
||||||
|
@ -222,35 +228,39 @@ class TestFileJpeg(PillowTestCase):
|
||||||
# rolling back exif support in 3.1 to pre-3.0 formatting.
|
# rolling back exif support in 3.1 to pre-3.0 formatting.
|
||||||
# expected from 2.9, with b/u qualifiers switched for 3.2 compatibility
|
# expected from 2.9, with b/u qualifiers switched for 3.2 compatibility
|
||||||
# this test passes on 2.9 and 3.1, but not 3.0
|
# this test passes on 2.9 and 3.1, but not 3.0
|
||||||
expected_exif = {34867: 4294967295,
|
expected_exif = {
|
||||||
258: (24, 24, 24),
|
34867: 4294967295,
|
||||||
36867: '2099:09:29 10:10:10',
|
258: (24, 24, 24),
|
||||||
34853: {0: b'\x00\x00\x00\x01',
|
36867: "2099:09:29 10:10:10",
|
||||||
2: (4294967295, 1),
|
34853: {
|
||||||
5: b'\x01',
|
0: b"\x00\x00\x00\x01",
|
||||||
30: 65535,
|
2: (4294967295, 1),
|
||||||
29: '1999:99:99 99:99:99'},
|
5: b"\x01",
|
||||||
296: 65535,
|
30: 65535,
|
||||||
34665: 185,
|
29: "1999:99:99 99:99:99",
|
||||||
41994: 65535,
|
},
|
||||||
514: 4294967295,
|
296: 65535,
|
||||||
271: 'Make',
|
34665: 185,
|
||||||
272: 'XXX-XXX',
|
41994: 65535,
|
||||||
305: 'PIL',
|
514: 4294967295,
|
||||||
42034: ((1, 1), (1, 1), (1, 1), (1, 1)),
|
271: "Make",
|
||||||
42035: 'LensMake',
|
272: "XXX-XXX",
|
||||||
34856: b'\xaa\xaa\xaa\xaa\xaa\xaa',
|
305: "PIL",
|
||||||
282: (4294967295, 1),
|
42034: ((1, 1), (1, 1), (1, 1), (1, 1)),
|
||||||
33434: (4294967295, 1)}
|
42035: "LensMake",
|
||||||
|
34856: b"\xaa\xaa\xaa\xaa\xaa\xaa",
|
||||||
|
282: (4294967295, 1),
|
||||||
|
33434: (4294967295, 1),
|
||||||
|
}
|
||||||
|
|
||||||
im = Image.open('Tests/images/exif_gps.jpg')
|
im = Image.open("Tests/images/exif_gps.jpg")
|
||||||
exif = im._getexif()
|
exif = im._getexif()
|
||||||
|
|
||||||
for tag, value in expected_exif.items():
|
for tag, value in expected_exif.items():
|
||||||
self.assertEqual(value, exif[tag])
|
self.assertEqual(value, exif[tag])
|
||||||
|
|
||||||
def test_exif_gps_typeerror(self):
|
def test_exif_gps_typeerror(self):
|
||||||
im = Image.open('Tests/images/exif_gps_typeerror.jpg')
|
im = Image.open("Tests/images/exif_gps_typeerror.jpg")
|
||||||
|
|
||||||
# Should not raise a TypeError
|
# Should not raise a TypeError
|
||||||
im._getexif()
|
im._getexif()
|
||||||
|
@ -291,6 +301,7 @@ class TestFileJpeg(PillowTestCase):
|
||||||
def getsampling(im):
|
def getsampling(im):
|
||||||
layer = im.layer
|
layer = im.layer
|
||||||
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
|
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
|
||||||
|
|
||||||
# experimental API
|
# experimental API
|
||||||
im = self.roundtrip(hopper(), subsampling=-1) # default
|
im = self.roundtrip(hopper(), subsampling=-1) # default
|
||||||
self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
|
self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
|
||||||
|
@ -312,13 +323,12 @@ class TestFileJpeg(PillowTestCase):
|
||||||
im = self.roundtrip(hopper(), subsampling="4:1:1")
|
im = self.roundtrip(hopper(), subsampling="4:1:1")
|
||||||
self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
|
self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
|
||||||
TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
|
|
||||||
|
|
||||||
def test_exif(self):
|
def test_exif(self):
|
||||||
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||||
info = im._getexif()
|
info = im._getexif()
|
||||||
self.assertEqual(info[305], 'Adobe Photoshop CS Macintosh')
|
self.assertEqual(info[305], "Adobe Photoshop CS Macintosh")
|
||||||
|
|
||||||
def test_mp(self):
|
def test_mp(self):
|
||||||
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||||
|
@ -327,16 +337,16 @@ class TestFileJpeg(PillowTestCase):
|
||||||
def test_quality_keep(self):
|
def test_quality_keep(self):
|
||||||
# RGB
|
# RGB
|
||||||
im = Image.open("Tests/images/hopper.jpg")
|
im = Image.open("Tests/images/hopper.jpg")
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
im.save(f, quality='keep')
|
im.save(f, quality="keep")
|
||||||
# Grayscale
|
# Grayscale
|
||||||
im = Image.open("Tests/images/hopper_gray.jpg")
|
im = Image.open("Tests/images/hopper_gray.jpg")
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
im.save(f, quality='keep')
|
im.save(f, quality="keep")
|
||||||
# CMYK
|
# CMYK
|
||||||
im = Image.open("Tests/images/pil_sample_cmyk.jpg")
|
im = Image.open("Tests/images/pil_sample_cmyk.jpg")
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
im.save(f, quality='keep')
|
im.save(f, quality="keep")
|
||||||
|
|
||||||
def test_junk_jpeg_header(self):
|
def test_junk_jpeg_header(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/630
|
# https://github.com/python-pillow/Pillow/issues/630
|
||||||
|
@ -364,8 +374,8 @@ class TestFileJpeg(PillowTestCase):
|
||||||
|
|
||||||
def _n_qtables_helper(self, n, test_file):
|
def _n_qtables_helper(self, n, test_file):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
f = self.tempfile('temp.jpg')
|
f = self.tempfile("temp.jpg")
|
||||||
im.save(f, qtables=[[n]*64]*n)
|
im.save(f, qtables=[[n] * 64] * n)
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
self.assertEqual(len(im.quantization), n)
|
self.assertEqual(len(im.quantization), n)
|
||||||
reloaded = self.roundtrip(im, qtables="keep")
|
reloaded = self.roundtrip(im, qtables="keep")
|
||||||
|
@ -376,18 +386,18 @@ class TestFileJpeg(PillowTestCase):
|
||||||
qtables = im.quantization
|
qtables = im.quantization
|
||||||
reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
|
reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
|
||||||
self.assertEqual(im.quantization, reloaded.quantization)
|
self.assertEqual(im.quantization, reloaded.quantization)
|
||||||
self.assert_image_similar(im, self.roundtrip(im, qtables='web_low'),
|
self.assert_image_similar(im, self.roundtrip(im, qtables="web_low"), 30)
|
||||||
30)
|
self.assert_image_similar(im, self.roundtrip(im, qtables="web_high"), 30)
|
||||||
self.assert_image_similar(im, self.roundtrip(im, qtables='web_high'),
|
self.assert_image_similar(im, self.roundtrip(im, qtables="keep"), 30)
|
||||||
30)
|
|
||||||
self.assert_image_similar(im, self.roundtrip(im, qtables='keep'), 30)
|
|
||||||
|
|
||||||
# valid bounds for baseline qtable
|
# valid bounds for baseline qtable
|
||||||
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
|
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
|
||||||
self.roundtrip(im, qtables=[bounds_qtable])
|
self.roundtrip(im, qtables=[bounds_qtable])
|
||||||
|
|
||||||
# values from wizard.txt in jpeg9-a src package.
|
# values from wizard.txt in jpeg9-a src package.
|
||||||
standard_l_qtable = [int(s) for s in """
|
standard_l_qtable = [
|
||||||
|
int(s)
|
||||||
|
for s in """
|
||||||
16 11 10 16 24 40 51 61
|
16 11 10 16 24 40 51 61
|
||||||
12 12 14 19 26 58 60 55
|
12 12 14 19 26 58 60 55
|
||||||
14 13 16 24 40 57 69 56
|
14 13 16 24 40 57 69 56
|
||||||
|
@ -396,9 +406,14 @@ class TestFileJpeg(PillowTestCase):
|
||||||
24 35 55 64 81 104 113 92
|
24 35 55 64 81 104 113 92
|
||||||
49 64 78 87 103 121 120 101
|
49 64 78 87 103 121 120 101
|
||||||
72 92 95 98 112 100 103 99
|
72 92 95 98 112 100 103 99
|
||||||
""".split(None)]
|
""".split(
|
||||||
|
None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
standard_chrominance_qtable = [int(s) for s in """
|
standard_chrominance_qtable = [
|
||||||
|
int(s)
|
||||||
|
for s in """
|
||||||
17 18 24 47 99 99 99 99
|
17 18 24 47 99 99 99 99
|
||||||
18 21 26 66 99 99 99 99
|
18 21 26 66 99 99 99 99
|
||||||
24 26 56 99 99 99 99 99
|
24 26 56 99 99 99 99 99
|
||||||
|
@ -407,25 +422,36 @@ class TestFileJpeg(PillowTestCase):
|
||||||
99 99 99 99 99 99 99 99
|
99 99 99 99 99 99 99 99
|
||||||
99 99 99 99 99 99 99 99
|
99 99 99 99 99 99 99 99
|
||||||
99 99 99 99 99 99 99 99
|
99 99 99 99 99 99 99 99
|
||||||
""".split(None)]
|
""".split(
|
||||||
|
None
|
||||||
|
)
|
||||||
|
]
|
||||||
# list of qtable lists
|
# list of qtable lists
|
||||||
self.assert_image_similar(
|
self.assert_image_similar(
|
||||||
im, self.roundtrip(
|
im,
|
||||||
im, qtables=[standard_l_qtable, standard_chrominance_qtable]),
|
self.roundtrip(
|
||||||
30)
|
im, qtables=[standard_l_qtable, standard_chrominance_qtable]
|
||||||
|
),
|
||||||
|
30,
|
||||||
|
)
|
||||||
|
|
||||||
# tuple of qtable lists
|
# tuple of qtable lists
|
||||||
self.assert_image_similar(
|
self.assert_image_similar(
|
||||||
im, self.roundtrip(
|
im,
|
||||||
im, qtables=(standard_l_qtable, standard_chrominance_qtable)),
|
self.roundtrip(
|
||||||
30)
|
im, qtables=(standard_l_qtable, standard_chrominance_qtable)
|
||||||
|
),
|
||||||
|
30,
|
||||||
|
)
|
||||||
|
|
||||||
# dict of qtable lists
|
# dict of qtable lists
|
||||||
self.assert_image_similar(im,
|
self.assert_image_similar(
|
||||||
self.roundtrip(im, qtables={
|
im,
|
||||||
0: standard_l_qtable,
|
self.roundtrip(
|
||||||
1: standard_chrominance_qtable
|
im, qtables={0: standard_l_qtable, 1: standard_chrominance_qtable}
|
||||||
}), 30)
|
),
|
||||||
|
30,
|
||||||
|
)
|
||||||
|
|
||||||
self._n_qtables_helper(1, "Tests/images/hopper_gray.jpg")
|
self._n_qtables_helper(1, "Tests/images/hopper_gray.jpg")
|
||||||
self._n_qtables_helper(1, "Tests/images/pil_sample_rgb.jpg")
|
self._n_qtables_helper(1, "Tests/images/pil_sample_rgb.jpg")
|
||||||
|
@ -437,18 +463,16 @@ class TestFileJpeg(PillowTestCase):
|
||||||
self._n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
|
self._n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
|
||||||
|
|
||||||
# not a sequence
|
# not a sequence
|
||||||
self.assertRaises(ValueError, self.roundtrip, im, qtables='a')
|
self.assertRaises(ValueError, self.roundtrip, im, qtables="a")
|
||||||
# sequence wrong length
|
# sequence wrong length
|
||||||
self.assertRaises(ValueError, self.roundtrip, im, qtables=[])
|
self.assertRaises(ValueError, self.roundtrip, im, qtables=[])
|
||||||
# sequence wrong length
|
# sequence wrong length
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
|
||||||
self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
|
|
||||||
|
|
||||||
# qtable entry not a sequence
|
# qtable entry not a sequence
|
||||||
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1])
|
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1])
|
||||||
# qtable entry has wrong number of items
|
# qtable entry has wrong number of items
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, self.roundtrip, im, qtables=[[1, 2, 3, 4]])
|
||||||
self.roundtrip, im, qtables=[[1, 2, 3, 4]])
|
|
||||||
|
|
||||||
@unittest.skipUnless(djpeg_available(), "djpeg not available")
|
@unittest.skipUnless(djpeg_available(), "djpeg not available")
|
||||||
def test_load_djpeg(self):
|
def test_load_djpeg(self):
|
||||||
|
@ -468,11 +492,12 @@ class TestFileJpeg(PillowTestCase):
|
||||||
def test_no_duplicate_0x1001_tag(self):
|
def test_no_duplicate_0x1001_tag(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ExifTags
|
from PIL import ExifTags
|
||||||
|
|
||||||
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
|
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(tag_ids['RelatedImageWidth'], 0x1001)
|
self.assertEqual(tag_ids["RelatedImageWidth"], 0x1001)
|
||||||
self.assertEqual(tag_ids['RelatedImageLength'], 0x1002)
|
self.assertEqual(tag_ids["RelatedImageLength"], 0x1002)
|
||||||
|
|
||||||
def test_MAXBLOCK_scaling(self):
|
def test_MAXBLOCK_scaling(self):
|
||||||
im = self.gen_random_image((512, 512))
|
im = self.gen_random_image((512, 512))
|
||||||
|
@ -482,9 +507,9 @@ class TestFileJpeg(PillowTestCase):
|
||||||
reloaded = Image.open(f)
|
reloaded = Image.open(f)
|
||||||
|
|
||||||
# none of these should crash
|
# none of these should crash
|
||||||
reloaded.save(f, quality='keep')
|
reloaded.save(f, quality="keep")
|
||||||
reloaded.save(f, quality='keep', progressive=True)
|
reloaded.save(f, quality="keep", progressive=True)
|
||||||
reloaded.save(f, quality='keep', optimize=True)
|
reloaded.save(f, quality="keep", optimize=True)
|
||||||
|
|
||||||
def test_bad_mpo_header(self):
|
def test_bad_mpo_header(self):
|
||||||
""" Treat unknown MPO as JPEG """
|
""" Treat unknown MPO as JPEG """
|
||||||
|
@ -500,14 +525,14 @@ class TestFileJpeg(PillowTestCase):
|
||||||
|
|
||||||
def test_save_correct_modes(self):
|
def test_save_correct_modes(self):
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
for mode in ['1', 'L', 'RGB', 'RGBX', 'CMYK', 'YCbCr']:
|
for mode in ["1", "L", "RGB", "RGBX", "CMYK", "YCbCr"]:
|
||||||
img = Image.new(mode, (20, 20))
|
img = Image.new(mode, (20, 20))
|
||||||
img.save(out, "JPEG")
|
img.save(out, "JPEG")
|
||||||
|
|
||||||
def test_save_wrong_modes(self):
|
def test_save_wrong_modes(self):
|
||||||
# ref https://github.com/python-pillow/Pillow/issues/2005
|
# ref https://github.com/python-pillow/Pillow/issues/2005
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
for mode in ['LA', 'La', 'RGBA', 'RGBa', 'P']:
|
for mode in ["LA", "La", "RGBA", "RGBa", "P"]:
|
||||||
img = Image.new(mode, (20, 20))
|
img = Image.new(mode, (20, 20))
|
||||||
self.assertRaises(IOError, img.save, out, "JPEG")
|
self.assertRaises(IOError, img.save, out, "JPEG")
|
||||||
|
|
||||||
|
@ -517,25 +542,25 @@ class TestFileJpeg(PillowTestCase):
|
||||||
im = Image.open("Tests/images/hopper.tif")
|
im = Image.open("Tests/images/hopper.tif")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
im.save(outfile, 'JPEG', dpi=im.info['dpi'])
|
im.save(outfile, "JPEG", dpi=im.info["dpi"])
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
reloaded.load()
|
reloaded.load()
|
||||||
self.assertEqual(im.info['dpi'], reloaded.info['dpi'])
|
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
|
||||||
|
|
||||||
def test_load_dpi_rounding(self):
|
def test_load_dpi_rounding(self):
|
||||||
# Round up
|
# Round up
|
||||||
im = Image.open('Tests/images/iptc_roundUp.jpg')
|
im = Image.open("Tests/images/iptc_roundUp.jpg")
|
||||||
self.assertEqual(im.info["dpi"], (44, 44))
|
self.assertEqual(im.info["dpi"], (44, 44))
|
||||||
|
|
||||||
# Round down
|
# Round down
|
||||||
im = Image.open('Tests/images/iptc_roundDown.jpg')
|
im = Image.open("Tests/images/iptc_roundDown.jpg")
|
||||||
self.assertEqual(im.info["dpi"], (2, 2))
|
self.assertEqual(im.info["dpi"], (2, 2))
|
||||||
|
|
||||||
def test_save_dpi_rounding(self):
|
def test_save_dpi_rounding(self):
|
||||||
outfile = self.tempfile("temp.jpg")
|
outfile = self.tempfile("temp.jpg")
|
||||||
im = Image.open('Tests/images/hopper.jpg')
|
im = Image.open("Tests/images/hopper.jpg")
|
||||||
|
|
||||||
im.save(outfile, dpi=(72.2, 72.2))
|
im.save(outfile, dpi=(72.2, 72.2))
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
|
@ -609,23 +634,26 @@ class TestFileJpeg(PillowTestCase):
|
||||||
im = Image.open("Tests/images/exif-ifd-offset.jpg")
|
im = Image.open("Tests/images/exif-ifd-offset.jpg")
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertEqual(im._getexif()[306], '2017:03:13 23:03:09')
|
self.assertEqual(im._getexif()[306], "2017:03:13 23:03:09")
|
||||||
|
|
||||||
def test_photoshop(self):
|
def test_photoshop(self):
|
||||||
im = Image.open("Tests/images/photoshop-200dpi.jpg")
|
im = Image.open("Tests/images/photoshop-200dpi.jpg")
|
||||||
self.assertEqual(im.info["photoshop"][0x03ed], {
|
self.assertEqual(
|
||||||
'XResolution': 200.0,
|
im.info["photoshop"][0x03ED],
|
||||||
'DisplayedUnitsX': 1,
|
{
|
||||||
'YResolution': 200.0,
|
"XResolution": 200.0,
|
||||||
'DisplayedUnitsY': 1,
|
"DisplayedUnitsX": 1,
|
||||||
})
|
"YResolution": 200.0,
|
||||||
|
"DisplayedUnitsY": 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
# This image does not contain a Photoshop header string
|
# This image does not contain a Photoshop header string
|
||||||
im = Image.open("Tests/images/app13.jpg")
|
im = Image.open("Tests/images/app13.jpg")
|
||||||
self.assertNotIn("photoshop", im.info)
|
self.assertNotIn("photoshop", im.info)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only")
|
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
|
||||||
class TestFileCloseW32(PillowTestCase):
|
class TestFileCloseW32(PillowTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
|
|
|
@ -5,7 +5,7 @@ from io import BytesIO
|
||||||
|
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
|
|
||||||
test_card = Image.open('Tests/images/test-card.png')
|
test_card = Image.open("Tests/images/test-card.png")
|
||||||
test_card.load()
|
test_card.load()
|
||||||
|
|
||||||
# OpenJPEG 2.0.0 outputs this debugging message sometimes; we should
|
# OpenJPEG 2.0.0 outputs this debugging message sometimes; we should
|
||||||
|
@ -14,10 +14,9 @@ test_card.load()
|
||||||
|
|
||||||
|
|
||||||
class TestFileJpeg2k(PillowTestCase):
|
class TestFileJpeg2k(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
|
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
|
||||||
self.skipTest('JPEG 2000 support not available')
|
self.skipTest("JPEG 2000 support not available")
|
||||||
|
|
||||||
def roundtrip(self, im, **options):
|
def roundtrip(self, im, **options):
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
|
@ -31,29 +30,28 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
# Internal version number
|
# Internal version number
|
||||||
self.assertRegex(Image.core.jp2klib_version, r'\d+\.\d+\.\d+$')
|
self.assertRegex(Image.core.jp2klib_version, r"\d+\.\d+\.\d+$")
|
||||||
|
|
||||||
im = Image.open('Tests/images/test-card-lossless.jp2')
|
im = Image.open("Tests/images/test-card-lossless.jp2")
|
||||||
px = im.load()
|
px = im.load()
|
||||||
self.assertEqual(px[0, 0], (0, 0, 0))
|
self.assertEqual(px[0, 0], (0, 0, 0))
|
||||||
self.assertEqual(im.mode, 'RGB')
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (640, 480))
|
self.assertEqual(im.size, (640, 480))
|
||||||
self.assertEqual(im.format, 'JPEG2000')
|
self.assertEqual(im.format, "JPEG2000")
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/jp2')
|
self.assertEqual(im.get_format_mimetype(), "image/jp2")
|
||||||
|
|
||||||
def test_jpf(self):
|
def test_jpf(self):
|
||||||
im = Image.open('Tests/images/balloon.jpf')
|
im = Image.open("Tests/images/balloon.jpf")
|
||||||
self.assertEqual(im.format, 'JPEG2000')
|
self.assertEqual(im.format, "JPEG2000")
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/jpx')
|
self.assertEqual(im.get_format_mimetype(), "image/jpx")
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, Jpeg2KImagePlugin.Jpeg2KImageFile, invalid_file)
|
||||||
Jpeg2KImagePlugin.Jpeg2KImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_bytesio(self):
|
def test_bytesio(self):
|
||||||
with open('Tests/images/test-card-lossless.jp2', 'rb') as f:
|
with open("Tests/images/test-card-lossless.jp2", "rb") as f:
|
||||||
data = BytesIO(f.read())
|
data = BytesIO(f.read())
|
||||||
im = Image.open(data)
|
im = Image.open(data)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -63,14 +61,14 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
# PIL (they were made using Adobe Photoshop)
|
# PIL (they were made using Adobe Photoshop)
|
||||||
|
|
||||||
def test_lossless(self):
|
def test_lossless(self):
|
||||||
im = Image.open('Tests/images/test-card-lossless.jp2')
|
im = Image.open("Tests/images/test-card-lossless.jp2")
|
||||||
im.load()
|
im.load()
|
||||||
outfile = self.tempfile('temp_test-card.png')
|
outfile = self.tempfile("temp_test-card.png")
|
||||||
im.save(outfile)
|
im.save(outfile)
|
||||||
self.assert_image_similar(im, test_card, 1.0e-3)
|
self.assert_image_similar(im, test_card, 1.0e-3)
|
||||||
|
|
||||||
def test_lossy_tiled(self):
|
def test_lossy_tiled(self):
|
||||||
im = Image.open('Tests/images/test-card-lossy-tiled.jp2')
|
im = Image.open("Tests/images/test-card-lossy-tiled.jp2")
|
||||||
im.load()
|
im.load()
|
||||||
self.assert_image_similar(im, test_card, 2.0)
|
self.assert_image_similar(im, test_card, 2.0)
|
||||||
|
|
||||||
|
@ -88,8 +86,8 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
|
|
||||||
def test_tiled_offset_rt(self):
|
def test_tiled_offset_rt(self):
|
||||||
im = self.roundtrip(
|
im = self.roundtrip(
|
||||||
test_card, tile_size=(128, 128),
|
test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32)
|
||||||
tile_offset=(0, 0), offset=(32, 32))
|
)
|
||||||
self.assert_image_equal(im, test_card)
|
self.assert_image_equal(im, test_card)
|
||||||
|
|
||||||
def test_irreversible_rt(self):
|
def test_irreversible_rt(self):
|
||||||
|
@ -97,40 +95,34 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
self.assert_image_similar(im, test_card, 2.0)
|
self.assert_image_similar(im, test_card, 2.0)
|
||||||
|
|
||||||
def test_prog_qual_rt(self):
|
def test_prog_qual_rt(self):
|
||||||
im = self.roundtrip(
|
im = self.roundtrip(test_card, quality_layers=[60, 40, 20], progression="LRCP")
|
||||||
test_card, quality_layers=[60, 40, 20], progression='LRCP')
|
|
||||||
self.assert_image_similar(im, test_card, 2.0)
|
self.assert_image_similar(im, test_card, 2.0)
|
||||||
|
|
||||||
def test_prog_res_rt(self):
|
def test_prog_res_rt(self):
|
||||||
im = self.roundtrip(test_card, num_resolutions=8, progression='RLCP')
|
im = self.roundtrip(test_card, num_resolutions=8, progression="RLCP")
|
||||||
self.assert_image_equal(im, test_card)
|
self.assert_image_equal(im, test_card)
|
||||||
|
|
||||||
def test_reduce(self):
|
def test_reduce(self):
|
||||||
im = Image.open('Tests/images/test-card-lossless.jp2')
|
im = Image.open("Tests/images/test-card-lossless.jp2")
|
||||||
im.reduce = 2
|
im.reduce = 2
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.size, (160, 120))
|
self.assertEqual(im.size, (160, 120))
|
||||||
|
|
||||||
def test_layers_type(self):
|
def test_layers_type(self):
|
||||||
outfile = self.tempfile('temp_layers.jp2')
|
outfile = self.tempfile("temp_layers.jp2")
|
||||||
for quality_layers in [
|
for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
|
||||||
[100, 50, 10],
|
|
||||||
(100, 50, 10),
|
|
||||||
None
|
|
||||||
]:
|
|
||||||
test_card.save(outfile, quality_layers=quality_layers)
|
test_card.save(outfile, quality_layers=quality_layers)
|
||||||
|
|
||||||
for quality_layers in [
|
for quality_layers in ["quality_layers", ("100", "50", "10")]:
|
||||||
'quality_layers',
|
self.assertRaises(
|
||||||
('100', '50', '10')
|
ValueError, test_card.save, outfile, quality_layers=quality_layers
|
||||||
]:
|
)
|
||||||
self.assertRaises(ValueError, test_card.save, outfile,
|
|
||||||
quality_layers=quality_layers)
|
|
||||||
|
|
||||||
def test_layers(self):
|
def test_layers(self):
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
test_card.save(out, 'JPEG2000', quality_layers=[100, 50, 10],
|
test_card.save(
|
||||||
progression='LRCP')
|
out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP"
|
||||||
|
)
|
||||||
out.seek(0)
|
out.seek(0)
|
||||||
|
|
||||||
im = Image.open(out)
|
im = Image.open(out)
|
||||||
|
@ -146,49 +138,49 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
|
|
||||||
def test_rgba(self):
|
def test_rgba(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
j2k = Image.open('Tests/images/rgb_trns_ycbc.j2k')
|
j2k = Image.open("Tests/images/rgb_trns_ycbc.j2k")
|
||||||
jp2 = Image.open('Tests/images/rgb_trns_ycbc.jp2')
|
jp2 = Image.open("Tests/images/rgb_trns_ycbc.jp2")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
j2k.load()
|
j2k.load()
|
||||||
jp2.load()
|
jp2.load()
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(j2k.mode, 'RGBA')
|
self.assertEqual(j2k.mode, "RGBA")
|
||||||
self.assertEqual(jp2.mode, 'RGBA')
|
self.assertEqual(jp2.mode, "RGBA")
|
||||||
|
|
||||||
def test_16bit_monochrome_has_correct_mode(self):
|
def test_16bit_monochrome_has_correct_mode(self):
|
||||||
|
|
||||||
j2k = Image.open('Tests/images/16bit.cropped.j2k')
|
j2k = Image.open("Tests/images/16bit.cropped.j2k")
|
||||||
jp2 = Image.open('Tests/images/16bit.cropped.jp2')
|
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
|
||||||
|
|
||||||
j2k.load()
|
j2k.load()
|
||||||
jp2.load()
|
jp2.load()
|
||||||
|
|
||||||
self.assertEqual(j2k.mode, 'I;16')
|
self.assertEqual(j2k.mode, "I;16")
|
||||||
self.assertEqual(jp2.mode, 'I;16')
|
self.assertEqual(jp2.mode, "I;16")
|
||||||
|
|
||||||
def test_16bit_monochrome_jp2_like_tiff(self):
|
def test_16bit_monochrome_jp2_like_tiff(self):
|
||||||
|
|
||||||
tiff_16bit = Image.open('Tests/images/16bit.cropped.tif')
|
tiff_16bit = Image.open("Tests/images/16bit.cropped.tif")
|
||||||
jp2 = Image.open('Tests/images/16bit.cropped.jp2')
|
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
|
||||||
self.assert_image_similar(jp2, tiff_16bit, 1e-3)
|
self.assert_image_similar(jp2, tiff_16bit, 1e-3)
|
||||||
|
|
||||||
def test_16bit_monochrome_j2k_like_tiff(self):
|
def test_16bit_monochrome_j2k_like_tiff(self):
|
||||||
|
|
||||||
tiff_16bit = Image.open('Tests/images/16bit.cropped.tif')
|
tiff_16bit = Image.open("Tests/images/16bit.cropped.tif")
|
||||||
j2k = Image.open('Tests/images/16bit.cropped.j2k')
|
j2k = Image.open("Tests/images/16bit.cropped.j2k")
|
||||||
self.assert_image_similar(j2k, tiff_16bit, 1e-3)
|
self.assert_image_similar(j2k, tiff_16bit, 1e-3)
|
||||||
|
|
||||||
def test_16bit_j2k_roundtrips(self):
|
def test_16bit_j2k_roundtrips(self):
|
||||||
|
|
||||||
j2k = Image.open('Tests/images/16bit.cropped.j2k')
|
j2k = Image.open("Tests/images/16bit.cropped.j2k")
|
||||||
im = self.roundtrip(j2k)
|
im = self.roundtrip(j2k)
|
||||||
self.assert_image_equal(im, j2k)
|
self.assert_image_equal(im, j2k)
|
||||||
|
|
||||||
def test_16bit_jp2_roundtrips(self):
|
def test_16bit_jp2_roundtrips(self):
|
||||||
|
|
||||||
jp2 = Image.open('Tests/images/16bit.cropped.jp2')
|
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
|
||||||
im = self.roundtrip(jp2)
|
im = self.roundtrip(jp2)
|
||||||
self.assert_image_equal(im, jp2)
|
self.assert_image_equal(im, jp2)
|
||||||
|
|
||||||
|
@ -196,12 +188,13 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
# prepatch, a malformed jp2 file could cause an UnboundLocalError
|
# prepatch, a malformed jp2 file could cause an UnboundLocalError
|
||||||
# exception.
|
# exception.
|
||||||
with self.assertRaises(IOError):
|
with self.assertRaises(IOError):
|
||||||
Image.open('Tests/images/unbound_variable.jp2')
|
Image.open("Tests/images/unbound_variable.jp2")
|
||||||
|
|
||||||
def test_parser_feed(self):
|
def test_parser_feed(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ImageFile
|
from PIL import ImageFile
|
||||||
with open('Tests/images/test-card-lossless.jp2', 'rb') as f:
|
|
||||||
|
with open("Tests/images/test-card-lossless.jp2", "rb") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
|
|
@ -16,9 +16,8 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LibTiffTestCase(PillowTestCase):
|
class LibTiffTestCase(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if not features.check('libtiff'):
|
if not features.check("libtiff"):
|
||||||
self.skipTest("tiff support not available")
|
self.skipTest("tiff support not available")
|
||||||
|
|
||||||
def _assert_noerr(self, im):
|
def _assert_noerr(self, im):
|
||||||
|
@ -31,7 +30,7 @@ class LibTiffTestCase(PillowTestCase):
|
||||||
im.getdata()
|
im.getdata()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.assertEqual(im._compression, 'group4')
|
self.assertEqual(im._compression, "group4")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print("No _compression")
|
print("No _compression")
|
||||||
print(dir(im))
|
print(dir(im))
|
||||||
|
@ -41,11 +40,10 @@ class LibTiffTestCase(PillowTestCase):
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
||||||
out_bytes = io.BytesIO()
|
out_bytes = io.BytesIO()
|
||||||
im.save(out_bytes, format='tiff', compression='group4')
|
im.save(out_bytes, format="tiff", compression="group4")
|
||||||
|
|
||||||
|
|
||||||
class TestFileLibTiff(LibTiffTestCase):
|
class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
def test_g4_tiff(self):
|
def test_g4_tiff(self):
|
||||||
"""Test the ordinary file path load path"""
|
"""Test the ordinary file path load path"""
|
||||||
|
|
||||||
|
@ -64,7 +62,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
"""Testing the string load path"""
|
"""Testing the string load path"""
|
||||||
|
|
||||||
test_file = "Tests/images/hopper_g4_500.tif"
|
test_file = "Tests/images/hopper_g4_500.tif"
|
||||||
with open(test_file, 'rb') as f:
|
with open(test_file, "rb") as f:
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
|
|
||||||
self.assertEqual(im.size, (500, 500))
|
self.assertEqual(im.size, (500, 500))
|
||||||
|
@ -74,7 +72,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
"""Testing the stringio loading code path"""
|
"""Testing the stringio loading code path"""
|
||||||
test_file = "Tests/images/hopper_g4_500.tif"
|
test_file = "Tests/images/hopper_g4_500.tif"
|
||||||
s = io.BytesIO()
|
s = io.BytesIO()
|
||||||
with open(test_file, 'rb') as f:
|
with open(test_file, "rb") as f:
|
||||||
s.write(f.read())
|
s.write(f.read())
|
||||||
s.seek(0)
|
s.seek(0)
|
||||||
im = Image.open(s)
|
im = Image.open(s)
|
||||||
|
@ -84,16 +82,16 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
def test_g4_eq_png(self):
|
def test_g4_eq_png(self):
|
||||||
""" Checking that we're actually getting the data that we expect"""
|
""" Checking that we're actually getting the data that we expect"""
|
||||||
png = Image.open('Tests/images/hopper_bw_500.png')
|
png = Image.open("Tests/images/hopper_bw_500.png")
|
||||||
g4 = Image.open('Tests/images/hopper_g4_500.tif')
|
g4 = Image.open("Tests/images/hopper_g4_500.tif")
|
||||||
|
|
||||||
self.assert_image_equal(g4, png)
|
self.assert_image_equal(g4, png)
|
||||||
|
|
||||||
# see https://github.com/python-pillow/Pillow/issues/279
|
# see https://github.com/python-pillow/Pillow/issues/279
|
||||||
def test_g4_fillorder_eq_png(self):
|
def test_g4_fillorder_eq_png(self):
|
||||||
""" Checking that we're actually getting the data that we expect"""
|
""" Checking that we're actually getting the data that we expect"""
|
||||||
png = Image.open('Tests/images/g4-fillorder-test.png')
|
png = Image.open("Tests/images/g4-fillorder-test.png")
|
||||||
g4 = Image.open('Tests/images/g4-fillorder-test.tif')
|
g4 = Image.open("Tests/images/g4-fillorder-test.tif")
|
||||||
|
|
||||||
self.assert_image_equal(g4, png)
|
self.assert_image_equal(g4, png)
|
||||||
|
|
||||||
|
@ -111,9 +109,9 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assertEqual(reread.size, (500, 500))
|
self.assertEqual(reread.size, (500, 500))
|
||||||
self._assert_noerr(reread)
|
self._assert_noerr(reread)
|
||||||
self.assert_image_equal(reread, rot)
|
self.assert_image_equal(reread, rot)
|
||||||
self.assertEqual(reread.info['compression'], 'group4')
|
self.assertEqual(reread.info["compression"], "group4")
|
||||||
|
|
||||||
self.assertEqual(reread.info['compression'], orig.info['compression'])
|
self.assertEqual(reread.info["compression"], orig.info["compression"])
|
||||||
|
|
||||||
self.assertNotEqual(orig.tobytes(), reread.tobytes())
|
self.assertNotEqual(orig.tobytes(), reread.tobytes())
|
||||||
|
|
||||||
|
@ -123,18 +121,16 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
self.assertEqual(im.mode, "RGB")
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (278, 374))
|
self.assertEqual(im.size, (278, 374))
|
||||||
self.assertEqual(
|
self.assertEqual(im.tile[0][:3], ("tiff_adobe_deflate", (0, 0, 278, 374), 0))
|
||||||
im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0))
|
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||||
'Tests/images/tiff_adobe_deflate.png')
|
|
||||||
|
|
||||||
def test_write_metadata(self):
|
def test_write_metadata(self):
|
||||||
""" Test metadata writing through libtiff """
|
""" Test metadata writing through libtiff """
|
||||||
for legacy_api in [False, True]:
|
for legacy_api in [False, True]:
|
||||||
img = Image.open('Tests/images/hopper_g4.tif')
|
img = Image.open("Tests/images/hopper_g4.tif")
|
||||||
f = self.tempfile('temp.tiff')
|
f = self.tempfile("temp.tiff")
|
||||||
|
|
||||||
img.save(f, tiffinfo=img.tag)
|
img.save(f, tiffinfo=img.tag)
|
||||||
|
|
||||||
|
@ -145,8 +141,12 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
# PhotometricInterpretation is set from SAVE_INFO,
|
# PhotometricInterpretation is set from SAVE_INFO,
|
||||||
# not the original image.
|
# not the original image.
|
||||||
ignored = ['StripByteCounts', 'RowsPerStrip', 'PageNumber',
|
ignored = [
|
||||||
'PhotometricInterpretation']
|
"StripByteCounts",
|
||||||
|
"RowsPerStrip",
|
||||||
|
"PageNumber",
|
||||||
|
"PhotometricInterpretation",
|
||||||
|
]
|
||||||
|
|
||||||
loaded = Image.open(f)
|
loaded = Image.open(f)
|
||||||
if legacy_api:
|
if legacy_api:
|
||||||
|
@ -154,28 +154,27 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
else:
|
else:
|
||||||
reloaded = loaded.tag_v2.named()
|
reloaded = loaded.tag_v2.named()
|
||||||
|
|
||||||
for tag, value in itertools.chain(reloaded.items(),
|
for tag, value in itertools.chain(reloaded.items(), original.items()):
|
||||||
original.items()):
|
|
||||||
if tag not in ignored:
|
if tag not in ignored:
|
||||||
val = original[tag]
|
val = original[tag]
|
||||||
if tag.endswith('Resolution'):
|
if tag.endswith("Resolution"):
|
||||||
if legacy_api:
|
if legacy_api:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
c_float(val[0][0] / val[0][1]).value,
|
c_float(val[0][0] / val[0][1]).value,
|
||||||
c_float(value[0][0] / value[0][1]).value,
|
c_float(value[0][0] / value[0][1]).value,
|
||||||
msg="%s didn't roundtrip" % tag)
|
msg="%s didn't roundtrip" % tag,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
c_float(val).value, c_float(value).value,
|
c_float(val).value,
|
||||||
msg="%s didn't roundtrip" % tag)
|
c_float(value).value,
|
||||||
|
msg="%s didn't roundtrip" % tag,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(val, value, msg="%s didn't roundtrip" % tag)
|
||||||
val, value, msg="%s didn't roundtrip" % tag)
|
|
||||||
|
|
||||||
# https://github.com/python-pillow/Pillow/issues/1561
|
# https://github.com/python-pillow/Pillow/issues/1561
|
||||||
requested_fields = ['StripByteCounts',
|
requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"]
|
||||||
'RowsPerStrip',
|
|
||||||
'StripOffsets']
|
|
||||||
for field in requested_fields:
|
for field in requested_fields:
|
||||||
self.assertIn(field, reloaded, "%s not in metadata" % field)
|
self.assertIn(field, reloaded, "%s not in metadata" % field)
|
||||||
|
|
||||||
|
@ -186,13 +185,15 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
# Get the list of the ones that we should be able to write
|
# Get the list of the ones that we should be able to write
|
||||||
|
|
||||||
core_items = {tag: info for tag, info in ((s, TiffTags.lookup(s)) for s
|
core_items = {
|
||||||
in TiffTags.LIBTIFF_CORE)
|
tag: info
|
||||||
if info.type is not None}
|
for tag, info in ((s, TiffTags.lookup(s)) for s in TiffTags.LIBTIFF_CORE)
|
||||||
|
if info.type is not None
|
||||||
|
}
|
||||||
|
|
||||||
# Exclude ones that have special meaning
|
# Exclude ones that have special meaning
|
||||||
# that we're already testing them
|
# that we're already testing them
|
||||||
im = Image.open('Tests/images/hopper_g4.tif')
|
im = Image.open("Tests/images/hopper_g4.tif")
|
||||||
for tag in im.tag_v2:
|
for tag in im.tag_v2:
|
||||||
try:
|
try:
|
||||||
del core_items[tag]
|
del core_items[tag]
|
||||||
|
@ -206,11 +207,13 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
# 5: "rational",
|
# 5: "rational",
|
||||||
# 12: "double",
|
# 12: "double",
|
||||||
# Type: dummy value
|
# Type: dummy value
|
||||||
values = {2: 'test',
|
values = {
|
||||||
3: 1,
|
2: "test",
|
||||||
4: 2**20,
|
3: 1,
|
||||||
5: TiffImagePlugin.IFDRational(100, 1),
|
4: 2 ** 20,
|
||||||
12: 1.05}
|
5: TiffImagePlugin.IFDRational(100, 1),
|
||||||
|
12: 1.05,
|
||||||
|
}
|
||||||
|
|
||||||
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
for tag, info in core_items.items():
|
for tag, info in core_items.items():
|
||||||
|
@ -219,8 +222,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
if info.length == 0:
|
if info.length == 0:
|
||||||
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
|
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
|
||||||
else:
|
else:
|
||||||
new_ifd[tag] = tuple(values[info.type]
|
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
|
||||||
for _ in range(info.length))
|
|
||||||
|
|
||||||
# Extra samples really doesn't make sense in this application.
|
# Extra samples really doesn't make sense in this application.
|
||||||
del new_ifd[338]
|
del new_ifd[338]
|
||||||
|
@ -236,16 +238,17 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
custom = {
|
custom = {
|
||||||
37000: [4, TiffTags.SHORT],
|
37000: [4, TiffTags.SHORT],
|
||||||
37001: [4.2, TiffTags.RATIONAL],
|
37001: [4.2, TiffTags.RATIONAL],
|
||||||
37002: ['custom tag value', TiffTags.ASCII],
|
37002: ["custom tag value", TiffTags.ASCII],
|
||||||
37003: [u'custom tag value', TiffTags.ASCII],
|
37003: [u"custom tag value", TiffTags.ASCII],
|
||||||
37004: [b'custom tag value', TiffTags.BYTE]
|
37004: [b"custom tag value", TiffTags.BYTE],
|
||||||
}
|
}
|
||||||
|
|
||||||
libtiff_version = TiffImagePlugin._libtiff_version()
|
libtiff_version = TiffImagePlugin._libtiff_version()
|
||||||
|
|
||||||
libtiffs = [False]
|
libtiffs = [False]
|
||||||
if distutils.version.StrictVersion(libtiff_version) >= \
|
if distutils.version.StrictVersion(
|
||||||
distutils.version.StrictVersion("4.0"):
|
libtiff_version
|
||||||
|
) >= distutils.version.StrictVersion("4.0"):
|
||||||
libtiffs.append(True)
|
libtiffs.append(True)
|
||||||
|
|
||||||
for libtiff in libtiffs:
|
for libtiff in libtiffs:
|
||||||
|
@ -281,68 +284,68 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
def test_int_dpi(self):
|
def test_int_dpi(self):
|
||||||
# issue #1765
|
# issue #1765
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
out = self.tempfile('temp.tif')
|
out = self.tempfile("temp.tif")
|
||||||
TiffImagePlugin.WRITE_LIBTIFF = True
|
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||||
im.save(out, dpi=(72, 72))
|
im.save(out, dpi=(72, 72))
|
||||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assertEqual(reloaded.info['dpi'], (72.0, 72.0))
|
self.assertEqual(reloaded.info["dpi"], (72.0, 72.0))
|
||||||
|
|
||||||
def test_g3_compression(self):
|
def test_g3_compression(self):
|
||||||
i = Image.open('Tests/images/hopper_g4_500.tif')
|
i = Image.open("Tests/images/hopper_g4_500.tif")
|
||||||
out = self.tempfile("temp.tif")
|
out = self.tempfile("temp.tif")
|
||||||
i.save(out, compression='group3')
|
i.save(out, compression="group3")
|
||||||
|
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
self.assertEqual(reread.info['compression'], 'group3')
|
self.assertEqual(reread.info["compression"], "group3")
|
||||||
self.assert_image_equal(reread, i)
|
self.assert_image_equal(reread, i)
|
||||||
|
|
||||||
def test_little_endian(self):
|
def test_little_endian(self):
|
||||||
im = Image.open('Tests/images/16bit.deflate.tif')
|
im = Image.open("Tests/images/16bit.deflate.tif")
|
||||||
self.assertEqual(im.getpixel((0, 0)), 480)
|
self.assertEqual(im.getpixel((0, 0)), 480)
|
||||||
self.assertEqual(im.mode, 'I;16')
|
self.assertEqual(im.mode, "I;16")
|
||||||
|
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
# Bytes are in image native order (little endian)
|
# Bytes are in image native order (little endian)
|
||||||
if py3:
|
if py3:
|
||||||
self.assertEqual(b[0], ord(b'\xe0'))
|
self.assertEqual(b[0], ord(b"\xe0"))
|
||||||
self.assertEqual(b[1], ord(b'\x01'))
|
self.assertEqual(b[1], ord(b"\x01"))
|
||||||
else:
|
else:
|
||||||
self.assertEqual(b[0], b'\xe0')
|
self.assertEqual(b[0], b"\xe0")
|
||||||
self.assertEqual(b[1], b'\x01')
|
self.assertEqual(b[1], b"\x01")
|
||||||
|
|
||||||
out = self.tempfile("temp.tif")
|
out = self.tempfile("temp.tif")
|
||||||
# out = "temp.le.tif"
|
# out = "temp.le.tif"
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.info['compression'], im.info['compression'])
|
self.assertEqual(reread.info["compression"], im.info["compression"])
|
||||||
self.assertEqual(reread.getpixel((0, 0)), 480)
|
self.assertEqual(reread.getpixel((0, 0)), 480)
|
||||||
# UNDONE - libtiff defaults to writing in native endian, so
|
# UNDONE - libtiff defaults to writing in native endian, so
|
||||||
# on big endian, we'll get back mode = 'I;16B' here.
|
# on big endian, we'll get back mode = 'I;16B' here.
|
||||||
|
|
||||||
def test_big_endian(self):
|
def test_big_endian(self):
|
||||||
im = Image.open('Tests/images/16bit.MM.deflate.tif')
|
im = Image.open("Tests/images/16bit.MM.deflate.tif")
|
||||||
|
|
||||||
self.assertEqual(im.getpixel((0, 0)), 480)
|
self.assertEqual(im.getpixel((0, 0)), 480)
|
||||||
self.assertEqual(im.mode, 'I;16B')
|
self.assertEqual(im.mode, "I;16B")
|
||||||
|
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
|
|
||||||
# Bytes are in image native order (big endian)
|
# Bytes are in image native order (big endian)
|
||||||
if py3:
|
if py3:
|
||||||
self.assertEqual(b[0], ord(b'\x01'))
|
self.assertEqual(b[0], ord(b"\x01"))
|
||||||
self.assertEqual(b[1], ord(b'\xe0'))
|
self.assertEqual(b[1], ord(b"\xe0"))
|
||||||
else:
|
else:
|
||||||
self.assertEqual(b[0], b'\x01')
|
self.assertEqual(b[0], b"\x01")
|
||||||
self.assertEqual(b[1], b'\xe0')
|
self.assertEqual(b[1], b"\xe0")
|
||||||
|
|
||||||
out = self.tempfile("temp.tif")
|
out = self.tempfile("temp.tif")
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
|
|
||||||
self.assertEqual(reread.info['compression'], im.info['compression'])
|
self.assertEqual(reread.info["compression"], im.info["compression"])
|
||||||
self.assertEqual(reread.getpixel((0, 0)), 480)
|
self.assertEqual(reread.getpixel((0, 0)), 480)
|
||||||
|
|
||||||
def test_g4_string_info(self):
|
def test_g4_string_info(self):
|
||||||
|
@ -352,18 +355,18 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
out = self.tempfile("temp.tif")
|
out = self.tempfile("temp.tif")
|
||||||
|
|
||||||
orig.tag[269] = 'temp.tif'
|
orig.tag[269] = "temp.tif"
|
||||||
orig.save(out)
|
orig.save(out)
|
||||||
|
|
||||||
reread = Image.open(out)
|
reread = Image.open(out)
|
||||||
self.assertEqual('temp.tif', reread.tag_v2[269])
|
self.assertEqual("temp.tif", reread.tag_v2[269])
|
||||||
self.assertEqual('temp.tif', reread.tag[269][0])
|
self.assertEqual("temp.tif", reread.tag[269][0])
|
||||||
|
|
||||||
def test_12bit_rawmode(self):
|
def test_12bit_rawmode(self):
|
||||||
""" Are we generating the same interpretation
|
""" Are we generating the same interpretation
|
||||||
of the image as Imagemagick is? """
|
of the image as Imagemagick is? """
|
||||||
TiffImagePlugin.READ_LIBTIFF = True
|
TiffImagePlugin.READ_LIBTIFF = True
|
||||||
im = Image.open('Tests/images/12bit.cropped.tif')
|
im = Image.open("Tests/images/12bit.cropped.tif")
|
||||||
im.load()
|
im.load()
|
||||||
TiffImagePlugin.READ_LIBTIFF = False
|
TiffImagePlugin.READ_LIBTIFF = False
|
||||||
# to make the target --
|
# to make the target --
|
||||||
|
@ -372,18 +375,19 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
|
# 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.
|
# so we need to unshift so that the integer values are the same.
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im, 'Tests/images/12in16bit.tif')
|
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
|
||||||
|
|
||||||
def test_blur(self):
|
def test_blur(self):
|
||||||
# test case from irc, how to do blur on b/w image
|
# test case from irc, how to do blur on b/w image
|
||||||
# and save to compressed tif.
|
# and save to compressed tif.
|
||||||
from PIL import ImageFilter
|
from PIL import ImageFilter
|
||||||
out = self.tempfile('temp.tif')
|
|
||||||
im = Image.open('Tests/images/pport_g4.tif')
|
out = self.tempfile("temp.tif")
|
||||||
im = im.convert('L')
|
im = Image.open("Tests/images/pport_g4.tif")
|
||||||
|
im = im.convert("L")
|
||||||
|
|
||||||
im = im.filter(ImageFilter.GaussianBlur(4))
|
im = im.filter(ImageFilter.GaussianBlur(4))
|
||||||
im.save(out, compression='tiff_adobe_deflate')
|
im.save(out, compression="tiff_adobe_deflate")
|
||||||
|
|
||||||
im2 = Image.open(out)
|
im2 = Image.open(out)
|
||||||
im2.load()
|
im2.load()
|
||||||
|
@ -391,23 +395,23 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
def test_compressions(self):
|
def test_compressions(self):
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
out = self.tempfile('temp.tif')
|
out = self.tempfile("temp.tif")
|
||||||
|
|
||||||
for compression in ('packbits', 'tiff_lzw'):
|
for compression in ("packbits", "tiff_lzw"):
|
||||||
im.save(out, compression=compression)
|
im.save(out, compression=compression)
|
||||||
im2 = Image.open(out)
|
im2 = Image.open(out)
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
im.save(out, compression='jpeg')
|
im.save(out, compression="jpeg")
|
||||||
im2 = Image.open(out)
|
im2 = Image.open(out)
|
||||||
self.assert_image_similar(im, im2, 30)
|
self.assert_image_similar(im, im2, 30)
|
||||||
|
|
||||||
def test_cmyk_save(self):
|
def test_cmyk_save(self):
|
||||||
im = hopper('CMYK')
|
im = hopper("CMYK")
|
||||||
out = self.tempfile('temp.tif')
|
out = self.tempfile("temp.tif")
|
||||||
|
|
||||||
im.save(out, compression='tiff_adobe_deflate')
|
im.save(out, compression="tiff_adobe_deflate")
|
||||||
im2 = Image.open(out)
|
im2 = Image.open(out)
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
|
@ -416,12 +420,12 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
to output on stderr from the error thrown by libtiff. We need to
|
to output on stderr from the error thrown by libtiff. We need to
|
||||||
capture that but not now"""
|
capture that but not now"""
|
||||||
|
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
out = self.tempfile('temp.tif')
|
out = self.tempfile("temp.tif")
|
||||||
|
|
||||||
self.assertRaises(IOError, im.save, out, compression='tiff_ccitt')
|
self.assertRaises(IOError, im.save, out, compression="tiff_ccitt")
|
||||||
self.assertRaises(IOError, im.save, out, compression='group3')
|
self.assertRaises(IOError, im.save, out, compression="group3")
|
||||||
self.assertRaises(IOError, im.save, out, compression='group4')
|
self.assertRaises(IOError, im.save, out, compression="group4")
|
||||||
|
|
||||||
def test_fp_leak(self):
|
def test_fp_leak(self):
|
||||||
im = Image.open("Tests/images/hopper_g4_500.tif")
|
im = Image.open("Tests/images/hopper_g4_500.tif")
|
||||||
|
@ -437,30 +441,30 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
def test_multipage(self):
|
def test_multipage(self):
|
||||||
# issue #862
|
# issue #862
|
||||||
TiffImagePlugin.READ_LIBTIFF = True
|
TiffImagePlugin.READ_LIBTIFF = True
|
||||||
im = Image.open('Tests/images/multipage.tiff')
|
im = Image.open("Tests/images/multipage.tiff")
|
||||||
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
|
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
|
||||||
|
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 128, 0))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
|
||||||
self.assertTrue(im.tag.next)
|
self.assertTrue(im.tag.next)
|
||||||
|
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (255, 0, 0))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
|
||||||
self.assertTrue(im.tag.next)
|
self.assertTrue(im.tag.next)
|
||||||
|
|
||||||
im.seek(2)
|
im.seek(2)
|
||||||
self.assertFalse(im.tag.next)
|
self.assertFalse(im.tag.next)
|
||||||
self.assertEqual(im.size, (20, 20))
|
self.assertEqual(im.size, (20, 20))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 0, 255))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
|
||||||
|
|
||||||
TiffImagePlugin.READ_LIBTIFF = False
|
TiffImagePlugin.READ_LIBTIFF = False
|
||||||
|
|
||||||
def test_multipage_nframes(self):
|
def test_multipage_nframes(self):
|
||||||
# issue #862
|
# issue #862
|
||||||
TiffImagePlugin.READ_LIBTIFF = True
|
TiffImagePlugin.READ_LIBTIFF = True
|
||||||
im = Image.open('Tests/images/multipage.tiff')
|
im = Image.open("Tests/images/multipage.tiff")
|
||||||
frames = im.n_frames
|
frames = im.n_frames
|
||||||
self.assertEqual(frames, 3)
|
self.assertEqual(frames, 3)
|
||||||
for _ in range(frames):
|
for _ in range(frames):
|
||||||
|
@ -472,7 +476,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
def test__next(self):
|
def test__next(self):
|
||||||
TiffImagePlugin.READ_LIBTIFF = True
|
TiffImagePlugin.READ_LIBTIFF = True
|
||||||
im = Image.open('Tests/images/hopper.tif')
|
im = Image.open("Tests/images/hopper.tif")
|
||||||
self.assertFalse(im.tag.next)
|
self.assertFalse(im.tag.next)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertFalse(im.tag.next)
|
self.assertFalse(im.tag.next)
|
||||||
|
@ -501,7 +505,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper2I.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/hopper2R.tif",
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
|
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
7.3, # epsilon
|
7.3, # epsilon
|
||||||
|
@ -510,7 +514,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper4I.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/hopper4R.tif",
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
|
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
original = hopper("L")
|
original = hopper("L")
|
||||||
|
@ -545,7 +549,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assert_image_similar(pilim, pilim_load, 0)
|
self.assert_image_similar(pilim, pilim_load, 0)
|
||||||
|
|
||||||
save_bytesio()
|
save_bytesio()
|
||||||
save_bytesio('raw')
|
save_bytesio("raw")
|
||||||
save_bytesio("packbits")
|
save_bytesio("packbits")
|
||||||
save_bytesio("tiff_lzw")
|
save_bytesio("tiff_lzw")
|
||||||
|
|
||||||
|
@ -554,12 +558,12 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
def test_crashing_metadata(self):
|
def test_crashing_metadata(self):
|
||||||
# issue 1597
|
# issue 1597
|
||||||
im = Image.open('Tests/images/rdf.tif')
|
im = Image.open("Tests/images/rdf.tif")
|
||||||
out = self.tempfile('temp.tif')
|
out = self.tempfile("temp.tif")
|
||||||
|
|
||||||
TiffImagePlugin.WRITE_LIBTIFF = True
|
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||||
# this shouldn't crash
|
# this shouldn't crash
|
||||||
im.save(out, format='TIFF')
|
im.save(out, format="TIFF")
|
||||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||||
|
|
||||||
def test_page_number_x_0(self):
|
def test_page_number_x_0(self):
|
||||||
|
@ -580,8 +584,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
# https://github.com/python-pillow/Pillow/issues/1651
|
# https://github.com/python-pillow/Pillow/issues/1651
|
||||||
|
|
||||||
tmpfile = self.tempfile("temp.tif")
|
tmpfile = self.tempfile("temp.tif")
|
||||||
with open(tmpfile, 'wb') as f:
|
with open(tmpfile, "wb") as f:
|
||||||
with open("Tests/images/g4-multi.tiff", 'rb') as src:
|
with open("Tests/images/g4-multi.tiff", "rb") as src:
|
||||||
f.write(src.read())
|
f.write(src.read())
|
||||||
|
|
||||||
im = Image.open(tmpfile)
|
im = Image.open(tmpfile)
|
||||||
|
@ -592,29 +596,29 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
def test_read_icc(self):
|
def test_read_icc(self):
|
||||||
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||||
icc = img.info.get('icc_profile')
|
icc = img.info.get("icc_profile")
|
||||||
self.assertIsNotNone(icc)
|
self.assertIsNotNone(icc)
|
||||||
TiffImagePlugin.READ_LIBTIFF = True
|
TiffImagePlugin.READ_LIBTIFF = True
|
||||||
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||||
icc_libtiff = img.info.get('icc_profile')
|
icc_libtiff = img.info.get("icc_profile")
|
||||||
self.assertIsNotNone(icc_libtiff)
|
self.assertIsNotNone(icc_libtiff)
|
||||||
TiffImagePlugin.READ_LIBTIFF = False
|
TiffImagePlugin.READ_LIBTIFF = False
|
||||||
self.assertEqual(icc, icc_libtiff)
|
self.assertEqual(icc, icc_libtiff)
|
||||||
|
|
||||||
def test_multipage_compression(self):
|
def test_multipage_compression(self):
|
||||||
im = Image.open('Tests/images/compression.tif')
|
im = Image.open("Tests/images/compression.tif")
|
||||||
|
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
self.assertEqual(im._compression, 'tiff_ccitt')
|
self.assertEqual(im._compression, "tiff_ccitt")
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
|
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
self.assertEqual(im._compression, 'packbits')
|
self.assertEqual(im._compression, "packbits")
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
self.assertEqual(im._compression, 'tiff_ccitt')
|
self.assertEqual(im._compression, "tiff_ccitt")
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
@ -638,13 +642,18 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assertEqual(im.size, (100, 40))
|
self.assertEqual(im.size, (100, 40))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.tile,
|
im.tile,
|
||||||
[('tiff_adobe_deflate', (0, 0, 100, 40), 0,
|
[
|
||||||
('RGB;16N', 'tiff_adobe_deflate', False))]
|
(
|
||||||
|
"tiff_adobe_deflate",
|
||||||
|
(0, 0, 100, 40),
|
||||||
|
0,
|
||||||
|
("RGB;16N", "tiff_adobe_deflate", False),
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_image_equal_tofile(
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
|
||||||
im, "Tests/images/tiff_16bit_RGB_target.png")
|
|
||||||
|
|
||||||
def test_16bit_RGBa_tiff(self):
|
def test_16bit_RGBa_tiff(self):
|
||||||
im = Image.open("Tests/images/tiff_16bit_RGBa.tiff")
|
im = Image.open("Tests/images/tiff_16bit_RGBa.tiff")
|
||||||
|
@ -652,13 +661,11 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assertEqual(im.mode, "RGBA")
|
self.assertEqual(im.mode, "RGBA")
|
||||||
self.assertEqual(im.size, (100, 40))
|
self.assertEqual(im.size, (100, 40))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.tile,
|
im.tile, [("tiff_lzw", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False))]
|
||||||
[('tiff_lzw', (0, 0, 100, 40), 0, ('RGBa;16N', 'tiff_lzw', False))]
|
|
||||||
)
|
)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_image_equal_tofile(
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
|
||||||
im, "Tests/images/tiff_16bit_RGBa_target.png")
|
|
||||||
|
|
||||||
def test_gimp_tiff(self):
|
def test_gimp_tiff(self):
|
||||||
# Read TIFF JPEG images from GIMP [@PIL168]
|
# Read TIFF JPEG images from GIMP [@PIL168]
|
||||||
|
@ -673,7 +680,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assertEqual(im.mode, "RGB")
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (256, 256))
|
self.assertEqual(im.size, (256, 256))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.tile, [('jpeg', (0, 0, 256, 256), 0, ('RGB', 'jpeg', False))]
|
im.tile, [("jpeg", (0, 0, 256, 256), 0, ("RGB", "jpeg", False))]
|
||||||
)
|
)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
@ -682,15 +689,14 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
def test_sampleformat(self):
|
def test_sampleformat(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/1466
|
# https://github.com/python-pillow/Pillow/issues/1466
|
||||||
im = Image.open("Tests/images/copyleft.tiff")
|
im = Image.open("Tests/images/copyleft.tiff")
|
||||||
self.assertEqual(im.mode, 'RGB')
|
self.assertEqual(im.mode, "RGB")
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im, "Tests/images/copyleft.png",
|
self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")
|
||||||
mode='RGB')
|
|
||||||
|
|
||||||
def test_lzw(self):
|
def test_lzw(self):
|
||||||
im = Image.open("Tests/images/hopper_lzw.tif")
|
im = Image.open("Tests/images/hopper_lzw.tif")
|
||||||
|
|
||||||
self.assertEqual(im.mode, 'RGB')
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "TIFF")
|
self.assertEqual(im.format, "TIFF")
|
||||||
im2 = hopper()
|
im2 = hopper()
|
||||||
|
@ -742,5 +748,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
infile = "Tests/images/old-style-jpeg-compression.tif"
|
infile = "Tests/images/old-style-jpeg-compression.tif"
|
||||||
im = Image.open(infile)
|
im = Image.open(infile)
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(
|
||||||
"Tests/images/old-style-jpeg-compression.png")
|
im, "Tests/images/old-style-jpeg-compression.png"
|
||||||
|
)
|
||||||
|
|
|
@ -17,7 +17,7 @@ class TestFileLibTiffSmall(LibTiffTestCase):
|
||||||
"""Testing the open file load path"""
|
"""Testing the open file load path"""
|
||||||
|
|
||||||
test_file = "Tests/images/hopper_g4.tif"
|
test_file = "Tests/images/hopper_g4.tif"
|
||||||
with open(test_file, 'rb') as f:
|
with open(test_file, "rb") as f:
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
|
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
|
@ -26,9 +26,10 @@ class TestFileLibTiffSmall(LibTiffTestCase):
|
||||||
def test_g4_hopper_bytesio(self):
|
def test_g4_hopper_bytesio(self):
|
||||||
"""Testing the bytesio loading code path"""
|
"""Testing the bytesio loading code path"""
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
test_file = "Tests/images/hopper_g4.tif"
|
test_file = "Tests/images/hopper_g4.tif"
|
||||||
s = BytesIO()
|
s = BytesIO()
|
||||||
with open(test_file, 'rb') as f:
|
with open(test_file, "rb") as f:
|
||||||
s.write(f.read())
|
s.write(f.read())
|
||||||
s.seek(0)
|
s.seek(0)
|
||||||
im = Image.open(s)
|
im = Image.open(s)
|
||||||
|
|
|
@ -4,12 +4,10 @@ from PIL import Image, McIdasImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFileMcIdas(PillowTestCase):
|
class TestFileMcIdas(PillowTestCase):
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, McIdasImagePlugin.McIdasImageFile, invalid_file)
|
||||||
McIdasImagePlugin.McIdasImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_valid_file(self):
|
def test_valid_file(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -13,9 +13,8 @@ TEST_FILE = "Tests/images/hopper.mic"
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(olefile_installed, "olefile package not installed")
|
@unittest.skipUnless(olefile_installed, "olefile package not installed")
|
||||||
@unittest.skipUnless(features.check('libtiff'), "libtiff not installed")
|
@unittest.skipUnless(features.check("libtiff"), "libtiff not installed")
|
||||||
class TestFileMic(PillowTestCase):
|
class TestFileMic(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -24,8 +23,8 @@ class TestFileMic(PillowTestCase):
|
||||||
self.assertEqual(im.format, "MIC")
|
self.assertEqual(im.format, "MIC")
|
||||||
|
|
||||||
# Adjust for the gamma of 2.2 encoded into the file
|
# Adjust for the gamma of 2.2 encoded into the file
|
||||||
lut = ImagePalette.make_gamma_lut(1/2.2)
|
lut = ImagePalette.make_gamma_lut(1 / 2.2)
|
||||||
im = Image.merge('RGBA', [chan.point(lut) for chan in im.split()])
|
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
|
||||||
|
|
||||||
im2 = hopper("RGBA")
|
im2 = hopper("RGBA")
|
||||||
self.assert_image_similar(im, im2, 10)
|
self.assert_image_similar(im, im2, 10)
|
||||||
|
@ -57,10 +56,8 @@ class TestFileMic(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
# Test an invalid OLE file
|
# Test an invalid OLE file
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, invalid_file)
|
||||||
MicImagePlugin.MicImageFile, invalid_file)
|
|
||||||
|
|
||||||
# Test a valid OLE file, but not a MIC file
|
# Test a valid OLE file, but not a MIC file
|
||||||
ole_file = "Tests/images/test-ole-file.doc"
|
ole_file = "Tests/images/test-ole-file.doc"
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, ole_file)
|
||||||
MicImagePlugin.MicImageFile, ole_file)
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
|
||||||
|
|
||||||
|
|
||||||
class TestFileMpo(PillowTestCase):
|
class TestFileMpo(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
|
@ -35,23 +34,25 @@ class TestFileMpo(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(test_files[0])
|
im = Image.open(test_files[0])
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_app(self):
|
def test_app(self):
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
# Test APP/COM reader (@PIL135)
|
# Test APP/COM reader (@PIL135)
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
self.assertEqual(im.applist[0][0], 'APP1')
|
self.assertEqual(im.applist[0][0], "APP1")
|
||||||
self.assertEqual(im.applist[1][0], 'APP2')
|
self.assertEqual(im.applist[1][0], "APP2")
|
||||||
self.assertEqual(im.applist[1][1][:16],
|
self.assertEqual(
|
||||||
b'MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00')
|
im.applist[1][1][:16], b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
|
||||||
|
)
|
||||||
self.assertEqual(len(im.applist), 2)
|
self.assertEqual(len(im.applist), 2)
|
||||||
|
|
||||||
def test_exif(self):
|
def test_exif(self):
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
info = im._getexif()
|
info = im._getexif()
|
||||||
self.assertEqual(info[272], 'Nintendo 3DS')
|
self.assertEqual(info[272], "Nintendo 3DS")
|
||||||
self.assertEqual(info[296], 2)
|
self.assertEqual(info[296], 2)
|
||||||
self.assertEqual(info[34665], 188)
|
self.assertEqual(info[34665], 188)
|
||||||
|
|
||||||
|
@ -68,19 +69,19 @@ class TestFileMpo(PillowTestCase):
|
||||||
# Nintendo
|
# Nintendo
|
||||||
im = Image.open("Tests/images/sugarshack.mpo")
|
im = Image.open("Tests/images/sugarshack.mpo")
|
||||||
exif = im.getexif()
|
exif = im.getexif()
|
||||||
self.assertEqual(exif.get_ifd(0x927c)[0x1101]["Parallax"], -44.798187255859375)
|
self.assertEqual(exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375)
|
||||||
|
|
||||||
# Fujifilm
|
# Fujifilm
|
||||||
im = Image.open("Tests/images/fujifilm.mpo")
|
im = Image.open("Tests/images/fujifilm.mpo")
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
exif = im.getexif()
|
exif = im.getexif()
|
||||||
self.assertEqual(exif.get_ifd(0x927c)[0xb211], -3.125)
|
self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125)
|
||||||
|
|
||||||
def test_mp(self):
|
def test_mp(self):
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
mpinfo = im._getmp()
|
mpinfo = im._getmp()
|
||||||
self.assertEqual(mpinfo[45056], b'0100')
|
self.assertEqual(mpinfo[45056], b"0100")
|
||||||
self.assertEqual(mpinfo[45057], 2)
|
self.assertEqual(mpinfo[45057], 2)
|
||||||
|
|
||||||
def test_mp_offset(self):
|
def test_mp_offset(self):
|
||||||
|
@ -88,7 +89,7 @@ class TestFileMpo(PillowTestCase):
|
||||||
# in APP2 data, in contrast to normal 8
|
# in APP2 data, in contrast to normal 8
|
||||||
im = Image.open("Tests/images/sugarshack_ifd_offset.mpo")
|
im = Image.open("Tests/images/sugarshack_ifd_offset.mpo")
|
||||||
mpinfo = im._getmp()
|
mpinfo = im._getmp()
|
||||||
self.assertEqual(mpinfo[45056], b'0100')
|
self.assertEqual(mpinfo[45056], b"0100")
|
||||||
self.assertEqual(mpinfo[45057], 2)
|
self.assertEqual(mpinfo[45057], 2)
|
||||||
|
|
||||||
def test_mp_attribute(self):
|
def test_mp_attribute(self):
|
||||||
|
@ -97,17 +98,16 @@ class TestFileMpo(PillowTestCase):
|
||||||
mpinfo = im._getmp()
|
mpinfo = im._getmp()
|
||||||
frameNumber = 0
|
frameNumber = 0
|
||||||
for mpentry in mpinfo[45058]:
|
for mpentry in mpinfo[45058]:
|
||||||
mpattr = mpentry['Attribute']
|
mpattr = mpentry["Attribute"]
|
||||||
if frameNumber:
|
if frameNumber:
|
||||||
self.assertFalse(mpattr['RepresentativeImageFlag'])
|
self.assertFalse(mpattr["RepresentativeImageFlag"])
|
||||||
else:
|
else:
|
||||||
self.assertTrue(mpattr['RepresentativeImageFlag'])
|
self.assertTrue(mpattr["RepresentativeImageFlag"])
|
||||||
self.assertFalse(mpattr['DependentParentImageFlag'])
|
self.assertFalse(mpattr["DependentParentImageFlag"])
|
||||||
self.assertFalse(mpattr['DependentChildImageFlag'])
|
self.assertFalse(mpattr["DependentChildImageFlag"])
|
||||||
self.assertEqual(mpattr['ImageDataFormat'], 'JPEG')
|
self.assertEqual(mpattr["ImageDataFormat"], "JPEG")
|
||||||
self.assertEqual(mpattr['MPType'],
|
self.assertEqual(mpattr["MPType"], "Multi-Frame Image: (Disparity)")
|
||||||
'Multi-Frame Image: (Disparity)')
|
self.assertEqual(mpattr["Reserved"], 0)
|
||||||
self.assertEqual(mpattr['Reserved'], 0)
|
|
||||||
frameNumber += 1
|
frameNumber += 1
|
||||||
|
|
||||||
def test_seek(self):
|
def test_seek(self):
|
||||||
|
@ -144,7 +144,7 @@ class TestFileMpo(PillowTestCase):
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_image_grab(self):
|
def test_image_grab(self):
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
|
|
|
@ -10,7 +10,6 @@ YA_EXTRA_DIR = "Tests/images/msp"
|
||||||
|
|
||||||
|
|
||||||
class TestFileMsp(PillowTestCase):
|
class TestFileMsp(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
test_file = self.tempfile("temp.msp")
|
test_file = self.tempfile("temp.msp")
|
||||||
|
|
||||||
|
@ -25,8 +24,7 @@ class TestFileMsp(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, MspImagePlugin.MspImageFile, invalid_file)
|
||||||
MspImagePlugin.MspImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_bad_checksum(self):
|
def test_bad_checksum(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -34,8 +32,7 @@ class TestFileMsp(PillowTestCase):
|
||||||
bad_checksum = "Tests/images/hopper_bad_checksum.msp"
|
bad_checksum = "Tests/images/hopper_bad_checksum.msp"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, MspImagePlugin.MspImageFile, bad_checksum)
|
||||||
MspImagePlugin.MspImageFile, bad_checksum)
|
|
||||||
|
|
||||||
def test_open_windows_v1(self):
|
def test_open_windows_v1(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -51,25 +48,26 @@ class TestFileMsp(PillowTestCase):
|
||||||
target = Image.open(target_path)
|
target = Image.open(target_path)
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
|
|
||||||
@unittest.skipIf(not os.path.exists(EXTRA_DIR),
|
@unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed")
|
||||||
"Extra image files not installed")
|
|
||||||
def test_open_windows_v2(self):
|
def test_open_windows_v2(self):
|
||||||
|
|
||||||
files = (os.path.join(EXTRA_DIR, f) for f in os.listdir(EXTRA_DIR)
|
files = (
|
||||||
if os.path.splitext(f)[1] == '.msp')
|
os.path.join(EXTRA_DIR, f)
|
||||||
|
for f in os.listdir(EXTRA_DIR)
|
||||||
|
if os.path.splitext(f)[1] == ".msp"
|
||||||
|
)
|
||||||
for path in files:
|
for path in files:
|
||||||
self._assert_file_image_equal(path,
|
self._assert_file_image_equal(path, path.replace(".msp", ".png"))
|
||||||
path.replace('.msp', '.png'))
|
|
||||||
|
|
||||||
@unittest.skipIf(not os.path.exists(YA_EXTRA_DIR),
|
@unittest.skipIf(
|
||||||
"Even More Extra image files not installed")
|
not os.path.exists(YA_EXTRA_DIR), "Even More Extra image files not installed"
|
||||||
|
)
|
||||||
def test_msp_v2(self):
|
def test_msp_v2(self):
|
||||||
for f in os.listdir(YA_EXTRA_DIR):
|
for f in os.listdir(YA_EXTRA_DIR):
|
||||||
if '.MSP' not in f:
|
if ".MSP" not in f:
|
||||||
continue
|
continue
|
||||||
path = os.path.join(YA_EXTRA_DIR, f)
|
path = os.path.join(YA_EXTRA_DIR, f)
|
||||||
self._assert_file_image_equal(path,
|
self._assert_file_image_equal(path, path.replace(".MSP", ".png"))
|
||||||
path.replace('.MSP', '.png'))
|
|
||||||
|
|
||||||
def test_cannot_save_wrong_mode(self):
|
def test_cannot_save_wrong_mode(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -3,9 +3,8 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestFilePcd(PillowTestCase):
|
class TestFilePcd(PillowTestCase):
|
||||||
|
|
||||||
def test_load_raw(self):
|
def test_load_raw(self):
|
||||||
im = Image.open('Tests/images/hopper.pcd')
|
im = Image.open("Tests/images/hopper.pcd")
|
||||||
im.load() # should not segfault.
|
im.load() # should not segfault.
|
||||||
|
|
||||||
# Note that this image was created with a resized hopper
|
# Note that this image was created with a resized hopper
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image, ImageFile, PcxImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFilePcx(PillowTestCase):
|
class TestFilePcx(PillowTestCase):
|
||||||
|
|
||||||
def _roundtrip(self, im):
|
def _roundtrip(self, im):
|
||||||
f = self.tempfile("temp.pcx")
|
f = self.tempfile("temp.pcx")
|
||||||
im.save(f)
|
im.save(f)
|
||||||
|
@ -17,7 +16,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
self.assert_image_equal(im2, im)
|
self.assert_image_equal(im2, im)
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
for mode in ('1', 'L', 'P', 'RGB'):
|
for mode in ("1", "L", "P", "RGB"):
|
||||||
self._roundtrip(hopper(mode))
|
self._roundtrip(hopper(mode))
|
||||||
|
|
||||||
# Test an unsupported mode
|
# Test an unsupported mode
|
||||||
|
@ -28,14 +27,13 @@ class TestFilePcx(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, PcxImagePlugin.PcxImageFile, invalid_file)
|
||||||
PcxImagePlugin.PcxImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_odd(self):
|
def test_odd(self):
|
||||||
# see issue #523, odd sized images should have a stride that's even.
|
# see issue #523, odd sized images should have a stride that's even.
|
||||||
# not that imagemagick or gimp write pcx that way.
|
# not that imagemagick or gimp write pcx that way.
|
||||||
# we were not handling properly.
|
# we were not handling properly.
|
||||||
for mode in ('1', 'L', 'P', 'RGB'):
|
for mode in ("1", "L", "P", "RGB"):
|
||||||
# larger, odd sized images are better here to ensure that
|
# larger, odd sized images are better here to ensure that
|
||||||
# we handle interrupted scan lines properly.
|
# we handle interrupted scan lines properly.
|
||||||
self._roundtrip(hopper(mode).resize((511, 511)))
|
self._roundtrip(hopper(mode).resize((511, 511)))
|
||||||
|
@ -50,17 +48,17 @@ class TestFilePcx(PillowTestCase):
|
||||||
self.assertEqual(im.tile[0][1], (0, 0, 447, 144))
|
self.assertEqual(im.tile[0][1], (0, 0, 447, 144))
|
||||||
|
|
||||||
# Make sure all pixels are either 0 or 255.
|
# Make sure all pixels are either 0 or 255.
|
||||||
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447*144)
|
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447 * 144)
|
||||||
|
|
||||||
def test_1px_width(self):
|
def test_1px_width(self):
|
||||||
im = Image.new('L', (1, 256))
|
im = Image.new("L", (1, 256))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(256):
|
for y in range(256):
|
||||||
px[0, y] = y
|
px[0, y] = y
|
||||||
self._roundtrip(im)
|
self._roundtrip(im)
|
||||||
|
|
||||||
def test_large_count(self):
|
def test_large_count(self):
|
||||||
im = Image.new('L', (256, 1))
|
im = Image.new("L", (256, 1))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for x in range(256):
|
for x in range(256):
|
||||||
px[x, 0] = x // 67 * 67
|
px[x, 0] = x // 67 * 67
|
||||||
|
@ -75,7 +73,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
ImageFile.MAXBLOCK = _last
|
ImageFile.MAXBLOCK = _last
|
||||||
|
|
||||||
def test_break_in_count_overflow(self):
|
def test_break_in_count_overflow(self):
|
||||||
im = Image.new('L', (256, 5))
|
im = Image.new("L", (256, 5))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(4):
|
for y in range(4):
|
||||||
for x in range(256):
|
for x in range(256):
|
||||||
|
@ -83,7 +81,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
self._test_buffer_overflow(im)
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
def test_break_one_in_loop(self):
|
def test_break_one_in_loop(self):
|
||||||
im = Image.new('L', (256, 5))
|
im = Image.new("L", (256, 5))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(5):
|
for y in range(5):
|
||||||
for x in range(256):
|
for x in range(256):
|
||||||
|
@ -91,7 +89,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
self._test_buffer_overflow(im)
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
def test_break_many_in_loop(self):
|
def test_break_many_in_loop(self):
|
||||||
im = Image.new('L', (256, 5))
|
im = Image.new("L", (256, 5))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(4):
|
for y in range(4):
|
||||||
for x in range(256):
|
for x in range(256):
|
||||||
|
@ -101,7 +99,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
self._test_buffer_overflow(im)
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
def test_break_one_at_end(self):
|
def test_break_one_at_end(self):
|
||||||
im = Image.new('L', (256, 5))
|
im = Image.new("L", (256, 5))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(5):
|
for y in range(5):
|
||||||
for x in range(256):
|
for x in range(256):
|
||||||
|
@ -110,7 +108,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
self._test_buffer_overflow(im)
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
def test_break_many_at_end(self):
|
def test_break_many_at_end(self):
|
||||||
im = Image.new('L', (256, 5))
|
im = Image.new("L", (256, 5))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(5):
|
for y in range(5):
|
||||||
for x in range(256):
|
for x in range(256):
|
||||||
|
@ -121,7 +119,7 @@ class TestFilePcx(PillowTestCase):
|
||||||
self._test_buffer_overflow(im)
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
def test_break_padding(self):
|
def test_break_padding(self):
|
||||||
im = Image.new('L', (257, 5))
|
im = Image.new("L", (257, 5))
|
||||||
px = im.load()
|
px = im.load()
|
||||||
for y in range(5):
|
for y in range(5):
|
||||||
for x in range(257):
|
for x in range(257):
|
||||||
|
|
|
@ -8,7 +8,6 @@ import time
|
||||||
|
|
||||||
|
|
||||||
class TestFilePdf(PillowTestCase):
|
class TestFilePdf(PillowTestCase):
|
||||||
|
|
||||||
def helper_save_as_pdf(self, mode, **kwargs):
|
def helper_save_as_pdf(self, mode, **kwargs):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
|
@ -21,15 +20,16 @@ class TestFilePdf(PillowTestCase):
|
||||||
self.assertTrue(os.path.isfile(outfile))
|
self.assertTrue(os.path.isfile(outfile))
|
||||||
self.assertGreater(os.path.getsize(outfile), 0)
|
self.assertGreater(os.path.getsize(outfile), 0)
|
||||||
with PdfParser.PdfParser(outfile) as pdf:
|
with PdfParser.PdfParser(outfile) as pdf:
|
||||||
if kwargs.get("append_images", False) or \
|
if kwargs.get("append_images", False) or kwargs.get("append", False):
|
||||||
kwargs.get("append", False):
|
|
||||||
self.assertGreater(len(pdf.pages), 1)
|
self.assertGreater(len(pdf.pages), 1)
|
||||||
else:
|
else:
|
||||||
self.assertGreater(len(pdf.pages), 0)
|
self.assertGreater(len(pdf.pages), 0)
|
||||||
with open(outfile, 'rb') as fp:
|
with open(outfile, "rb") as fp:
|
||||||
contents = fp.read()
|
contents = fp.read()
|
||||||
size = tuple(int(d) for d in
|
size = tuple(
|
||||||
contents.split(b'/MediaBox [ 0 0 ')[1].split(b']')[0].split())
|
int(d)
|
||||||
|
for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
|
||||||
|
)
|
||||||
self.assertEqual(im.size, size)
|
self.assertEqual(im.size, size)
|
||||||
|
|
||||||
return outfile
|
return outfile
|
||||||
|
@ -82,7 +82,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
# Multiframe image
|
# Multiframe image
|
||||||
im = Image.open("Tests/images/dispose_bgnd.gif")
|
im = Image.open("Tests/images/dispose_bgnd.gif")
|
||||||
|
|
||||||
outfile = self.tempfile('temp.pdf')
|
outfile = self.tempfile("temp.pdf")
|
||||||
im.save(outfile, save_all=True)
|
im.save(outfile, save_all=True)
|
||||||
|
|
||||||
self.assertTrue(os.path.isfile(outfile))
|
self.assertTrue(os.path.isfile(outfile))
|
||||||
|
@ -99,6 +99,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
for im in ims:
|
||||||
yield im
|
yield im
|
||||||
|
|
||||||
im.save(outfile, save_all=True, append_images=imGenerator(ims))
|
im.save(outfile, save_all=True, append_images=imGenerator(ims))
|
||||||
|
|
||||||
self.assertTrue(os.path.isfile(outfile))
|
self.assertTrue(os.path.isfile(outfile))
|
||||||
|
@ -115,7 +116,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
# Test saving a multiframe image without save_all
|
# Test saving a multiframe image without save_all
|
||||||
im = Image.open("Tests/images/dispose_bgnd.gif")
|
im = Image.open("Tests/images/dispose_bgnd.gif")
|
||||||
|
|
||||||
outfile = self.tempfile('temp.pdf')
|
outfile = self.tempfile("temp.pdf")
|
||||||
im.save(outfile)
|
im.save(outfile)
|
||||||
|
|
||||||
self.assertTrue(os.path.isfile(outfile))
|
self.assertTrue(os.path.isfile(outfile))
|
||||||
|
@ -124,8 +125,8 @@ class TestFilePdf(PillowTestCase):
|
||||||
def test_pdf_open(self):
|
def test_pdf_open(self):
|
||||||
# fail on a buffer full of null bytes
|
# fail on a buffer full of null bytes
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
PdfParser.PdfFormatError,
|
PdfParser.PdfFormatError, PdfParser.PdfParser, buf=bytearray(65536)
|
||||||
PdfParser.PdfParser, buf=bytearray(65536))
|
)
|
||||||
|
|
||||||
# make an empty PDF object
|
# make an empty PDF object
|
||||||
with PdfParser.PdfParser() as empty_pdf:
|
with PdfParser.PdfParser() as empty_pdf:
|
||||||
|
@ -162,10 +163,9 @@ class TestFilePdf(PillowTestCase):
|
||||||
im = hopper("RGB")
|
im = hopper("RGB")
|
||||||
temp_dir = tempfile.mkdtemp()
|
temp_dir = tempfile.mkdtemp()
|
||||||
try:
|
try:
|
||||||
self.assertRaises(IOError,
|
self.assertRaises(
|
||||||
im.save,
|
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
|
||||||
os.path.join(temp_dir, "nonexistent.pdf"),
|
)
|
||||||
append=True)
|
|
||||||
finally:
|
finally:
|
||||||
os.rmdir(temp_dir)
|
os.rmdir(temp_dir)
|
||||||
|
|
||||||
|
@ -194,9 +194,9 @@ class TestFilePdf(PillowTestCase):
|
||||||
with PdfParser.PdfParser(pdf_filename, mode="r+b") as pdf:
|
with PdfParser.PdfParser(pdf_filename, mode="r+b") as pdf:
|
||||||
self.assertEqual(len(pdf.pages), 1)
|
self.assertEqual(len(pdf.pages), 1)
|
||||||
self.assertEqual(len(pdf.info), 4)
|
self.assertEqual(len(pdf.info), 4)
|
||||||
self.assertEqual(pdf.info.Title, os.path.splitext(
|
self.assertEqual(
|
||||||
os.path.basename(pdf_filename)
|
pdf.info.Title, os.path.splitext(os.path.basename(pdf_filename))[0]
|
||||||
)[0])
|
)
|
||||||
self.assertEqual(pdf.info.Producer, "PdfParser")
|
self.assertEqual(pdf.info.Producer, "PdfParser")
|
||||||
self.assertIn(b"CreationDate", pdf.info)
|
self.assertIn(b"CreationDate", pdf.info)
|
||||||
self.assertIn(b"ModDate", pdf.info)
|
self.assertIn(b"ModDate", pdf.info)
|
||||||
|
@ -223,8 +223,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
# append two images
|
# append two images
|
||||||
mode_CMYK = hopper("CMYK")
|
mode_CMYK = hopper("CMYK")
|
||||||
mode_P = hopper("P")
|
mode_P = hopper("P")
|
||||||
mode_CMYK.save(pdf_filename,
|
mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P])
|
||||||
append=True, save_all=True, append_images=[mode_P])
|
|
||||||
|
|
||||||
# open the PDF again, check pages and info again
|
# open the PDF again, check pages and info again
|
||||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||||
|
@ -242,10 +241,16 @@ class TestFilePdf(PillowTestCase):
|
||||||
def test_pdf_info(self):
|
def test_pdf_info(self):
|
||||||
# make a PDF file
|
# make a PDF file
|
||||||
pdf_filename = self.helper_save_as_pdf(
|
pdf_filename = self.helper_save_as_pdf(
|
||||||
"RGB", title="title", author="author", subject="subject",
|
"RGB",
|
||||||
keywords="keywords", creator="creator", producer="producer",
|
title="title",
|
||||||
|
author="author",
|
||||||
|
subject="subject",
|
||||||
|
keywords="keywords",
|
||||||
|
creator="creator",
|
||||||
|
producer="producer",
|
||||||
creationDate=time.strptime("2000", "%Y"),
|
creationDate=time.strptime("2000", "%Y"),
|
||||||
modDate=time.strptime("2001", "%Y"))
|
modDate=time.strptime("2001", "%Y"),
|
||||||
|
)
|
||||||
|
|
||||||
# open it, check pages and info
|
# open it, check pages and info
|
||||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||||
|
@ -256,8 +261,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
self.assertEqual(pdf.info.Keywords, "keywords")
|
self.assertEqual(pdf.info.Keywords, "keywords")
|
||||||
self.assertEqual(pdf.info.Creator, "creator")
|
self.assertEqual(pdf.info.Creator, "creator")
|
||||||
self.assertEqual(pdf.info.Producer, "producer")
|
self.assertEqual(pdf.info.Producer, "producer")
|
||||||
self.assertEqual(pdf.info.CreationDate,
|
self.assertEqual(pdf.info.CreationDate, time.strptime("2000", "%Y"))
|
||||||
time.strptime("2000", "%Y"))
|
|
||||||
self.assertEqual(pdf.info.ModDate, time.strptime("2001", "%Y"))
|
self.assertEqual(pdf.info.ModDate, time.strptime("2001", "%Y"))
|
||||||
self.check_pdf_pages_consistency(pdf)
|
self.check_pdf_pages_consistency(pdf)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hopper.pxr"
|
||||||
|
|
||||||
|
|
||||||
class TestFilePixar(PillowTestCase):
|
class TestFilePixar(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -21,6 +20,4 @@ class TestFilePixar(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(SyntaxError, PixarImagePlugin.PixarImageFile, invalid_file)
|
||||||
SyntaxError,
|
|
||||||
PixarImagePlugin.PixarImageFile, invalid_file)
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
@ -32,7 +33,7 @@ def chunk(cid, *data):
|
||||||
|
|
||||||
o32 = PngImagePlugin.o32
|
o32 = PngImagePlugin.o32
|
||||||
|
|
||||||
IHDR = chunk(b"IHDR", o32(1), o32(1), b'\x08\x02', b'\0\0\0')
|
IHDR = chunk(b"IHDR", o32(1), o32(1), b"\x08\x02", b"\0\0\0")
|
||||||
IDAT = chunk(b"IDAT")
|
IDAT = chunk(b"IDAT")
|
||||||
IEND = chunk(b"IEND")
|
IEND = chunk(b"IEND")
|
||||||
|
|
||||||
|
@ -52,7 +53,6 @@ def roundtrip(im, **options):
|
||||||
|
|
||||||
|
|
||||||
class TestFilePng(PillowTestCase):
|
class TestFilePng(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
|
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
|
||||||
self.skipTest("zip/deflate support not available")
|
self.skipTest("zip/deflate support not available")
|
||||||
|
@ -86,7 +86,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertEqual(im.mode, "RGB")
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "PNG")
|
self.assertEqual(im.format, "PNG")
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/png')
|
self.assertEqual(im.get_format_mimetype(), "image/png")
|
||||||
|
|
||||||
for mode in ["1", "L", "P", "RGB", "I", "I;16"]:
|
for mode in ["1", "L", "P", "RGB", "I", "I;16"]:
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
|
@ -99,8 +99,7 @@ class TestFilePng(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, invalid_file)
|
||||||
PngImagePlugin.PngImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_broken(self):
|
def test_broken(self):
|
||||||
# Check reading of totally broken files. In this case, the test
|
# Check reading of totally broken files. In this case, the test
|
||||||
|
@ -112,76 +111,83 @@ class TestFilePng(PillowTestCase):
|
||||||
def test_bad_text(self):
|
def test_bad_text(self):
|
||||||
# Make sure PIL can read malformed tEXt chunks (@PIL152)
|
# Make sure PIL can read malformed tEXt chunks (@PIL152)
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'tEXt') + TAIL)
|
im = load(HEAD + chunk(b"tEXt") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL)
|
im = load(HEAD + chunk(b"tEXt", b"spam") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL)
|
im = load(HEAD + chunk(b"tEXt", b"spam\0") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL)
|
im = load(HEAD + chunk(b"tEXt", b"spam\0egg") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': 'egg'})
|
self.assertEqual(im.info, {"spam": "egg"})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL)
|
im = load(HEAD + chunk(b"tEXt", b"spam\0egg\0") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': 'egg\x00'})
|
self.assertEqual(im.info, {"spam": "egg\x00"})
|
||||||
|
|
||||||
def test_bad_ztxt(self):
|
def test_bad_ztxt(self):
|
||||||
# Test reading malformed zTXt chunks (python-pillow/Pillow#318)
|
# Test reading malformed zTXt chunks (python-pillow/Pillow#318)
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'zTXt') + TAIL)
|
im = load(HEAD + chunk(b"zTXt") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'zTXt', b'spam') + TAIL)
|
im = load(HEAD + chunk(b"zTXt", b"spam") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'zTXt', b'spam\0') + TAIL)
|
im = load(HEAD + chunk(b"zTXt", b"spam\0") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'zTXt', b'spam\0\0') + TAIL)
|
im = load(HEAD + chunk(b"zTXt", b"spam\0\0") + TAIL)
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
|
|
||||||
im = load(HEAD + chunk(
|
im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")[:1]) + TAIL)
|
||||||
b'zTXt', b'spam\0\0' + zlib.compress(b'egg')[:1]) + TAIL)
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
|
||||||
|
|
||||||
im = load(
|
im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")) + TAIL)
|
||||||
HEAD + chunk(b'zTXt', b'spam\0\0' + zlib.compress(b'egg')) + TAIL)
|
self.assertEqual(im.info, {"spam": "egg"})
|
||||||
self.assertEqual(im.info, {'spam': 'egg'})
|
|
||||||
|
|
||||||
def test_bad_itxt(self):
|
def test_bad_itxt(self):
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt') + TAIL)
|
im = load(HEAD + chunk(b"iTXt") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam') + TAIL)
|
im = load(HEAD + chunk(b"iTXt", b"spam") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0') + TAIL)
|
im = load(HEAD + chunk(b"iTXt", b"spam\0") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0\x02') + TAIL)
|
im = load(HEAD + chunk(b"iTXt", b"spam\0\x02") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0\0\0foo\0') + TAIL)
|
im = load(HEAD + chunk(b"iTXt", b"spam\0\0\0foo\0") + TAIL)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0\0\0en\0Spam\0egg') + TAIL)
|
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": "egg"})
|
||||||
self.assertEqual(im.info["spam"].lang, "en")
|
self.assertEqual(im.info["spam"].lang, "en")
|
||||||
self.assertEqual(im.info["spam"].tkey, "Spam")
|
self.assertEqual(im.info["spam"].tkey, "Spam")
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\0en\0Spam\0' +
|
im = load(
|
||||||
zlib.compress(b"egg")[:1]) + TAIL)
|
HEAD
|
||||||
self.assertEqual(im.info, {'spam': ''})
|
+ chunk(b"iTXt", b"spam\0\1\0en\0Spam\0" + zlib.compress(b"egg")[:1])
|
||||||
|
+ TAIL
|
||||||
|
)
|
||||||
|
self.assertEqual(im.info, {"spam": ""})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\1en\0Spam\0' +
|
im = load(
|
||||||
zlib.compress(b"egg")) + TAIL)
|
HEAD
|
||||||
|
+ chunk(b"iTXt", b"spam\0\1\1en\0Spam\0" + zlib.compress(b"egg"))
|
||||||
|
+ TAIL
|
||||||
|
)
|
||||||
self.assertEqual(im.info, {})
|
self.assertEqual(im.info, {})
|
||||||
|
|
||||||
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\0en\0Spam\0' +
|
im = load(
|
||||||
zlib.compress(b"egg")) + TAIL)
|
HEAD
|
||||||
|
+ chunk(b"iTXt", b"spam\0\1\0en\0Spam\0" + zlib.compress(b"egg"))
|
||||||
|
+ TAIL
|
||||||
|
)
|
||||||
self.assertEqual(im.info, {"spam": "egg"})
|
self.assertEqual(im.info, {"spam": "egg"})
|
||||||
self.assertEqual(im.info["spam"].lang, "en")
|
self.assertEqual(im.info["spam"].lang, "en")
|
||||||
self.assertEqual(im.info["spam"].tkey, "Spam")
|
self.assertEqual(im.info["spam"].tkey, "Spam")
|
||||||
|
@ -213,7 +219,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (162, 150))
|
self.assert_image(im, "RGBA", (162, 150))
|
||||||
|
|
||||||
# image has 124 unique alpha values
|
# image has 124 unique alpha values
|
||||||
self.assertEqual(len(im.getchannel('A').getcolors()), 124)
|
self.assertEqual(len(im.getchannel("A").getcolors()), 124)
|
||||||
|
|
||||||
def test_load_transparent_rgb(self):
|
def test_load_transparent_rgb(self):
|
||||||
test_file = "Tests/images/rgb_trns.png"
|
test_file = "Tests/images/rgb_trns.png"
|
||||||
|
@ -225,7 +231,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (64, 64))
|
self.assert_image(im, "RGBA", (64, 64))
|
||||||
|
|
||||||
# image has 876 transparent pixels
|
# image has 876 transparent pixels
|
||||||
self.assertEqual(im.getchannel('A').getcolors()[0][0], 876)
|
self.assertEqual(im.getchannel("A").getcolors()[0][0], 876)
|
||||||
|
|
||||||
def test_save_p_transparent_palette(self):
|
def test_save_p_transparent_palette(self):
|
||||||
in_file = "Tests/images/pil123p.png"
|
in_file = "Tests/images/pil123p.png"
|
||||||
|
@ -247,7 +253,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (162, 150))
|
self.assert_image(im, "RGBA", (162, 150))
|
||||||
|
|
||||||
# image has 124 unique alpha values
|
# image has 124 unique alpha values
|
||||||
self.assertEqual(len(im.getchannel('A').getcolors()), 124)
|
self.assertEqual(len(im.getchannel("A").getcolors()), 124)
|
||||||
|
|
||||||
def test_save_p_single_transparency(self):
|
def test_save_p_single_transparency(self):
|
||||||
in_file = "Tests/images/p_trns_single.png"
|
in_file = "Tests/images/p_trns_single.png"
|
||||||
|
@ -271,7 +277,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertEqual(im.getpixel((31, 31)), (0, 255, 52, 0))
|
self.assertEqual(im.getpixel((31, 31)), (0, 255, 52, 0))
|
||||||
|
|
||||||
# image has 876 transparent pixels
|
# image has 876 transparent pixels
|
||||||
self.assertEqual(im.getchannel('A').getcolors()[0][0], 876)
|
self.assertEqual(im.getchannel("A").getcolors()[0][0], 876)
|
||||||
|
|
||||||
def test_save_p_transparent_black(self):
|
def test_save_p_transparent_black(self):
|
||||||
# check if solid black image with full transparency
|
# check if solid black image with full transparency
|
||||||
|
@ -292,19 +298,14 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
|
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
|
||||||
|
|
||||||
def test_save_greyscale_transparency(self):
|
def test_save_greyscale_transparency(self):
|
||||||
for mode, num_transparent in {
|
for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
|
||||||
"1": 1994,
|
in_file = "Tests/images/" + mode.lower() + "_trns.png"
|
||||||
"L": 559,
|
|
||||||
"I": 559,
|
|
||||||
}.items():
|
|
||||||
in_file = "Tests/images/"+mode.lower()+"_trns.png"
|
|
||||||
im = Image.open(in_file)
|
im = Image.open(in_file)
|
||||||
self.assertEqual(im.mode, mode)
|
self.assertEqual(im.mode, mode)
|
||||||
self.assertEqual(im.info["transparency"], 255)
|
self.assertEqual(im.info["transparency"], 255)
|
||||||
|
|
||||||
im_rgba = im.convert('RGBA')
|
im_rgba = im.convert("RGBA")
|
||||||
self.assertEqual(
|
self.assertEqual(im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
|
||||||
im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
|
|
||||||
|
|
||||||
test_file = self.tempfile("temp.png")
|
test_file = self.tempfile("temp.png")
|
||||||
im.save(test_file)
|
im.save(test_file)
|
||||||
|
@ -314,9 +315,10 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertEqual(test_im.info["transparency"], 255)
|
self.assertEqual(test_im.info["transparency"], 255)
|
||||||
self.assert_image_equal(im, test_im)
|
self.assert_image_equal(im, test_im)
|
||||||
|
|
||||||
test_im_rgba = test_im.convert('RGBA')
|
test_im_rgba = test_im.convert("RGBA")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
test_im_rgba.getchannel('A').getcolors()[0][0], num_transparent)
|
test_im_rgba.getchannel("A").getcolors()[0][0], num_transparent
|
||||||
|
)
|
||||||
|
|
||||||
def test_save_rgb_single_transparency(self):
|
def test_save_rgb_single_transparency(self):
|
||||||
in_file = "Tests/images/caption_6_33_22.png"
|
in_file = "Tests/images/caption_6_33_22.png"
|
||||||
|
@ -345,7 +347,7 @@ class TestFilePng(PillowTestCase):
|
||||||
# -14: malformed chunk
|
# -14: malformed chunk
|
||||||
|
|
||||||
for offset in (-10, -13, -14):
|
for offset in (-10, -13, -14):
|
||||||
with open(TEST_PNG_FILE, 'rb') as f:
|
with open(TEST_PNG_FILE, "rb") as f:
|
||||||
test_file = f.read()[:offset]
|
test_file = f.read()[:offset]
|
||||||
|
|
||||||
im = Image.open(BytesIO(test_file))
|
im = Image.open(BytesIO(test_file))
|
||||||
|
@ -355,12 +357,11 @@ class TestFilePng(PillowTestCase):
|
||||||
def test_verify_ignores_crc_error(self):
|
def test_verify_ignores_crc_error(self):
|
||||||
# check ignores crc errors in ancillary chunks
|
# check ignores crc errors in ancillary chunks
|
||||||
|
|
||||||
chunk_data = chunk(b'tEXt', b'spam')
|
chunk_data = chunk(b"tEXt", b"spam")
|
||||||
broken_crc_chunk_data = chunk_data[:-1] + b'q' # break CRC
|
broken_crc_chunk_data = chunk_data[:-1] + b"q" # break CRC
|
||||||
|
|
||||||
image_data = HEAD + broken_crc_chunk_data + TAIL
|
image_data = HEAD + broken_crc_chunk_data + TAIL
|
||||||
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
|
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data))
|
||||||
BytesIO(image_data))
|
|
||||||
|
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
try:
|
try:
|
||||||
|
@ -372,12 +373,13 @@ class TestFilePng(PillowTestCase):
|
||||||
def test_verify_not_ignores_crc_error_in_required_chunk(self):
|
def test_verify_not_ignores_crc_error_in_required_chunk(self):
|
||||||
# check does not ignore crc errors in required chunks
|
# check does not ignore crc errors in required chunks
|
||||||
|
|
||||||
image_data = MAGIC + IHDR[:-1] + b'q' + TAIL
|
image_data = MAGIC + IHDR[:-1] + b"q" + TAIL
|
||||||
|
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
try:
|
try:
|
||||||
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
|
self.assertRaises(
|
||||||
BytesIO(image_data))
|
SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data)
|
||||||
|
)
|
||||||
finally:
|
finally:
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||||
|
|
||||||
|
@ -417,8 +419,8 @@ class TestFilePng(PillowTestCase):
|
||||||
info.add_text("ZIP", "VALUE", zip=True)
|
info.add_text("ZIP", "VALUE", zip=True)
|
||||||
|
|
||||||
im = roundtrip(im, pnginfo=info)
|
im = roundtrip(im, pnginfo=info)
|
||||||
self.assertEqual(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
|
self.assertEqual(im.info, {"TXT": "VALUE", "ZIP": "VALUE"})
|
||||||
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
|
self.assertEqual(im.text, {"TXT": "VALUE", "ZIP": "VALUE"})
|
||||||
|
|
||||||
def test_roundtrip_itxt(self):
|
def test_roundtrip_itxt(self):
|
||||||
# Check iTXt roundtripping
|
# Check iTXt roundtripping
|
||||||
|
@ -426,8 +428,7 @@ class TestFilePng(PillowTestCase):
|
||||||
im = Image.new("RGB", (32, 32))
|
im = Image.new("RGB", (32, 32))
|
||||||
info = PngImagePlugin.PngInfo()
|
info = PngImagePlugin.PngInfo()
|
||||||
info.add_itxt("spam", "Eggs", "en", "Spam")
|
info.add_itxt("spam", "Eggs", "en", "Spam")
|
||||||
info.add_text("eggs", PngImagePlugin.iTXt("Spam", "en", "Eggs"),
|
info.add_text("eggs", PngImagePlugin.iTXt("Spam", "en", "Eggs"), zip=True)
|
||||||
zip=True)
|
|
||||||
|
|
||||||
im = roundtrip(im, pnginfo=info)
|
im = roundtrip(im, pnginfo=info)
|
||||||
self.assertEqual(im.info, {"spam": "Eggs", "eggs": "Spam"})
|
self.assertEqual(im.info, {"spam": "Eggs", "eggs": "Spam"})
|
||||||
|
@ -459,11 +460,11 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertEqual(im.info, {"Text": value})
|
self.assertEqual(im.info, {"Text": value})
|
||||||
|
|
||||||
if py3:
|
if py3:
|
||||||
rt_text(" Aa" + chr(0xa0) + chr(0xc4) + chr(0xff)) # Latin1
|
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
|
||||||
rt_text(chr(0x400) + chr(0x472) + chr(0x4ff)) # Cyrillic
|
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
|
||||||
rt_text(chr(0x4e00) + chr(0x66f0) + # CJK
|
# CJK:
|
||||||
chr(0x9fba) + chr(0x3042) + chr(0xac00))
|
rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
|
||||||
rt_text("A" + chr(0xc4) + chr(0x472) + chr(0x3042)) # Combined
|
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
|
||||||
|
|
||||||
def test_scary(self):
|
def test_scary(self):
|
||||||
# Check reading of evil PNG file. For information, see:
|
# Check reading of evil PNG file. For information, see:
|
||||||
|
@ -471,8 +472,8 @@ class TestFilePng(PillowTestCase):
|
||||||
# The first byte is removed from pngtest_bad.png
|
# The first byte is removed from pngtest_bad.png
|
||||||
# to avoid classification as malware.
|
# to avoid classification as malware.
|
||||||
|
|
||||||
with open("Tests/images/pngtest_bad.png.bin", 'rb') as fd:
|
with open("Tests/images/pngtest_bad.png.bin", "rb") as fd:
|
||||||
data = b'\x89' + fd.read()
|
data = b"\x89" + fd.read()
|
||||||
|
|
||||||
pngfile = BytesIO(data)
|
pngfile = BytesIO(data)
|
||||||
self.assertRaises(IOError, Image.open, pngfile)
|
self.assertRaises(IOError, Image.open, pngfile)
|
||||||
|
@ -494,17 +495,16 @@ class TestFilePng(PillowTestCase):
|
||||||
|
|
||||||
def test_trns_p(self):
|
def test_trns_p(self):
|
||||||
# Check writing a transparency of 0, issue #528
|
# Check writing a transparency of 0, issue #528
|
||||||
im = hopper('P')
|
im = hopper("P")
|
||||||
im.info['transparency'] = 0
|
im.info["transparency"] = 0
|
||||||
|
|
||||||
f = self.tempfile("temp.png")
|
f = self.tempfile("temp.png")
|
||||||
im.save(f)
|
im.save(f)
|
||||||
|
|
||||||
im2 = Image.open(f)
|
im2 = Image.open(f)
|
||||||
self.assertIn('transparency', im2.info)
|
self.assertIn("transparency", im2.info)
|
||||||
|
|
||||||
self.assert_image_equal(im2.convert('RGBA'),
|
self.assert_image_equal(im2.convert("RGBA"), im.convert("RGBA"))
|
||||||
im.convert('RGBA'))
|
|
||||||
|
|
||||||
def test_trns_null(self):
|
def test_trns_null(self):
|
||||||
# Check reading images with null tRNS value, issue #1239
|
# Check reading images with null tRNS value, issue #1239
|
||||||
|
@ -515,39 +515,39 @@ class TestFilePng(PillowTestCase):
|
||||||
|
|
||||||
def test_save_icc_profile(self):
|
def test_save_icc_profile(self):
|
||||||
im = Image.open("Tests/images/icc_profile_none.png")
|
im = Image.open("Tests/images/icc_profile_none.png")
|
||||||
self.assertIsNone(im.info['icc_profile'])
|
self.assertIsNone(im.info["icc_profile"])
|
||||||
|
|
||||||
with_icc = Image.open("Tests/images/icc_profile.png")
|
with_icc = Image.open("Tests/images/icc_profile.png")
|
||||||
expected_icc = with_icc.info['icc_profile']
|
expected_icc = with_icc.info["icc_profile"]
|
||||||
|
|
||||||
im = roundtrip(im, icc_profile=expected_icc)
|
im = roundtrip(im, icc_profile=expected_icc)
|
||||||
self.assertEqual(im.info['icc_profile'], expected_icc)
|
self.assertEqual(im.info["icc_profile"], expected_icc)
|
||||||
|
|
||||||
def test_discard_icc_profile(self):
|
def test_discard_icc_profile(self):
|
||||||
im = Image.open('Tests/images/icc_profile.png')
|
im = Image.open("Tests/images/icc_profile.png")
|
||||||
|
|
||||||
im = roundtrip(im, icc_profile=None)
|
im = roundtrip(im, icc_profile=None)
|
||||||
self.assertNotIn('icc_profile', im.info)
|
self.assertNotIn("icc_profile", im.info)
|
||||||
|
|
||||||
def test_roundtrip_icc_profile(self):
|
def test_roundtrip_icc_profile(self):
|
||||||
im = Image.open('Tests/images/icc_profile.png')
|
im = Image.open("Tests/images/icc_profile.png")
|
||||||
expected_icc = im.info['icc_profile']
|
expected_icc = im.info["icc_profile"]
|
||||||
|
|
||||||
im = roundtrip(im)
|
im = roundtrip(im)
|
||||||
self.assertEqual(im.info['icc_profile'], expected_icc)
|
self.assertEqual(im.info["icc_profile"], expected_icc)
|
||||||
|
|
||||||
def test_roundtrip_no_icc_profile(self):
|
def test_roundtrip_no_icc_profile(self):
|
||||||
im = Image.open("Tests/images/icc_profile_none.png")
|
im = Image.open("Tests/images/icc_profile_none.png")
|
||||||
self.assertIsNone(im.info['icc_profile'])
|
self.assertIsNone(im.info["icc_profile"])
|
||||||
|
|
||||||
im = roundtrip(im)
|
im = roundtrip(im)
|
||||||
self.assertNotIn('icc_profile', im.info)
|
self.assertNotIn("icc_profile", im.info)
|
||||||
|
|
||||||
def test_repr_png(self):
|
def test_repr_png(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
||||||
repr_png = Image.open(BytesIO(im._repr_png_()))
|
repr_png = Image.open(BytesIO(im._repr_png_()))
|
||||||
self.assertEqual(repr_png.format, 'PNG')
|
self.assertEqual(repr_png.format, "PNG")
|
||||||
self.assert_image_equal(im, repr_png)
|
self.assert_image_equal(im, repr_png)
|
||||||
|
|
||||||
def test_chunk_order(self):
|
def test_chunk_order(self):
|
||||||
|
@ -579,10 +579,10 @@ class TestFilePng(PillowTestCase):
|
||||||
|
|
||||||
def test_textual_chunks_after_idat(self):
|
def test_textual_chunks_after_idat(self):
|
||||||
im = Image.open("Tests/images/hopper.png")
|
im = Image.open("Tests/images/hopper.png")
|
||||||
self.assertIn('comment', im.text.keys())
|
self.assertIn("comment", im.text.keys())
|
||||||
for k, v in {
|
for k, v in {
|
||||||
'date:create': '2014-09-04T09:37:08+03:00',
|
"date:create": "2014-09-04T09:37:08+03:00",
|
||||||
'date:modify': '2014-09-04T09:37:08+03:00',
|
"date:modify": "2014-09-04T09:37:08+03:00",
|
||||||
}.items():
|
}.items():
|
||||||
self.assertEqual(im.text[k], v)
|
self.assertEqual(im.text[k], v)
|
||||||
|
|
||||||
|
@ -601,7 +601,7 @@ class TestFilePng(PillowTestCase):
|
||||||
|
|
||||||
# Raises an EOFError in load_end
|
# Raises an EOFError in load_end
|
||||||
im = Image.open("Tests/images/hopper_idat_after_image_end.png")
|
im = Image.open("Tests/images/hopper_idat_after_image_end.png")
|
||||||
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
|
self.assertEqual(im.text, {"TXT": "VALUE", "ZIP": "VALUE"})
|
||||||
|
|
||||||
def test_exif(self):
|
def test_exif(self):
|
||||||
im = Image.open("Tests/images/exif.png")
|
im = Image.open("Tests/images/exif.png")
|
||||||
|
@ -637,20 +637,21 @@ class TestFilePng(PillowTestCase):
|
||||||
reloaded = Image.open(test_file)
|
reloaded = Image.open(test_file)
|
||||||
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
|
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_WEBP and _webp.HAVE_WEBPANIM,
|
@unittest.skipUnless(
|
||||||
"WebP support not installed with animation")
|
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP support not installed with animation"
|
||||||
|
)
|
||||||
def test_apng(self):
|
def test_apng(self):
|
||||||
im = Image.open("Tests/images/iss634.apng")
|
im = Image.open("Tests/images/iss634.apng")
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/apng')
|
self.assertEqual(im.get_format_mimetype(), "image/apng")
|
||||||
|
|
||||||
# This also tests reading unknown PNG chunks (fcTL and fdAT) in load_end
|
# This also tests reading unknown PNG chunks (fcTL and fdAT) in load_end
|
||||||
expected = Image.open("Tests/images/iss634.webp")
|
expected = Image.open("Tests/images/iss634.webp")
|
||||||
self.assert_image_similar(im, expected, 0.23)
|
self.assert_image_similar(im, expected, 0.23)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
class TestTruncatedPngPLeaks(PillowLeakTestCase):
|
class TestTruncatedPngPLeaks(PillowLeakTestCase):
|
||||||
mem_limit = 2*1024 # max increase in K
|
mem_limit = 2 * 1024 # max increase in K
|
||||||
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs
|
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -658,7 +659,7 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase):
|
||||||
self.skipTest("zip/deflate support not available")
|
self.skipTest("zip/deflate support not available")
|
||||||
|
|
||||||
def test_leak_load(self):
|
def test_leak_load(self):
|
||||||
with open('Tests/images/hopper.png', 'rb') as f:
|
with open("Tests/images/hopper.png", "rb") as f:
|
||||||
DATA = BytesIO(f.read(16 * 1024))
|
DATA = BytesIO(f.read(16 * 1024))
|
||||||
|
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
|
|
@ -7,7 +7,6 @@ test_file = "Tests/images/hopper.ppm"
|
||||||
|
|
||||||
|
|
||||||
class TestFilePpm(PillowTestCase):
|
class TestFilePpm(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -17,39 +16,39 @@ class TestFilePpm(PillowTestCase):
|
||||||
self.assertEqual(im.get_format_mimetype(), "image/x-portable-pixmap")
|
self.assertEqual(im.get_format_mimetype(), "image/x-portable-pixmap")
|
||||||
|
|
||||||
def test_16bit_pgm(self):
|
def test_16bit_pgm(self):
|
||||||
im = Image.open('Tests/images/16_bit_binary.pgm')
|
im = Image.open("Tests/images/16_bit_binary.pgm")
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, 'I')
|
self.assertEqual(im.mode, "I")
|
||||||
self.assertEqual(im.size, (20, 100))
|
self.assertEqual(im.size, (20, 100))
|
||||||
self.assertEqual(im.get_format_mimetype(), "image/x-portable-graymap")
|
self.assertEqual(im.get_format_mimetype(), "image/x-portable-graymap")
|
||||||
|
|
||||||
tgt = Image.open('Tests/images/16_bit_binary_pgm.png')
|
tgt = Image.open("Tests/images/16_bit_binary_pgm.png")
|
||||||
self.assert_image_equal(im, tgt)
|
self.assert_image_equal(im, tgt)
|
||||||
|
|
||||||
def test_16bit_pgm_write(self):
|
def test_16bit_pgm_write(self):
|
||||||
im = Image.open('Tests/images/16_bit_binary.pgm')
|
im = Image.open("Tests/images/16_bit_binary.pgm")
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
f = self.tempfile('temp.pgm')
|
f = self.tempfile("temp.pgm")
|
||||||
im.save(f, 'PPM')
|
im.save(f, "PPM")
|
||||||
|
|
||||||
reloaded = Image.open(f)
|
reloaded = Image.open(f)
|
||||||
self.assert_image_equal(im, reloaded)
|
self.assert_image_equal(im, reloaded)
|
||||||
|
|
||||||
def test_pnm(self):
|
def test_pnm(self):
|
||||||
im = Image.open('Tests/images/hopper.pnm')
|
im = Image.open("Tests/images/hopper.pnm")
|
||||||
self.assert_image_similar(im, hopper(), 0.0001)
|
self.assert_image_similar(im, hopper(), 0.0001)
|
||||||
|
|
||||||
f = self.tempfile('temp.pnm')
|
f = self.tempfile("temp.pnm")
|
||||||
im.save(f)
|
im.save(f)
|
||||||
|
|
||||||
reloaded = Image.open(f)
|
reloaded = Image.open(f)
|
||||||
self.assert_image_equal(im, reloaded)
|
self.assert_image_equal(im, reloaded)
|
||||||
|
|
||||||
def test_truncated_file(self):
|
def test_truncated_file(self):
|
||||||
path = self.tempfile('temp.pgm')
|
path = self.tempfile("temp.pgm")
|
||||||
with open(path, 'w') as f:
|
with open(path, "w") as f:
|
||||||
f.write('P6')
|
f.write("P6")
|
||||||
|
|
||||||
self.assertRaises(ValueError, Image.open, path)
|
self.assertRaises(ValueError, Image.open, path)
|
||||||
|
|
||||||
|
@ -60,17 +59,17 @@ class TestFilePpm(PillowTestCase):
|
||||||
# sizes.
|
# sizes.
|
||||||
|
|
||||||
with self.assertRaises(IOError):
|
with self.assertRaises(IOError):
|
||||||
Image.open('Tests/images/negative_size.ppm')
|
Image.open("Tests/images/negative_size.ppm")
|
||||||
|
|
||||||
def test_mimetypes(self):
|
def test_mimetypes(self):
|
||||||
path = self.tempfile('temp.pgm')
|
path = self.tempfile("temp.pgm")
|
||||||
|
|
||||||
with open(path, 'w') as f:
|
with open(path, "w") as f:
|
||||||
f.write("P4\n128 128\n255")
|
f.write("P4\n128 128\n255")
|
||||||
im = Image.open(path)
|
im = Image.open(path)
|
||||||
self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap")
|
self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap")
|
||||||
|
|
||||||
with open(path, 'w') as f:
|
with open(path, "w") as f:
|
||||||
f.write("PyCMYK\n128 128\n255")
|
f.write("PyCMYK\n128 128\n255")
|
||||||
im = Image.open(path)
|
im = Image.open(path)
|
||||||
self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap")
|
self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap")
|
||||||
|
|
|
@ -6,7 +6,6 @@ test_file = "Tests/images/hopper.psd"
|
||||||
|
|
||||||
|
|
||||||
class TestImagePsd(PillowTestCase):
|
class TestImagePsd(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -21,13 +20,13 @@ class TestImagePsd(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file)
|
||||||
PsdImagePlugin.PsdImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open("Tests/images/hopper_merged.psd")
|
im = Image.open("Tests/images/hopper_merged.psd")
|
||||||
|
@ -41,14 +40,14 @@ class TestImagePsd(PillowTestCase):
|
||||||
def test_eoferror(self):
|
def test_eoferror(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
# PSD seek index starts at 1 rather than 0
|
# PSD seek index starts at 1 rather than 0
|
||||||
n_frames = im.n_frames+1
|
n_frames = im.n_frames + 1
|
||||||
|
|
||||||
# Test seeking past the last frame
|
# Test seeking past the last frame
|
||||||
self.assertRaises(EOFError, im.seek, n_frames)
|
self.assertRaises(EOFError, im.seek, n_frames)
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_seek_tell(self):
|
def test_seek_tell(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
|
@ -74,7 +73,7 @@ class TestImagePsd(PillowTestCase):
|
||||||
def test_open_after_exclusive_load(self):
|
def test_open_after_exclusive_load(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
im.load()
|
im.load()
|
||||||
im.seek(im.tell()+1)
|
im.seek(im.tell() + 1)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
def test_icc_profile(self):
|
def test_icc_profile(self):
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image, SgiImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFileSgi(PillowTestCase):
|
class TestFileSgi(PillowTestCase):
|
||||||
|
|
||||||
def test_rgb(self):
|
def test_rgb(self):
|
||||||
# Created with ImageMagick then renamed:
|
# Created with ImageMagick then renamed:
|
||||||
# convert hopper.ppm -compress None sgi:hopper.rgb
|
# convert hopper.ppm -compress None sgi:hopper.rgb
|
||||||
|
@ -12,7 +11,7 @@ class TestFileSgi(PillowTestCase):
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
self.assert_image_equal(im, hopper())
|
self.assert_image_equal(im, hopper())
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/rgb')
|
self.assertEqual(im.get_format_mimetype(), "image/rgb")
|
||||||
|
|
||||||
def test_rgb16(self):
|
def test_rgb16(self):
|
||||||
test_file = "Tests/images/hopper16.rgb"
|
test_file = "Tests/images/hopper16.rgb"
|
||||||
|
@ -26,8 +25,8 @@ class TestFileSgi(PillowTestCase):
|
||||||
test_file = "Tests/images/hopper.bw"
|
test_file = "Tests/images/hopper.bw"
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
self.assert_image_similar(im, hopper('L'), 2)
|
self.assert_image_similar(im, hopper("L"), 2)
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/sgi')
|
self.assertEqual(im.get_format_mimetype(), "image/sgi")
|
||||||
|
|
||||||
def test_rgba(self):
|
def test_rgba(self):
|
||||||
# Created with ImageMagick:
|
# Created with ImageMagick:
|
||||||
|
@ -35,9 +34,9 @@ class TestFileSgi(PillowTestCase):
|
||||||
test_file = "Tests/images/transparent.sgi"
|
test_file = "Tests/images/transparent.sgi"
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
target = Image.open('Tests/images/transparent.png')
|
target = Image.open("Tests/images/transparent.png")
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
self.assertEqual(im.get_format_mimetype(), 'image/sgi')
|
self.assertEqual(im.get_format_mimetype(), "image/sgi")
|
||||||
|
|
||||||
def test_rle(self):
|
def test_rle(self):
|
||||||
# Created with ImageMagick:
|
# Created with ImageMagick:
|
||||||
|
@ -45,47 +44,46 @@ class TestFileSgi(PillowTestCase):
|
||||||
test_file = "Tests/images/hopper.sgi"
|
test_file = "Tests/images/hopper.sgi"
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
target = Image.open('Tests/images/hopper.rgb')
|
target = Image.open("Tests/images/hopper.rgb")
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
|
|
||||||
def test_rle16(self):
|
def test_rle16(self):
|
||||||
test_file = "Tests/images/tv16.sgi"
|
test_file = "Tests/images/tv16.sgi"
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
target = Image.open('Tests/images/tv.rgb')
|
target = Image.open("Tests/images/tv.rgb")
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, SgiImagePlugin.SgiImageFile, invalid_file)
|
||||||
SgiImagePlugin.SgiImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self):
|
||||||
def roundtrip(img):
|
def roundtrip(img):
|
||||||
out = self.tempfile('temp.sgi')
|
out = self.tempfile("temp.sgi")
|
||||||
img.save(out, format='sgi')
|
img.save(out, format="sgi")
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assert_image_equal(img, reloaded)
|
self.assert_image_equal(img, reloaded)
|
||||||
|
|
||||||
for mode in ('L', 'RGB', 'RGBA'):
|
for mode in ("L", "RGB", "RGBA"):
|
||||||
roundtrip(hopper(mode))
|
roundtrip(hopper(mode))
|
||||||
|
|
||||||
# Test 1 dimension for an L mode image
|
# Test 1 dimension for an L mode image
|
||||||
roundtrip(Image.new('L', (10, 1)))
|
roundtrip(Image.new("L", (10, 1)))
|
||||||
|
|
||||||
def test_write16(self):
|
def test_write16(self):
|
||||||
test_file = "Tests/images/hopper16.rgb"
|
test_file = "Tests/images/hopper16.rgb"
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
out = self.tempfile('temp.sgi')
|
out = self.tempfile("temp.sgi")
|
||||||
im.save(out, format='sgi', bpc=2)
|
im.save(out, format="sgi", bpc=2)
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assert_image_equal(im, reloaded)
|
self.assert_image_equal(im, reloaded)
|
||||||
|
|
||||||
def test_unsupported_mode(self):
|
def test_unsupported_mode(self):
|
||||||
im = hopper('LA')
|
im = hopper("LA")
|
||||||
out = self.tempfile('temp.sgi')
|
out = self.tempfile("temp.sgi")
|
||||||
|
|
||||||
self.assertRaises(ValueError, im.save, out, format='sgi')
|
self.assertRaises(ValueError, im.save, out, format="sgi")
|
||||||
|
|
|
@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/hopper.spider"
|
||||||
|
|
||||||
|
|
||||||
class TestImageSpider(PillowTestCase):
|
class TestImageSpider(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -22,11 +21,12 @@ class TestImageSpider(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
temp = self.tempfile('temp.spider')
|
temp = self.tempfile("temp.spider")
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
|
|
@ -4,11 +4,10 @@ from PIL import Image, SunImagePlugin
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
EXTRA_DIR = 'Tests/images/sunraster'
|
EXTRA_DIR = "Tests/images/sunraster"
|
||||||
|
|
||||||
|
|
||||||
class TestFileSun(PillowTestCase):
|
class TestFileSun(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
# Created with ImageMagick: convert hopper.jpg hopper.ras
|
# Created with ImageMagick: convert hopper.jpg hopper.ras
|
||||||
|
@ -23,20 +22,20 @@ class TestFileSun(PillowTestCase):
|
||||||
self.assert_image_similar(im, hopper(), 5) # visually verified
|
self.assert_image_similar(im, hopper(), 5) # visually verified
|
||||||
|
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, SunImagePlugin.SunImageFile, invalid_file)
|
||||||
SunImagePlugin.SunImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_im1(self):
|
def test_im1(self):
|
||||||
im = Image.open('Tests/images/sunraster.im1')
|
im = Image.open("Tests/images/sunraster.im1")
|
||||||
target = Image.open('Tests/images/sunraster.im1.png')
|
target = Image.open("Tests/images/sunraster.im1.png")
|
||||||
self.assert_image_equal(im, target)
|
self.assert_image_equal(im, target)
|
||||||
|
|
||||||
@unittest.skipIf(not os.path.exists(EXTRA_DIR),
|
@unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed")
|
||||||
"Extra image files not installed")
|
|
||||||
def test_others(self):
|
def test_others(self):
|
||||||
files = (os.path.join(EXTRA_DIR, f) for f in
|
files = (
|
||||||
os.listdir(EXTRA_DIR) if os.path.splitext(f)[1]
|
os.path.join(EXTRA_DIR, f)
|
||||||
in ('.sun', '.SUN', '.ras'))
|
for f in os.listdir(EXTRA_DIR)
|
||||||
|
if os.path.splitext(f)[1] in (".sun", ".SUN", ".ras")
|
||||||
|
)
|
||||||
for path in files:
|
for path in files:
|
||||||
with Image.open(path) as im:
|
with Image.open(path) as im:
|
||||||
im.load()
|
im.load()
|
||||||
|
|
|
@ -9,15 +9,14 @@ TEST_TAR_FILE = "Tests/images/hopper.tar"
|
||||||
|
|
||||||
|
|
||||||
class TestFileTar(PillowTestCase):
|
class TestFileTar(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs:
|
if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs:
|
||||||
self.skipTest("neither jpeg nor zip support available")
|
self.skipTest("neither jpeg nor zip support available")
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
for codec, test_path, format in [
|
for codec, test_path, format in [
|
||||||
['zip_decoder', 'hopper.png', 'PNG'],
|
["zip_decoder", "hopper.png", "PNG"],
|
||||||
['jpeg_decoder', 'hopper.jpg', 'JPEG']
|
["jpeg_decoder", "hopper.jpg", "JPEG"],
|
||||||
]:
|
]:
|
||||||
if codec in codecs:
|
if codec in codecs:
|
||||||
tar = TarIO.TarIO(TEST_TAR_FILE, test_path)
|
tar = TarIO.TarIO(TEST_TAR_FILE, test_path)
|
||||||
|
@ -28,9 +27,9 @@ class TestFileTar(PillowTestCase):
|
||||||
self.assertEqual(im.format, format)
|
self.assertEqual(im.format, format)
|
||||||
|
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
tar = TarIO.TarIO(TEST_TAR_FILE, 'hopper.jpg')
|
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
|
||||||
tar.close()
|
tar.close()
|
||||||
|
|
||||||
def test_contextmanager(self):
|
def test_contextmanager(self):
|
||||||
with TarIO.TarIO(TEST_TAR_FILE, 'hopper.jpg'):
|
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -16,16 +16,13 @@ class TestFileTga(PillowTestCase):
|
||||||
_MODES = ("L", "LA", "P", "RGB", "RGBA")
|
_MODES = ("L", "LA", "P", "RGB", "RGBA")
|
||||||
_ORIGINS = ("tl", "bl")
|
_ORIGINS = ("tl", "bl")
|
||||||
|
|
||||||
_ORIGIN_TO_ORIENTATION = {
|
_ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
|
||||||
"tl": 1,
|
|
||||||
"bl": -1
|
|
||||||
}
|
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
for mode in self._MODES:
|
for mode in self._MODES:
|
||||||
png_paths = glob(
|
png_paths = glob(
|
||||||
os.path.join(
|
os.path.join(_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower()))
|
||||||
_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower())))
|
)
|
||||||
|
|
||||||
for png_path in png_paths:
|
for png_path in png_paths:
|
||||||
reference_im = Image.open(png_path)
|
reference_im = Image.open(png_path)
|
||||||
|
@ -34,21 +31,22 @@ class TestFileTga(PillowTestCase):
|
||||||
path_no_ext = os.path.splitext(png_path)[0]
|
path_no_ext = os.path.splitext(png_path)[0]
|
||||||
for origin, rle in product(self._ORIGINS, (True, False)):
|
for origin, rle in product(self._ORIGINS, (True, False)):
|
||||||
tga_path = "{}_{}_{}.tga".format(
|
tga_path = "{}_{}_{}.tga".format(
|
||||||
path_no_ext, origin, "rle" if rle else "raw")
|
path_no_ext, origin, "rle" if rle else "raw"
|
||||||
|
)
|
||||||
|
|
||||||
original_im = Image.open(tga_path)
|
original_im = Image.open(tga_path)
|
||||||
self.assertEqual(original_im.format, "TGA")
|
self.assertEqual(original_im.format, "TGA")
|
||||||
self.assertEqual(original_im.get_format_mimetype(), "image/x-tga")
|
self.assertEqual(original_im.get_format_mimetype(), "image/x-tga")
|
||||||
if rle:
|
if rle:
|
||||||
self.assertEqual(
|
self.assertEqual(original_im.info["compression"], "tga_rle")
|
||||||
original_im.info["compression"], "tga_rle")
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
original_im.info["orientation"],
|
original_im.info["orientation"],
|
||||||
self._ORIGIN_TO_ORIENTATION[origin])
|
self._ORIGIN_TO_ORIENTATION[origin],
|
||||||
|
)
|
||||||
if mode == "P":
|
if mode == "P":
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
original_im.getpalette(),
|
original_im.getpalette(), reference_im.getpalette()
|
||||||
reference_im.getpalette())
|
)
|
||||||
|
|
||||||
self.assert_image_equal(original_im, reference_im)
|
self.assert_image_equal(original_im, reference_im)
|
||||||
|
|
||||||
|
@ -62,14 +60,15 @@ class TestFileTga(PillowTestCase):
|
||||||
if rle:
|
if rle:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
saved_im.info["compression"],
|
saved_im.info["compression"],
|
||||||
original_im.info["compression"])
|
original_im.info["compression"],
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
saved_im.info["orientation"],
|
saved_im.info["orientation"], original_im.info["orientation"]
|
||||||
original_im.info["orientation"])
|
)
|
||||||
if mode == "P":
|
if mode == "P":
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
saved_im.getpalette(),
|
saved_im.getpalette(), original_im.getpalette()
|
||||||
original_im.getpalette())
|
)
|
||||||
|
|
||||||
self.assert_image_equal(saved_im, original_im)
|
self.assert_image_equal(saved_im, original_im)
|
||||||
|
|
||||||
|
@ -128,8 +127,7 @@ class TestFileTga(PillowTestCase):
|
||||||
|
|
||||||
# Save with custom id section greater than 255 characters
|
# Save with custom id section greater than 255 characters
|
||||||
id_section = b"Test content" * 25
|
id_section = b"Test content" * 25
|
||||||
self.assert_warning(UserWarning,
|
self.assert_warning(UserWarning, lambda: im.save(out, id_section=id_section))
|
||||||
lambda: im.save(out, id_section=id_section))
|
|
||||||
test_im = Image.open(out)
|
test_im = Image.open(out)
|
||||||
self.assertEqual(test_im.info["id_section"], id_section[:255])
|
self.assertEqual(test_im.info["id_section"], id_section[:255])
|
||||||
|
|
||||||
|
@ -191,15 +189,13 @@ class TestFileTga(PillowTestCase):
|
||||||
in_file = "Tests/images/la.tga"
|
in_file = "Tests/images/la.tga"
|
||||||
im = Image.open(in_file)
|
im = Image.open(in_file)
|
||||||
self.assertEqual(im.mode, "LA")
|
self.assertEqual(im.mode, "LA")
|
||||||
self.assertEqual(
|
self.assertEqual(im.getchannel("A").getcolors()[0][0], num_transparent)
|
||||||
im.getchannel("A").getcolors()[0][0], num_transparent)
|
|
||||||
|
|
||||||
out = self.tempfile("temp.tga")
|
out = self.tempfile("temp.tga")
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
||||||
test_im = Image.open(out)
|
test_im = Image.open(out)
|
||||||
self.assertEqual(test_im.mode, "LA")
|
self.assertEqual(test_im.mode, "LA")
|
||||||
self.assertEqual(
|
self.assertEqual(test_im.getchannel("A").getcolors()[0][0], num_transparent)
|
||||||
test_im.getchannel("A").getcolors()[0][0], num_transparent)
|
|
||||||
|
|
||||||
self.assert_image_equal(im, test_im)
|
self.assert_image_equal(im, test_im)
|
||||||
|
|
|
@ -12,7 +12,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TestFileTiff(PillowTestCase):
|
class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
filename = self.tempfile("temp.tif")
|
filename = self.tempfile("temp.tif")
|
||||||
|
@ -44,6 +43,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
def open():
|
def open():
|
||||||
im = Image.open("Tests/images/multipage.tiff")
|
im = Image.open("Tests/images/multipage.tiff")
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_warning(None, open)
|
self.assert_warning(None, open)
|
||||||
|
|
||||||
def test_mac_tiff(self):
|
def test_mac_tiff(self):
|
||||||
|
@ -54,7 +54,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
self.assertEqual(im.mode, "RGBA")
|
self.assertEqual(im.mode, "RGBA")
|
||||||
self.assertEqual(im.size, (55, 43))
|
self.assertEqual(im.size, (55, 43))
|
||||||
self.assertEqual(im.tile, [('raw', (0, 0, 55, 43), 8, ('RGBa', 0, 1))])
|
self.assertEqual(im.tile, [("raw", (0, 0, 55, 43), 8, ("RGBa", 0, 1))])
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
|
self.assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
|
||||||
|
@ -64,16 +64,14 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
self.assertEqual(im.mode, "RGBA")
|
self.assertEqual(im.mode, "RGBA")
|
||||||
self.assertEqual(im.size, (52, 53))
|
self.assertEqual(im.size, (52, 53))
|
||||||
self.assertEqual(im.tile,
|
self.assertEqual(im.tile, [("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))])
|
||||||
[('raw', (0, 0, 52, 53), 160, ('RGBA', 0, 1))])
|
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
def test_set_legacy_api(self):
|
def test_set_legacy_api(self):
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
with self.assertRaises(Exception) as e:
|
with self.assertRaises(Exception) as e:
|
||||||
ifd.legacy_api = None
|
ifd.legacy_api = None
|
||||||
self.assertEqual(str(e.exception),
|
self.assertEqual(str(e.exception), "Not allowing setting of legacy api")
|
||||||
"Not allowing setting of legacy api")
|
|
||||||
|
|
||||||
def test_size(self):
|
def test_size(self):
|
||||||
filename = "Tests/images/pil168.tif"
|
filename = "Tests/images/pil168.tif"
|
||||||
|
@ -81,6 +79,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
def set_size():
|
def set_size():
|
||||||
im.size = (256, 256)
|
im.size = (256, 256)
|
||||||
|
|
||||||
self.assert_warning(DeprecationWarning, set_size)
|
self.assert_warning(DeprecationWarning, set_size)
|
||||||
|
|
||||||
def test_xyres_tiff(self):
|
def test_xyres_tiff(self):
|
||||||
|
@ -92,29 +91,24 @@ class TestFileTiff(PillowTestCase):
|
||||||
self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple)
|
self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple)
|
||||||
|
|
||||||
# v2 api
|
# v2 api
|
||||||
self.assertIsInstance(im.tag_v2[X_RESOLUTION],
|
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
|
||||||
TiffImagePlugin.IFDRational)
|
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
|
||||||
self.assertIsInstance(im.tag_v2[Y_RESOLUTION],
|
|
||||||
TiffImagePlugin.IFDRational)
|
|
||||||
|
|
||||||
self.assertEqual(im.info['dpi'], (72., 72.))
|
self.assertEqual(im.info["dpi"], (72.0, 72.0))
|
||||||
|
|
||||||
def test_xyres_fallback_tiff(self):
|
def test_xyres_fallback_tiff(self):
|
||||||
filename = "Tests/images/compression.tif"
|
filename = "Tests/images/compression.tif"
|
||||||
im = Image.open(filename)
|
im = Image.open(filename)
|
||||||
|
|
||||||
# v2 api
|
# v2 api
|
||||||
self.assertIsInstance(im.tag_v2[X_RESOLUTION],
|
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
|
||||||
TiffImagePlugin.IFDRational)
|
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
|
||||||
self.assertIsInstance(im.tag_v2[Y_RESOLUTION],
|
self.assertRaises(KeyError, lambda: im.tag_v2[RESOLUTION_UNIT])
|
||||||
TiffImagePlugin.IFDRational)
|
|
||||||
self.assertRaises(KeyError,
|
|
||||||
lambda: im.tag_v2[RESOLUTION_UNIT])
|
|
||||||
|
|
||||||
# Legacy.
|
# Legacy.
|
||||||
self.assertEqual(im.info['resolution'], (100., 100.))
|
self.assertEqual(im.info["resolution"], (100.0, 100.0))
|
||||||
# Fallback "inch".
|
# Fallback "inch".
|
||||||
self.assertEqual(im.info['dpi'], (100., 100.))
|
self.assertEqual(im.info["dpi"], (100.0, 100.0))
|
||||||
|
|
||||||
def test_int_resolution(self):
|
def test_int_resolution(self):
|
||||||
filename = "Tests/images/pil168.tif"
|
filename = "Tests/images/pil168.tif"
|
||||||
|
@ -124,20 +118,21 @@ class TestFileTiff(PillowTestCase):
|
||||||
im.tag_v2[X_RESOLUTION] = 71
|
im.tag_v2[X_RESOLUTION] = 71
|
||||||
im.tag_v2[Y_RESOLUTION] = 71
|
im.tag_v2[Y_RESOLUTION] = 71
|
||||||
im._setup()
|
im._setup()
|
||||||
self.assertEqual(im.info['dpi'], (71., 71.))
|
self.assertEqual(im.info["dpi"], (71.0, 71.0))
|
||||||
|
|
||||||
def test_load_dpi_rounding(self):
|
def test_load_dpi_rounding(self):
|
||||||
for resolutionUnit, dpi in ((None, (72, 73)),
|
for resolutionUnit, dpi in ((None, (72, 73)), (2, (72, 73)), (3, (183, 185))):
|
||||||
(2, (72, 73)),
|
|
||||||
(3, (183, 185))):
|
|
||||||
im = Image.open(
|
im = Image.open(
|
||||||
"Tests/images/hopper_roundDown_"+str(resolutionUnit)+".tif")
|
"Tests/images/hopper_roundDown_" + str(resolutionUnit) + ".tif"
|
||||||
|
)
|
||||||
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
|
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
|
||||||
self.assertEqual(im.info['dpi'], (dpi[0], dpi[0]))
|
self.assertEqual(im.info["dpi"], (dpi[0], dpi[0]))
|
||||||
|
|
||||||
im = Image.open("Tests/images/hopper_roundUp_"+str(resolutionUnit)+".tif")
|
im = Image.open(
|
||||||
|
"Tests/images/hopper_roundUp_" + str(resolutionUnit) + ".tif"
|
||||||
|
)
|
||||||
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
|
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
|
||||||
self.assertEqual(im.info['dpi'], (dpi[1], dpi[1]))
|
self.assertEqual(im.info["dpi"], (dpi[1], dpi[1]))
|
||||||
|
|
||||||
def test_save_dpi_rounding(self):
|
def test_save_dpi_rounding(self):
|
||||||
outfile = self.tempfile("temp.tif")
|
outfile = self.tempfile("temp.tif")
|
||||||
|
@ -148,12 +143,13 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
reloaded = Image.open(outfile)
|
reloaded = Image.open(outfile)
|
||||||
reloaded.load()
|
reloaded.load()
|
||||||
self.assertEqual((round(dpi), round(dpi)), reloaded.info['dpi'])
|
self.assertEqual((round(dpi), round(dpi)), reloaded.info["dpi"])
|
||||||
|
|
||||||
def test_save_setting_missing_resolution(self):
|
def test_save_setting_missing_resolution(self):
|
||||||
b = BytesIO()
|
b = BytesIO()
|
||||||
Image.open("Tests/images/10ct_32bit_128.tiff").save(
|
Image.open("Tests/images/10ct_32bit_128.tiff").save(
|
||||||
b, format="tiff", resolution=123.45)
|
b, format="tiff", resolution=123.45
|
||||||
|
)
|
||||||
im = Image.open(b)
|
im = Image.open(b)
|
||||||
self.assertEqual(float(im.tag_v2[X_RESOLUTION]), 123.45)
|
self.assertEqual(float(im.tag_v2[X_RESOLUTION]), 123.45)
|
||||||
self.assertEqual(float(im.tag_v2[Y_RESOLUTION]), 123.45)
|
self.assertEqual(float(im.tag_v2[Y_RESOLUTION]), 123.45)
|
||||||
|
@ -161,16 +157,14 @@ class TestFileTiff(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, TiffImagePlugin.TiffImageFile, invalid_file)
|
||||||
TiffImagePlugin.TiffImageFile, invalid_file)
|
|
||||||
|
|
||||||
TiffImagePlugin.PREFIXES.append(b"\xff\xd8\xff\xe0")
|
TiffImagePlugin.PREFIXES.append(b"\xff\xd8\xff\xe0")
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, TiffImagePlugin.TiffImageFile, invalid_file)
|
||||||
TiffImagePlugin.TiffImageFile, invalid_file)
|
|
||||||
TiffImagePlugin.PREFIXES.pop()
|
TiffImagePlugin.PREFIXES.pop()
|
||||||
|
|
||||||
def test_bad_exif(self):
|
def test_bad_exif(self):
|
||||||
i = Image.open('Tests/images/hopper_bad_exif.jpg')
|
i = Image.open("Tests/images/hopper_bad_exif.jpg")
|
||||||
# Should not raise struct.error.
|
# Should not raise struct.error.
|
||||||
self.assert_warning(UserWarning, i._getexif)
|
self.assert_warning(UserWarning, i._getexif)
|
||||||
|
|
||||||
|
@ -185,38 +179,38 @@ class TestFileTiff(PillowTestCase):
|
||||||
self.assertRaises(IOError, im.save, outfile)
|
self.assertRaises(IOError, im.save, outfile)
|
||||||
|
|
||||||
def test_little_endian(self):
|
def test_little_endian(self):
|
||||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
im = Image.open("Tests/images/16bit.cropped.tif")
|
||||||
self.assertEqual(im.getpixel((0, 0)), 480)
|
self.assertEqual(im.getpixel((0, 0)), 480)
|
||||||
self.assertEqual(im.mode, 'I;16')
|
self.assertEqual(im.mode, "I;16")
|
||||||
|
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
# Bytes are in image native order (little endian)
|
# Bytes are in image native order (little endian)
|
||||||
if py3:
|
if py3:
|
||||||
self.assertEqual(b[0], ord(b'\xe0'))
|
self.assertEqual(b[0], ord(b"\xe0"))
|
||||||
self.assertEqual(b[1], ord(b'\x01'))
|
self.assertEqual(b[1], ord(b"\x01"))
|
||||||
else:
|
else:
|
||||||
self.assertEqual(b[0], b'\xe0')
|
self.assertEqual(b[0], b"\xe0")
|
||||||
self.assertEqual(b[1], b'\x01')
|
self.assertEqual(b[1], b"\x01")
|
||||||
|
|
||||||
def test_big_endian(self):
|
def test_big_endian(self):
|
||||||
im = Image.open('Tests/images/16bit.MM.cropped.tif')
|
im = Image.open("Tests/images/16bit.MM.cropped.tif")
|
||||||
self.assertEqual(im.getpixel((0, 0)), 480)
|
self.assertEqual(im.getpixel((0, 0)), 480)
|
||||||
self.assertEqual(im.mode, 'I;16B')
|
self.assertEqual(im.mode, "I;16B")
|
||||||
|
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
|
|
||||||
# Bytes are in image native order (big endian)
|
# Bytes are in image native order (big endian)
|
||||||
if py3:
|
if py3:
|
||||||
self.assertEqual(b[0], ord(b'\x01'))
|
self.assertEqual(b[0], ord(b"\x01"))
|
||||||
self.assertEqual(b[1], ord(b'\xe0'))
|
self.assertEqual(b[1], ord(b"\xe0"))
|
||||||
else:
|
else:
|
||||||
self.assertEqual(b[0], b'\x01')
|
self.assertEqual(b[0], b"\x01")
|
||||||
self.assertEqual(b[1], b'\xe0')
|
self.assertEqual(b[1], b"\xe0")
|
||||||
|
|
||||||
def test_16bit_s(self):
|
def test_16bit_s(self):
|
||||||
im = Image.open('Tests/images/16bit.s.tif')
|
im = Image.open("Tests/images/16bit.s.tif")
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, 'I')
|
self.assertEqual(im.mode, "I")
|
||||||
self.assertEqual(im.getpixel((0, 0)), 32767)
|
self.assertEqual(im.getpixel((0, 0)), 32767)
|
||||||
self.assertEqual(im.getpixel((0, 1)), 0)
|
self.assertEqual(im.getpixel((0, 1)), 0)
|
||||||
|
|
||||||
|
@ -224,7 +218,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
""" Are we generating the same interpretation
|
""" Are we generating the same interpretation
|
||||||
of the image as Imagemagick is? """
|
of the image as Imagemagick is? """
|
||||||
|
|
||||||
im = Image.open('Tests/images/12bit.cropped.tif')
|
im = Image.open("Tests/images/12bit.cropped.tif")
|
||||||
|
|
||||||
# to make the target --
|
# to make the target --
|
||||||
# convert 12bit.cropped.tif -depth 16 tmp.tif
|
# convert 12bit.cropped.tif -depth 16 tmp.tif
|
||||||
|
@ -232,33 +226,33 @@ class TestFileTiff(PillowTestCase):
|
||||||
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
|
# 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.
|
# so we need to unshift so that the integer values are the same.
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im, 'Tests/images/12in16bit.tif')
|
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
|
||||||
|
|
||||||
def test_32bit_float(self):
|
def test_32bit_float(self):
|
||||||
# Issue 614, specific 32-bit float format
|
# Issue 614, specific 32-bit float format
|
||||||
path = 'Tests/images/10ct_32bit_128.tiff'
|
path = "Tests/images/10ct_32bit_128.tiff"
|
||||||
im = Image.open(path)
|
im = Image.open(path)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assertEqual(im.getpixel((0, 0)), -0.4526388943195343)
|
self.assertEqual(im.getpixel((0, 0)), -0.4526388943195343)
|
||||||
self.assertEqual(
|
self.assertEqual(im.getextrema(), (-3.140936851501465, 3.140684127807617))
|
||||||
im.getextrema(), (-3.140936851501465, 3.140684127807617))
|
|
||||||
|
|
||||||
def test_unknown_pixel_mode(self):
|
def test_unknown_pixel_mode(self):
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
IOError, Image.open, 'Tests/images/hopper_unknown_pixel_mode.tif')
|
IOError, Image.open, "Tests/images/hopper_unknown_pixel_mode.tif"
|
||||||
|
)
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
for path, n_frames in [
|
for path, n_frames in [
|
||||||
['Tests/images/multipage-lastframe.tif', 1],
|
["Tests/images/multipage-lastframe.tif", 1],
|
||||||
['Tests/images/multipage.tiff', 3]
|
["Tests/images/multipage.tiff", 3],
|
||||||
]:
|
]:
|
||||||
im = Image.open(path)
|
im = Image.open(path)
|
||||||
self.assertEqual(im.n_frames, n_frames)
|
self.assertEqual(im.n_frames, n_frames)
|
||||||
self.assertEqual(im.is_animated, n_frames != 1)
|
self.assertEqual(im.is_animated, n_frames != 1)
|
||||||
|
|
||||||
def test_eoferror(self):
|
def test_eoferror(self):
|
||||||
im = Image.open('Tests/images/multipage-lastframe.tif')
|
im = Image.open("Tests/images/multipage-lastframe.tif")
|
||||||
n_frames = im.n_frames
|
n_frames = im.n_frames
|
||||||
|
|
||||||
# Test seeking past the last frame
|
# Test seeking past the last frame
|
||||||
|
@ -266,37 +260,37 @@ class TestFileTiff(PillowTestCase):
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
# Test that seeking to the last frame does not raise an error
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_multipage(self):
|
def test_multipage(self):
|
||||||
# issue #862
|
# issue #862
|
||||||
im = Image.open('Tests/images/multipage.tiff')
|
im = Image.open("Tests/images/multipage.tiff")
|
||||||
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
|
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
|
||||||
|
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 128, 0))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
|
||||||
|
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (255, 0, 0))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
|
||||||
|
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 128, 0))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
|
||||||
|
|
||||||
im.seek(2)
|
im.seek(2)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.size, (20, 20))
|
self.assertEqual(im.size, (20, 20))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 0, 255))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
|
||||||
|
|
||||||
def test_multipage_last_frame(self):
|
def test_multipage_last_frame(self):
|
||||||
im = Image.open('Tests/images/multipage-lastframe.tif')
|
im = Image.open("Tests/images/multipage-lastframe.tif")
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.size, (20, 20))
|
self.assertEqual(im.size, (20, 20))
|
||||||
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 0, 255))
|
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
|
||||||
|
|
||||||
def test___str__(self):
|
def test___str__(self):
|
||||||
filename = "Tests/images/pil136.tiff"
|
filename = "Tests/images/pil136.tiff"
|
||||||
|
@ -314,16 +308,39 @@ class TestFileTiff(PillowTestCase):
|
||||||
im = Image.open(filename)
|
im = Image.open(filename)
|
||||||
|
|
||||||
# v2 interface
|
# v2 interface
|
||||||
v2_tags = {256: 55, 257: 43, 258: (8, 8, 8, 8), 259: 1,
|
v2_tags = {
|
||||||
262: 2, 296: 2, 273: (8,), 338: (1,), 277: 4,
|
256: 55,
|
||||||
279: (9460,), 282: 72.0, 283: 72.0, 284: 1}
|
257: 43,
|
||||||
|
258: (8, 8, 8, 8),
|
||||||
|
259: 1,
|
||||||
|
262: 2,
|
||||||
|
296: 2,
|
||||||
|
273: (8,),
|
||||||
|
338: (1,),
|
||||||
|
277: 4,
|
||||||
|
279: (9460,),
|
||||||
|
282: 72.0,
|
||||||
|
283: 72.0,
|
||||||
|
284: 1,
|
||||||
|
}
|
||||||
self.assertEqual(dict(im.tag_v2), v2_tags)
|
self.assertEqual(dict(im.tag_v2), v2_tags)
|
||||||
|
|
||||||
# legacy interface
|
# legacy interface
|
||||||
legacy_tags = {256: (55,), 257: (43,), 258: (8, 8, 8, 8), 259: (1,),
|
legacy_tags = {
|
||||||
262: (2,), 296: (2,), 273: (8,), 338: (1,), 277: (4,),
|
256: (55,),
|
||||||
279: (9460,), 282: ((720000, 10000),),
|
257: (43,),
|
||||||
283: ((720000, 10000),), 284: (1,)}
|
258: (8, 8, 8, 8),
|
||||||
|
259: (1,),
|
||||||
|
262: (2,),
|
||||||
|
296: (2,),
|
||||||
|
273: (8,),
|
||||||
|
338: (1,),
|
||||||
|
277: (4,),
|
||||||
|
279: (9460,),
|
||||||
|
282: ((720000, 10000),),
|
||||||
|
283: ((720000, 10000),),
|
||||||
|
284: (1,),
|
||||||
|
}
|
||||||
self.assertEqual(dict(im.tag), legacy_tags)
|
self.assertEqual(dict(im.tag), legacy_tags)
|
||||||
|
|
||||||
def test__delitem__(self):
|
def test__delitem__(self):
|
||||||
|
@ -351,13 +368,13 @@ class TestFileTiff(PillowTestCase):
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
data = b"abcdabcd"
|
data = b"abcdabcd"
|
||||||
ret = ifd.load_float(data, False)
|
ret = ifd.load_float(data, False)
|
||||||
self.assertEqual(ret, (1.6777999408082104e+22, 1.6777999408082104e+22))
|
self.assertEqual(ret, (1.6777999408082104e22, 1.6777999408082104e22))
|
||||||
|
|
||||||
def test_load_double(self):
|
def test_load_double(self):
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
data = b"abcdefghabcdefgh"
|
data = b"abcdefghabcdefgh"
|
||||||
ret = ifd.load_double(data, False)
|
ret = ifd.load_double(data, False)
|
||||||
self.assertEqual(ret, (8.540883223036124e+194, 8.540883223036124e+194))
|
self.assertEqual(ret, (8.540883223036124e194, 8.540883223036124e194))
|
||||||
|
|
||||||
def test_seek(self):
|
def test_seek(self):
|
||||||
filename = "Tests/images/pil136.tiff"
|
filename = "Tests/images/pil136.tiff"
|
||||||
|
@ -374,12 +391,14 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
def test__limit_rational_int(self):
|
def test__limit_rational_int(self):
|
||||||
from PIL.TiffImagePlugin import _limit_rational
|
from PIL.TiffImagePlugin import _limit_rational
|
||||||
|
|
||||||
value = 34
|
value = 34
|
||||||
ret = _limit_rational(value, 65536)
|
ret = _limit_rational(value, 65536)
|
||||||
self.assertEqual(ret, (34, 1))
|
self.assertEqual(ret, (34, 1))
|
||||||
|
|
||||||
def test__limit_rational_float(self):
|
def test__limit_rational_float(self):
|
||||||
from PIL.TiffImagePlugin import _limit_rational
|
from PIL.TiffImagePlugin import _limit_rational
|
||||||
|
|
||||||
value = 22.3
|
value = 22.3
|
||||||
ret = _limit_rational(value, 65536)
|
ret = _limit_rational(value, 65536)
|
||||||
self.assertEqual(ret, (223, 10))
|
self.assertEqual(ret, (223, 10))
|
||||||
|
@ -401,7 +420,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper2I.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/hopper2R.tif",
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
|
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
7.3, # epsilon
|
7.3, # epsilon
|
||||||
|
@ -410,7 +429,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper4I.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/hopper4R.tif",
|
||||||
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
|
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
original = hopper("L")
|
original = hopper("L")
|
||||||
|
@ -426,9 +445,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
def test_with_underscores(self):
|
def test_with_underscores(self):
|
||||||
kwargs = {'resolution_unit': 'inch',
|
kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
|
||||||
'x_resolution': 72,
|
|
||||||
'y_resolution': 36}
|
|
||||||
filename = self.tempfile("temp.tif")
|
filename = self.tempfile("temp.tif")
|
||||||
hopper("RGB").save(filename, **kwargs)
|
hopper("RGB").save(filename, **kwargs)
|
||||||
im = Image.open(filename)
|
im = Image.open(filename)
|
||||||
|
@ -459,8 +476,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
infile = "Tests/images/tiff_strip_raw.tif"
|
infile = "Tests/images/tiff_strip_raw.tif"
|
||||||
im = Image.open(infile)
|
im = Image.open(infile)
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||||
"Tests/images/tiff_adobe_deflate.png")
|
|
||||||
|
|
||||||
def test_strip_planar_raw(self):
|
def test_strip_planar_raw(self):
|
||||||
# gdal_translate -of GTiff -co INTERLEAVE=BAND \
|
# gdal_translate -of GTiff -co INTERLEAVE=BAND \
|
||||||
|
@ -468,16 +484,14 @@ class TestFileTiff(PillowTestCase):
|
||||||
infile = "Tests/images/tiff_strip_planar_raw.tif"
|
infile = "Tests/images/tiff_strip_planar_raw.tif"
|
||||||
im = Image.open(infile)
|
im = Image.open(infile)
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||||
"Tests/images/tiff_adobe_deflate.png")
|
|
||||||
|
|
||||||
def test_strip_planar_raw_with_overviews(self):
|
def test_strip_planar_raw_with_overviews(self):
|
||||||
# gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16
|
# gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16
|
||||||
infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif"
|
infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif"
|
||||||
im = Image.open(infile)
|
im = Image.open(infile)
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||||
"Tests/images/tiff_adobe_deflate.png")
|
|
||||||
|
|
||||||
def test_tiled_planar_raw(self):
|
def test_tiled_planar_raw(self):
|
||||||
# gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \
|
# gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \
|
||||||
|
@ -486,8 +500,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
infile = "Tests/images/tiff_tiled_planar_raw.tif"
|
infile = "Tests/images/tiff_tiled_planar_raw.tif"
|
||||||
im = Image.open(infile)
|
im = Image.open(infile)
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||||
"Tests/images/tiff_adobe_deflate.png")
|
|
||||||
|
|
||||||
def test_palette(self):
|
def test_palette(self):
|
||||||
for mode in ["P", "PA"]:
|
for mode in ["P", "PA"]:
|
||||||
|
@ -513,9 +526,8 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
# Test appending images
|
# Test appending images
|
||||||
mp = io.BytesIO()
|
mp = io.BytesIO()
|
||||||
im = Image.new('RGB', (100, 100), '#f00')
|
im = Image.new("RGB", (100, 100), "#f00")
|
||||||
ims = [Image.new('RGB', (100, 100), color) for color
|
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
|
||||||
in ['#0f0', '#00f']]
|
|
||||||
im.copy().save(mp, format="TIFF", save_all=True, append_images=ims)
|
im.copy().save(mp, format="TIFF", save_all=True, append_images=ims)
|
||||||
|
|
||||||
mp.seek(0, os.SEEK_SET)
|
mp.seek(0, os.SEEK_SET)
|
||||||
|
@ -526,9 +538,9 @@ class TestFileTiff(PillowTestCase):
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
for im in ims:
|
||||||
yield im
|
yield im
|
||||||
|
|
||||||
mp = io.BytesIO()
|
mp = io.BytesIO()
|
||||||
im.save(mp, format="TIFF", save_all=True,
|
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
|
||||||
append_images=imGenerator(ims))
|
|
||||||
|
|
||||||
mp.seek(0, os.SEEK_SET)
|
mp.seek(0, os.SEEK_SET)
|
||||||
reread = Image.open(mp)
|
reread = Image.open(mp)
|
||||||
|
@ -539,15 +551,15 @@ class TestFileTiff(PillowTestCase):
|
||||||
# At the time of writing this will only work for non-compressed tiffs
|
# At the time of writing this will only work for non-compressed tiffs
|
||||||
# as libtiff does not support embedded ICC profiles,
|
# as libtiff does not support embedded ICC profiles,
|
||||||
# ImageFile._save(..) however does.
|
# ImageFile._save(..) however does.
|
||||||
im = Image.new('RGB', (1, 1))
|
im = Image.new("RGB", (1, 1))
|
||||||
im.info['icc_profile'] = 'Dummy value'
|
im.info["icc_profile"] = "Dummy value"
|
||||||
|
|
||||||
# Try save-load round trip to make sure both handle icc_profile.
|
# Try save-load round trip to make sure both handle icc_profile.
|
||||||
tmpfile = self.tempfile('temp.tif')
|
tmpfile = self.tempfile("temp.tif")
|
||||||
im.save(tmpfile, 'TIFF', compression='raw')
|
im.save(tmpfile, "TIFF", compression="raw")
|
||||||
reloaded = Image.open(tmpfile)
|
reloaded = Image.open(tmpfile)
|
||||||
|
|
||||||
self.assertEqual(b'Dummy value', reloaded.info['icc_profile'])
|
self.assertEqual(b"Dummy value", reloaded.info["icc_profile"])
|
||||||
|
|
||||||
def test_close_on_load_exclusive(self):
|
def test_close_on_load_exclusive(self):
|
||||||
# similar to test_fd_leak, but runs on unixlike os
|
# similar to test_fd_leak, but runs on unixlike os
|
||||||
|
@ -568,7 +580,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
with Image.open("Tests/images/uint16_1_4660.tif") as im:
|
with Image.open("Tests/images/uint16_1_4660.tif") as im:
|
||||||
im.save(tmpfile)
|
im.save(tmpfile)
|
||||||
|
|
||||||
with open(tmpfile, 'rb') as f:
|
with open(tmpfile, "rb") as f:
|
||||||
im = Image.open(f)
|
im = Image.open(f)
|
||||||
fp = im.fp
|
fp = im.fp
|
||||||
self.assertFalse(fp.closed)
|
self.assertFalse(fp.closed)
|
||||||
|
@ -576,7 +588,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
self.assertFalse(fp.closed)
|
self.assertFalse(fp.closed)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only")
|
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
|
||||||
class TestFileTiffW32(PillowTestCase):
|
class TestFileTiffW32(PillowTestCase):
|
||||||
def test_fd_leak(self):
|
def test_fd_leak(self):
|
||||||
tmpfile = self.tempfile("temp.tif")
|
tmpfile = self.tempfile("temp.tif")
|
||||||
|
|
|
@ -10,7 +10,6 @@ tag_ids = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
|
||||||
|
|
||||||
|
|
||||||
class TestFileTiffMetadata(PillowTestCase):
|
class TestFileTiffMetadata(PillowTestCase):
|
||||||
|
|
||||||
def test_rt_metadata(self):
|
def test_rt_metadata(self):
|
||||||
""" Test writing arbitrary metadata into the tiff image directory
|
""" Test writing arbitrary metadata into the tiff image directory
|
||||||
Use case is ImageJ private tags, one numeric, one arbitrary
|
Use case is ImageJ private tags, one numeric, one arbitrary
|
||||||
|
@ -29,23 +28,23 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
# the tiff file format can't take 8 bit bytes in that field.
|
# the tiff file format can't take 8 bit bytes in that field.
|
||||||
|
|
||||||
basetextdata = "This is some arbitrary metadata for a text field"
|
basetextdata = "This is some arbitrary metadata for a text field"
|
||||||
bindata = basetextdata.encode('ascii') + b" \xff"
|
bindata = basetextdata.encode("ascii") + b" \xff"
|
||||||
textdata = basetextdata + " " + chr(255)
|
textdata = basetextdata + " " + chr(255)
|
||||||
reloaded_textdata = basetextdata + " ?"
|
reloaded_textdata = basetextdata + " ?"
|
||||||
floatdata = 12.345
|
floatdata = 12.345
|
||||||
doubledata = 67.89
|
doubledata = 67.89
|
||||||
info = TiffImagePlugin.ImageFileDirectory()
|
info = TiffImagePlugin.ImageFileDirectory()
|
||||||
|
|
||||||
ImageJMetaData = tag_ids['ImageJMetaData']
|
ImageJMetaData = tag_ids["ImageJMetaData"]
|
||||||
ImageJMetaDataByteCounts = tag_ids['ImageJMetaDataByteCounts']
|
ImageJMetaDataByteCounts = tag_ids["ImageJMetaDataByteCounts"]
|
||||||
ImageDescription = tag_ids['ImageDescription']
|
ImageDescription = tag_ids["ImageDescription"]
|
||||||
|
|
||||||
info[ImageJMetaDataByteCounts] = len(bindata)
|
info[ImageJMetaDataByteCounts] = len(bindata)
|
||||||
info[ImageJMetaData] = bindata
|
info[ImageJMetaData] = bindata
|
||||||
info[tag_ids['RollAngle']] = floatdata
|
info[tag_ids["RollAngle"]] = floatdata
|
||||||
info.tagtype[tag_ids['RollAngle']] = 11
|
info.tagtype[tag_ids["RollAngle"]] = 11
|
||||||
info[tag_ids['YawAngle']] = doubledata
|
info[tag_ids["YawAngle"]] = doubledata
|
||||||
info.tagtype[tag_ids['YawAngle']] = 12
|
info.tagtype[tag_ids["YawAngle"]] = 12
|
||||||
|
|
||||||
info[ImageDescription] = textdata
|
info[ImageDescription] = textdata
|
||||||
|
|
||||||
|
@ -56,8 +55,7 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
loaded = Image.open(f)
|
loaded = Image.open(f)
|
||||||
|
|
||||||
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
|
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
|
||||||
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts],
|
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),))
|
||||||
(len(bindata),))
|
|
||||||
|
|
||||||
self.assertEqual(loaded.tag[ImageJMetaData], bindata)
|
self.assertEqual(loaded.tag[ImageJMetaData], bindata)
|
||||||
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
|
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
|
||||||
|
@ -65,9 +63,9 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,))
|
self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,))
|
||||||
self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata)
|
self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata)
|
||||||
|
|
||||||
loaded_float = loaded.tag[tag_ids['RollAngle']][0]
|
loaded_float = loaded.tag[tag_ids["RollAngle"]][0]
|
||||||
self.assertAlmostEqual(loaded_float, floatdata, places=5)
|
self.assertAlmostEqual(loaded_float, floatdata, places=5)
|
||||||
loaded_double = loaded.tag[tag_ids['YawAngle']][0]
|
loaded_double = loaded.tag[tag_ids["YawAngle"]][0]
|
||||||
self.assertAlmostEqual(loaded_double, doubledata)
|
self.assertAlmostEqual(loaded_double, doubledata)
|
||||||
|
|
||||||
# check with 2 element ImageJMetaDataByteCounts, issue #2006
|
# check with 2 element ImageJMetaDataByteCounts, issue #2006
|
||||||
|
@ -76,55 +74,61 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
img.save(f, tiffinfo=info)
|
img.save(f, tiffinfo=info)
|
||||||
loaded = Image.open(f)
|
loaded = Image.open(f)
|
||||||
|
|
||||||
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts],
|
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
|
||||||
(8, len(bindata) - 8))
|
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
|
||||||
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts],
|
|
||||||
(8, len(bindata) - 8))
|
|
||||||
|
|
||||||
def test_read_metadata(self):
|
def test_read_metadata(self):
|
||||||
img = Image.open('Tests/images/hopper_g4.tif')
|
img = Image.open("Tests/images/hopper_g4.tif")
|
||||||
|
|
||||||
self.assertEqual({'YResolution': IFDRational(4294967295, 113653537),
|
self.assertEqual(
|
||||||
'PlanarConfiguration': 1,
|
{
|
||||||
'BitsPerSample': (1,),
|
"YResolution": IFDRational(4294967295, 113653537),
|
||||||
'ImageLength': 128,
|
"PlanarConfiguration": 1,
|
||||||
'Compression': 4,
|
"BitsPerSample": (1,),
|
||||||
'FillOrder': 1,
|
"ImageLength": 128,
|
||||||
'RowsPerStrip': 128,
|
"Compression": 4,
|
||||||
'ResolutionUnit': 3,
|
"FillOrder": 1,
|
||||||
'PhotometricInterpretation': 0,
|
"RowsPerStrip": 128,
|
||||||
'PageNumber': (0, 1),
|
"ResolutionUnit": 3,
|
||||||
'XResolution': IFDRational(4294967295, 113653537),
|
"PhotometricInterpretation": 0,
|
||||||
'ImageWidth': 128,
|
"PageNumber": (0, 1),
|
||||||
'Orientation': 1,
|
"XResolution": IFDRational(4294967295, 113653537),
|
||||||
'StripByteCounts': (1968,),
|
"ImageWidth": 128,
|
||||||
'SamplesPerPixel': 1,
|
"Orientation": 1,
|
||||||
'StripOffsets': (8,)
|
"StripByteCounts": (1968,),
|
||||||
}, img.tag_v2.named())
|
"SamplesPerPixel": 1,
|
||||||
|
"StripOffsets": (8,),
|
||||||
|
},
|
||||||
|
img.tag_v2.named(),
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual({'YResolution': ((4294967295, 113653537),),
|
self.assertEqual(
|
||||||
'PlanarConfiguration': (1,),
|
{
|
||||||
'BitsPerSample': (1,),
|
"YResolution": ((4294967295, 113653537),),
|
||||||
'ImageLength': (128,),
|
"PlanarConfiguration": (1,),
|
||||||
'Compression': (4,),
|
"BitsPerSample": (1,),
|
||||||
'FillOrder': (1,),
|
"ImageLength": (128,),
|
||||||
'RowsPerStrip': (128,),
|
"Compression": (4,),
|
||||||
'ResolutionUnit': (3,),
|
"FillOrder": (1,),
|
||||||
'PhotometricInterpretation': (0,),
|
"RowsPerStrip": (128,),
|
||||||
'PageNumber': (0, 1),
|
"ResolutionUnit": (3,),
|
||||||
'XResolution': ((4294967295, 113653537),),
|
"PhotometricInterpretation": (0,),
|
||||||
'ImageWidth': (128,),
|
"PageNumber": (0, 1),
|
||||||
'Orientation': (1,),
|
"XResolution": ((4294967295, 113653537),),
|
||||||
'StripByteCounts': (1968,),
|
"ImageWidth": (128,),
|
||||||
'SamplesPerPixel': (1,),
|
"Orientation": (1,),
|
||||||
'StripOffsets': (8,)
|
"StripByteCounts": (1968,),
|
||||||
}, img.tag.named())
|
"SamplesPerPixel": (1,),
|
||||||
|
"StripOffsets": (8,),
|
||||||
|
},
|
||||||
|
img.tag.named(),
|
||||||
|
)
|
||||||
|
|
||||||
def test_write_metadata(self):
|
def test_write_metadata(self):
|
||||||
""" Test metadata writing through the python code """
|
""" Test metadata writing through the python code """
|
||||||
img = Image.open('Tests/images/hopper.tif')
|
img = Image.open("Tests/images/hopper.tif")
|
||||||
|
|
||||||
f = self.tempfile('temp.tiff')
|
f = self.tempfile("temp.tiff")
|
||||||
img.save(f, tiffinfo=img.tag)
|
img.save(f, tiffinfo=img.tag)
|
||||||
|
|
||||||
loaded = Image.open(f)
|
loaded = Image.open(f)
|
||||||
|
@ -134,42 +138,44 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
|
|
||||||
for k, v in original.items():
|
for k, v in original.items():
|
||||||
if isinstance(v, IFDRational):
|
if isinstance(v, IFDRational):
|
||||||
original[k] = IFDRational(*_limit_rational(v, 2**31))
|
original[k] = IFDRational(*_limit_rational(v, 2 ** 31))
|
||||||
elif isinstance(v, tuple) and isinstance(v[0], IFDRational):
|
elif isinstance(v, tuple) and isinstance(v[0], IFDRational):
|
||||||
original[k] = tuple(IFDRational(*_limit_rational(elt, 2**31))
|
original[k] = tuple(
|
||||||
for elt in v)
|
IFDRational(*_limit_rational(elt, 2 ** 31)) for elt in v
|
||||||
|
)
|
||||||
|
|
||||||
ignored = ['StripByteCounts', 'RowsPerStrip',
|
ignored = ["StripByteCounts", "RowsPerStrip", "PageNumber", "StripOffsets"]
|
||||||
'PageNumber', 'StripOffsets']
|
|
||||||
|
|
||||||
for tag, value in reloaded.items():
|
for tag, value in reloaded.items():
|
||||||
if tag in ignored:
|
if tag in ignored:
|
||||||
continue
|
continue
|
||||||
if (isinstance(original[tag], tuple)
|
if isinstance(original[tag], tuple) and isinstance(
|
||||||
and isinstance(original[tag][0], IFDRational)):
|
original[tag][0], IFDRational
|
||||||
|
):
|
||||||
# Need to compare element by element in the tuple,
|
# Need to compare element by element in the tuple,
|
||||||
# not comparing tuples of object references
|
# not comparing tuples of object references
|
||||||
self.assert_deep_equal(original[tag],
|
self.assert_deep_equal(
|
||||||
value,
|
original[tag],
|
||||||
"%s didn't roundtrip, %s, %s" %
|
value,
|
||||||
(tag, original[tag], value))
|
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(original[tag],
|
self.assertEqual(
|
||||||
value,
|
original[tag],
|
||||||
"%s didn't roundtrip, %s, %s" %
|
value,
|
||||||
(tag, original[tag], value))
|
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
|
||||||
|
)
|
||||||
|
|
||||||
for tag, value in original.items():
|
for tag, value in original.items():
|
||||||
if tag not in ignored:
|
if tag not in ignored:
|
||||||
self.assertEqual(
|
self.assertEqual(value, reloaded[tag], "%s didn't roundtrip" % tag)
|
||||||
value, reloaded[tag], "%s didn't roundtrip" % tag)
|
|
||||||
|
|
||||||
def test_no_duplicate_50741_tag(self):
|
def test_no_duplicate_50741_tag(self):
|
||||||
self.assertEqual(tag_ids['MakerNoteSafety'], 50741)
|
self.assertEqual(tag_ids["MakerNoteSafety"], 50741)
|
||||||
self.assertEqual(tag_ids['BestQualityScale'], 50780)
|
self.assertEqual(tag_ids["BestQualityScale"], 50780)
|
||||||
|
|
||||||
def test_empty_metadata(self):
|
def test_empty_metadata(self):
|
||||||
f = io.BytesIO(b'II*\x00\x08\x00\x00\x00')
|
f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
|
||||||
head = f.read(8)
|
head = f.read(8)
|
||||||
info = TiffImagePlugin.ImageFileDirectory(head)
|
info = TiffImagePlugin.ImageFileDirectory(head)
|
||||||
# Should not raise struct.error.
|
# Should not raise struct.error.
|
||||||
|
@ -177,31 +183,31 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
|
|
||||||
def test_iccprofile(self):
|
def test_iccprofile(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/1462
|
# https://github.com/python-pillow/Pillow/issues/1462
|
||||||
im = Image.open('Tests/images/hopper.iccprofile.tif')
|
im = Image.open("Tests/images/hopper.iccprofile.tif")
|
||||||
out = self.tempfile('temp.tiff')
|
out = self.tempfile("temp.tiff")
|
||||||
|
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assertNotIsInstance(im.info['icc_profile'], tuple)
|
self.assertNotIsInstance(im.info["icc_profile"], tuple)
|
||||||
self.assertEqual(im.info['icc_profile'], reloaded.info['icc_profile'])
|
self.assertEqual(im.info["icc_profile"], reloaded.info["icc_profile"])
|
||||||
|
|
||||||
def test_iccprofile_binary(self):
|
def test_iccprofile_binary(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/1526
|
# https://github.com/python-pillow/Pillow/issues/1526
|
||||||
# We should be able to load this,
|
# We should be able to load this,
|
||||||
# but probably won't be able to save it.
|
# but probably won't be able to save it.
|
||||||
|
|
||||||
im = Image.open('Tests/images/hopper.iccprofile_binary.tif')
|
im = Image.open("Tests/images/hopper.iccprofile_binary.tif")
|
||||||
self.assertEqual(im.tag_v2.tagtype[34675], 1)
|
self.assertEqual(im.tag_v2.tagtype[34675], 1)
|
||||||
self.assertTrue(im.info['icc_profile'])
|
self.assertTrue(im.info["icc_profile"])
|
||||||
|
|
||||||
def test_iccprofile_save_png(self):
|
def test_iccprofile_save_png(self):
|
||||||
im = Image.open('Tests/images/hopper.iccprofile.tif')
|
im = Image.open("Tests/images/hopper.iccprofile.tif")
|
||||||
outfile = self.tempfile('temp.png')
|
outfile = self.tempfile("temp.png")
|
||||||
im.save(outfile)
|
im.save(outfile)
|
||||||
|
|
||||||
def test_iccprofile_binary_save_png(self):
|
def test_iccprofile_binary_save_png(self):
|
||||||
im = Image.open('Tests/images/hopper.iccprofile_binary.tif')
|
im = Image.open("Tests/images/hopper.iccprofile_binary.tif")
|
||||||
outfile = self.tempfile('temp.png')
|
outfile = self.tempfile("temp.png")
|
||||||
im.save(outfile)
|
im.save(outfile)
|
||||||
|
|
||||||
def test_exif_div_zero(self):
|
def test_exif_div_zero(self):
|
||||||
|
@ -209,8 +215,8 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
info = TiffImagePlugin.ImageFileDirectory_v2()
|
info = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
info[41988] = TiffImagePlugin.IFDRational(0, 0)
|
info[41988] = TiffImagePlugin.IFDRational(0, 0)
|
||||||
|
|
||||||
out = self.tempfile('temp.tiff')
|
out = self.tempfile("temp.tiff")
|
||||||
im.save(out, tiffinfo=info, compression='raw')
|
im.save(out, tiffinfo=info, compression="raw")
|
||||||
|
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assertEqual(0, reloaded.tag_v2[41988].numerator)
|
self.assertEqual(0, reloaded.tag_v2[41988].numerator)
|
||||||
|
@ -218,10 +224,11 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
|
|
||||||
def test_expty_values(self):
|
def test_expty_values(self):
|
||||||
data = io.BytesIO(
|
data = io.BytesIO(
|
||||||
b'II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00'
|
b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
|
||||||
b'\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||||
b'\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a '
|
b"\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a "
|
||||||
b'text\x00\x00')
|
b"text\x00\x00"
|
||||||
|
)
|
||||||
head = data.read(8)
|
head = data.read(8)
|
||||||
info = TiffImagePlugin.ImageFileDirectory_v2(head)
|
info = TiffImagePlugin.ImageFileDirectory_v2(head)
|
||||||
info.load(data)
|
info.load(data)
|
||||||
|
@ -230,10 +237,10 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
self.assertIn(33432, info)
|
self.assertIn(33432, info)
|
||||||
|
|
||||||
def test_PhotoshopInfo(self):
|
def test_PhotoshopInfo(self):
|
||||||
im = Image.open('Tests/images/issue_2278.tif')
|
im = Image.open("Tests/images/issue_2278.tif")
|
||||||
|
|
||||||
self.assertIsInstance(im.tag_v2[34377], bytes)
|
self.assertIsInstance(im.tag_v2[34377], bytes)
|
||||||
out = self.tempfile('temp.tiff')
|
out = self.tempfile("temp.tiff")
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reloaded = Image.open(out)
|
reloaded = Image.open(out)
|
||||||
self.assertIsInstance(reloaded.tag_v2[34377], bytes)
|
self.assertIsInstance(reloaded.tag_v2[34377], bytes)
|
||||||
|
@ -242,7 +249,7 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
|
|
||||||
# 277: ("SamplesPerPixel", SHORT, 1),
|
# 277: ("SamplesPerPixel", SHORT, 1),
|
||||||
ifd._tagdata[277] = struct.pack('hh', 4, 4)
|
ifd._tagdata[277] = struct.pack("hh", 4, 4)
|
||||||
ifd.tagtype[277] = TiffTags.SHORT
|
ifd.tagtype[277] = TiffTags.SHORT
|
||||||
|
|
||||||
# Should not raise ValueError.
|
# Should not raise ValueError.
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import WalImageFile
|
||||||
|
|
||||||
|
|
||||||
class TestFileWal(PillowTestCase):
|
class TestFileWal(PillowTestCase):
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
TEST_FILE = "Tests/images/hopper.wal"
|
TEST_FILE = "Tests/images/hopper.wal"
|
||||||
|
|
|
@ -4,6 +4,7 @@ from PIL import Image, WebPImagePlugin
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
@ -16,8 +17,7 @@ class TestUnsupportedWebp(PillowTestCase):
|
||||||
|
|
||||||
file_path = "Tests/images/hopper.webp"
|
file_path = "Tests/images/hopper.webp"
|
||||||
self.assert_warning(
|
self.assert_warning(
|
||||||
UserWarning,
|
UserWarning, lambda: self.assertRaises(IOError, Image.open, file_path)
|
||||||
lambda: self.assertRaises(IOError, Image.open, file_path)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if HAVE_WEBP:
|
if HAVE_WEBP:
|
||||||
|
@ -26,7 +26,6 @@ class TestUnsupportedWebp(PillowTestCase):
|
||||||
|
|
||||||
@unittest.skipIf(not HAVE_WEBP, "WebP support not installed")
|
@unittest.skipIf(not HAVE_WEBP, "WebP support not installed")
|
||||||
class TestFileWebp(PillowTestCase):
|
class TestFileWebp(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.rgb_mode = "RGB"
|
self.rgb_mode = "RGB"
|
||||||
|
|
||||||
|
@ -51,7 +50,8 @@ class TestFileWebp(PillowTestCase):
|
||||||
# generated with:
|
# generated with:
|
||||||
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
|
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
|
||||||
self.assert_image_similar_tofile(
|
self.assert_image_similar_tofile(
|
||||||
image, 'Tests/images/hopper_webp_bits.ppm', 1.0)
|
image, "Tests/images/hopper_webp_bits.ppm", 1.0
|
||||||
|
)
|
||||||
|
|
||||||
def test_write_rgb(self):
|
def test_write_rgb(self):
|
||||||
"""
|
"""
|
||||||
|
@ -72,7 +72,8 @@ class TestFileWebp(PillowTestCase):
|
||||||
|
|
||||||
# generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm
|
# generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm
|
||||||
self.assert_image_similar_tofile(
|
self.assert_image_similar_tofile(
|
||||||
image, 'Tests/images/hopper_webp_write.ppm', 12.0)
|
image, "Tests/images/hopper_webp_write.ppm", 12.0
|
||||||
|
)
|
||||||
|
|
||||||
# This test asserts that the images are similar. If the average pixel
|
# This test asserts that the images are similar. If the average pixel
|
||||||
# difference between the two images is less than the epsilon value,
|
# difference between the two images is less than the epsilon value,
|
||||||
|
@ -149,12 +150,13 @@ class TestFileWebp(PillowTestCase):
|
||||||
|
|
||||||
def test_file_pointer_could_be_reused(self):
|
def test_file_pointer_could_be_reused(self):
|
||||||
file_path = "Tests/images/hopper.webp"
|
file_path = "Tests/images/hopper.webp"
|
||||||
with open(file_path, 'rb') as blob:
|
with open(file_path, "rb") as blob:
|
||||||
Image.open(blob).load()
|
Image.open(blob).load()
|
||||||
Image.open(blob).load()
|
Image.open(blob).load()
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_WEBP and _webp.HAVE_WEBPANIM,
|
@unittest.skipUnless(
|
||||||
"WebP save all not available")
|
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP save all not available"
|
||||||
|
)
|
||||||
def test_background_from_gif(self):
|
def test_background_from_gif(self):
|
||||||
im = Image.open("Tests/images/chi.gif")
|
im = Image.open("Tests/images/chi.gif")
|
||||||
original_value = im.convert("RGB").getpixel((1, 1))
|
original_value = im.convert("RGB").getpixel((1, 1))
|
||||||
|
@ -169,6 +171,7 @@ class TestFileWebp(PillowTestCase):
|
||||||
|
|
||||||
reread = Image.open(out_gif)
|
reread = Image.open(out_gif)
|
||||||
reread_value = reread.convert("RGB").getpixel((1, 1))
|
reread_value = reread.convert("RGB").getpixel((1, 1))
|
||||||
difference = sum([abs(original_value[i] - reread_value[i])
|
difference = sum(
|
||||||
for i in range(0, 3)])
|
[abs(original_value[i] - reread_value[i]) for i in range(0, 3)]
|
||||||
|
)
|
||||||
self.assertLess(difference, 5)
|
self.assertLess(difference, 5)
|
||||||
|
|
|
@ -10,11 +10,11 @@ except ImportError:
|
||||||
|
|
||||||
@unittest.skipIf(_webp is None, "WebP support not installed")
|
@unittest.skipIf(_webp is None, "WebP support not installed")
|
||||||
class TestFileWebpAlpha(PillowTestCase):
|
class TestFileWebpAlpha(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if _webp.WebPDecoderBuggyAlpha(self):
|
if _webp.WebPDecoderBuggyAlpha(self):
|
||||||
self.skipTest("Buggy early version of WebP installed, "
|
self.skipTest(
|
||||||
"not testing transparency")
|
"Buggy early version of WebP installed, not testing transparency"
|
||||||
|
)
|
||||||
|
|
||||||
def test_read_rgba(self):
|
def test_read_rgba(self):
|
||||||
"""
|
"""
|
||||||
|
@ -34,7 +34,7 @@ class TestFileWebpAlpha(PillowTestCase):
|
||||||
|
|
||||||
image.tobytes()
|
image.tobytes()
|
||||||
|
|
||||||
target = Image.open('Tests/images/transparent.png')
|
target = Image.open("Tests/images/transparent.png")
|
||||||
self.assert_image_similar(image, target, 20.0)
|
self.assert_image_similar(image, target, 20.0)
|
||||||
|
|
||||||
def test_write_lossless_rgb(self):
|
def test_write_lossless_rgb(self):
|
||||||
|
@ -46,7 +46,7 @@ class TestFileWebpAlpha(PillowTestCase):
|
||||||
temp_file = self.tempfile("temp.webp")
|
temp_file = self.tempfile("temp.webp")
|
||||||
# temp_file = "temp.webp"
|
# temp_file = "temp.webp"
|
||||||
|
|
||||||
pil_image = hopper('RGBA')
|
pil_image = hopper("RGBA")
|
||||||
|
|
||||||
mask = Image.new("RGBA", (64, 64), (128, 128, 128, 128))
|
mask = Image.new("RGBA", (64, 64), (128, 128, 128, 128))
|
||||||
# Add some partially transparent bits:
|
# Add some partially transparent bits:
|
||||||
|
|
|
@ -4,21 +4,23 @@ from PIL import Image
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
|
||||||
|
|
||||||
class TestFileWebpAnimation(PillowTestCase):
|
class TestFileWebpAnimation(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if not HAVE_WEBP:
|
if not HAVE_WEBP:
|
||||||
self.skipTest('WebP support not installed')
|
self.skipTest("WebP support not installed")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not _webp.HAVE_WEBPANIM:
|
if not _webp.HAVE_WEBPANIM:
|
||||||
self.skipTest("WebP library does not contain animation support, "
|
self.skipTest(
|
||||||
"not testing animation")
|
"WebP library does not contain animation support, "
|
||||||
|
"not testing animation"
|
||||||
|
)
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
"""
|
"""
|
||||||
|
@ -53,8 +55,8 @@ class TestFileWebpAnimation(PillowTestCase):
|
||||||
orig.load()
|
orig.load()
|
||||||
im.load()
|
im.load()
|
||||||
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
|
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
|
||||||
orig.seek(orig.n_frames-1)
|
orig.seek(orig.n_frames - 1)
|
||||||
im.seek(im.n_frames-1)
|
im.seek(im.n_frames - 1)
|
||||||
orig.load()
|
orig.load()
|
||||||
im.load()
|
im.load()
|
||||||
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
|
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
|
||||||
|
@ -78,23 +80,27 @@ class TestFileWebpAnimation(PillowTestCase):
|
||||||
im.load()
|
im.load()
|
||||||
self.assert_image_equal(im, frame2.convert("RGBA"))
|
self.assert_image_equal(im, frame2.convert("RGBA"))
|
||||||
|
|
||||||
frame1 = Image.open('Tests/images/anim_frame1.webp')
|
frame1 = Image.open("Tests/images/anim_frame1.webp")
|
||||||
frame2 = Image.open('Tests/images/anim_frame2.webp')
|
frame2 = Image.open("Tests/images/anim_frame2.webp")
|
||||||
|
|
||||||
temp_file1 = self.tempfile("temp.webp")
|
temp_file1 = self.tempfile("temp.webp")
|
||||||
frame1.copy().save(temp_file1,
|
frame1.copy().save(
|
||||||
save_all=True, append_images=[frame2],
|
temp_file1, save_all=True, append_images=[frame2], lossless=True
|
||||||
lossless=True)
|
)
|
||||||
check(temp_file1)
|
check(temp_file1)
|
||||||
|
|
||||||
# Tests appending using a generator
|
# Tests appending using a generator
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
for im in ims:
|
||||||
yield im
|
yield im
|
||||||
|
|
||||||
temp_file2 = self.tempfile("temp_generator.webp")
|
temp_file2 = self.tempfile("temp_generator.webp")
|
||||||
frame1.copy().save(temp_file2,
|
frame1.copy().save(
|
||||||
save_all=True, append_images=imGenerator([frame2]),
|
temp_file2,
|
||||||
lossless=True)
|
save_all=True,
|
||||||
|
append_images=imGenerator([frame2]),
|
||||||
|
lossless=True,
|
||||||
|
)
|
||||||
check(temp_file2)
|
check(temp_file2)
|
||||||
|
|
||||||
def test_timestamp_and_duration(self):
|
def test_timestamp_and_duration(self):
|
||||||
|
@ -105,11 +111,14 @@ class TestFileWebpAnimation(PillowTestCase):
|
||||||
|
|
||||||
durations = [0, 10, 20, 30, 40]
|
durations = [0, 10, 20, 30, 40]
|
||||||
temp_file = self.tempfile("temp.webp")
|
temp_file = self.tempfile("temp.webp")
|
||||||
frame1 = Image.open('Tests/images/anim_frame1.webp')
|
frame1 = Image.open("Tests/images/anim_frame1.webp")
|
||||||
frame2 = Image.open('Tests/images/anim_frame2.webp')
|
frame2 = Image.open("Tests/images/anim_frame2.webp")
|
||||||
frame1.save(temp_file, save_all=True,
|
frame1.save(
|
||||||
append_images=[frame2, frame1, frame2, frame1],
|
temp_file,
|
||||||
duration=durations)
|
save_all=True,
|
||||||
|
append_images=[frame2, frame1, frame2, frame1],
|
||||||
|
duration=durations,
|
||||||
|
)
|
||||||
|
|
||||||
im = Image.open(temp_file)
|
im = Image.open(temp_file)
|
||||||
self.assertEqual(im.n_frames, 5)
|
self.assertEqual(im.n_frames, 5)
|
||||||
|
@ -133,18 +142,21 @@ class TestFileWebpAnimation(PillowTestCase):
|
||||||
|
|
||||||
dur = 33
|
dur = 33
|
||||||
temp_file = self.tempfile("temp.webp")
|
temp_file = self.tempfile("temp.webp")
|
||||||
frame1 = Image.open('Tests/images/anim_frame1.webp')
|
frame1 = Image.open("Tests/images/anim_frame1.webp")
|
||||||
frame2 = Image.open('Tests/images/anim_frame2.webp')
|
frame2 = Image.open("Tests/images/anim_frame2.webp")
|
||||||
frame1.save(temp_file, save_all=True,
|
frame1.save(
|
||||||
append_images=[frame2, frame1, frame2, frame1],
|
temp_file,
|
||||||
duration=dur)
|
save_all=True,
|
||||||
|
append_images=[frame2, frame1, frame2, frame1],
|
||||||
|
duration=dur,
|
||||||
|
)
|
||||||
|
|
||||||
im = Image.open(temp_file)
|
im = Image.open(temp_file)
|
||||||
self.assertEqual(im.n_frames, 5)
|
self.assertEqual(im.n_frames, 5)
|
||||||
self.assertTrue(im.is_animated)
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
# Traverse frames in reverse, checking timestamps and durations
|
# Traverse frames in reverse, checking timestamps and durations
|
||||||
ts = dur * (im.n_frames-1)
|
ts = dur * (im.n_frames - 1)
|
||||||
for frame in reversed(range(im.n_frames)):
|
for frame in reversed(range(im.n_frames)):
|
||||||
im.seek(frame)
|
im.seek(frame)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
|
@ -4,20 +4,20 @@ from PIL import Image
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
|
||||||
|
|
||||||
class TestFileWebpLossless(PillowTestCase):
|
class TestFileWebpLossless(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if not HAVE_WEBP:
|
if not HAVE_WEBP:
|
||||||
self.skipTest('WebP support not installed')
|
self.skipTest("WebP support not installed")
|
||||||
return
|
return
|
||||||
|
|
||||||
if _webp.WebPDecoderVersion() < 0x0200:
|
if _webp.WebPDecoderVersion() < 0x0200:
|
||||||
self.skipTest('lossless not included')
|
self.skipTest("lossless not included")
|
||||||
|
|
||||||
self.rgb_mode = "RGB"
|
self.rgb_mode = "RGB"
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,20 @@ from PIL import Image
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _webp
|
from PIL import _webp
|
||||||
|
|
||||||
HAVE_WEBP = True
|
HAVE_WEBP = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
|
||||||
|
|
||||||
class TestFileWebpMetadata(PillowTestCase):
|
class TestFileWebpMetadata(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if not HAVE_WEBP:
|
if not HAVE_WEBP:
|
||||||
self.skipTest('WebP support not installed')
|
self.skipTest("WebP support not installed")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not _webp.HAVE_WEBPMUX:
|
if not _webp.HAVE_WEBPMUX:
|
||||||
self.skipTest('WebPMux support not installed')
|
self.skipTest("WebPMux support not installed")
|
||||||
|
|
||||||
def test_read_exif_metadata(self):
|
def test_read_exif_metadata(self):
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
# camera make
|
# camera make
|
||||||
self.assertEqual(exif[271], "Canon")
|
self.assertEqual(exif[271], "Canon")
|
||||||
|
|
||||||
jpeg_image = Image.open('Tests/images/flower.jpg')
|
jpeg_image = Image.open("Tests/images/flower.jpg")
|
||||||
expected_exif = jpeg_image.info['exif']
|
expected_exif = jpeg_image.info["exif"]
|
||||||
|
|
||||||
self.assertEqual(exif_data, expected_exif)
|
self.assertEqual(exif_data, expected_exif)
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
|
|
||||||
file_path = "Tests/images/flower.jpg"
|
file_path = "Tests/images/flower.jpg"
|
||||||
image = Image.open(file_path)
|
image = Image.open(file_path)
|
||||||
expected_exif = image.info['exif']
|
expected_exif = image.info["exif"]
|
||||||
|
|
||||||
test_buffer = BytesIO()
|
test_buffer = BytesIO()
|
||||||
|
|
||||||
|
@ -52,11 +52,10 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
test_buffer.seek(0)
|
test_buffer.seek(0)
|
||||||
webp_image = Image.open(test_buffer)
|
webp_image = Image.open(test_buffer)
|
||||||
|
|
||||||
webp_exif = webp_image.info.get('exif', None)
|
webp_exif = webp_image.info.get("exif", None)
|
||||||
self.assertTrue(webp_exif)
|
self.assertTrue(webp_exif)
|
||||||
if webp_exif:
|
if webp_exif:
|
||||||
self.assertEqual(
|
self.assertEqual(webp_exif, expected_exif, "WebP EXIF didn't match")
|
||||||
webp_exif, expected_exif, "WebP EXIF didn't match")
|
|
||||||
|
|
||||||
def test_read_icc_profile(self):
|
def test_read_icc_profile(self):
|
||||||
|
|
||||||
|
@ -66,10 +65,10 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
self.assertEqual(image.format, "WEBP")
|
self.assertEqual(image.format, "WEBP")
|
||||||
self.assertTrue(image.info.get("icc_profile", None))
|
self.assertTrue(image.info.get("icc_profile", None))
|
||||||
|
|
||||||
icc = image.info['icc_profile']
|
icc = image.info["icc_profile"]
|
||||||
|
|
||||||
jpeg_image = Image.open('Tests/images/flower2.jpg')
|
jpeg_image = Image.open("Tests/images/flower2.jpg")
|
||||||
expected_icc = jpeg_image.info['icc_profile']
|
expected_icc = jpeg_image.info["icc_profile"]
|
||||||
|
|
||||||
self.assertEqual(icc, expected_icc)
|
self.assertEqual(icc, expected_icc)
|
||||||
|
|
||||||
|
@ -78,7 +77,7 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
|
|
||||||
file_path = "Tests/images/flower2.jpg"
|
file_path = "Tests/images/flower2.jpg"
|
||||||
image = Image.open(file_path)
|
image = Image.open(file_path)
|
||||||
expected_icc_profile = image.info['icc_profile']
|
expected_icc_profile = image.info["icc_profile"]
|
||||||
|
|
||||||
test_buffer = BytesIO()
|
test_buffer = BytesIO()
|
||||||
|
|
||||||
|
@ -87,20 +86,20 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
test_buffer.seek(0)
|
test_buffer.seek(0)
|
||||||
webp_image = Image.open(test_buffer)
|
webp_image = Image.open(test_buffer)
|
||||||
|
|
||||||
webp_icc_profile = webp_image.info.get('icc_profile', None)
|
webp_icc_profile = webp_image.info.get("icc_profile", None)
|
||||||
|
|
||||||
self.assertTrue(webp_icc_profile)
|
self.assertTrue(webp_icc_profile)
|
||||||
if webp_icc_profile:
|
if webp_icc_profile:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
webp_icc_profile, expected_icc_profile,
|
webp_icc_profile, expected_icc_profile, "Webp ICC didn't match"
|
||||||
"Webp ICC didn't match")
|
)
|
||||||
|
|
||||||
def test_read_no_exif(self):
|
def test_read_no_exif(self):
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
file_path = "Tests/images/flower.jpg"
|
file_path = "Tests/images/flower.jpg"
|
||||||
image = Image.open(file_path)
|
image = Image.open(file_path)
|
||||||
self.assertIn('exif', image.info)
|
self.assertIn("exif", image.info)
|
||||||
|
|
||||||
test_buffer = BytesIO()
|
test_buffer = BytesIO()
|
||||||
|
|
||||||
|
@ -113,23 +112,28 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
|
|
||||||
def test_write_animated_metadata(self):
|
def test_write_animated_metadata(self):
|
||||||
if not _webp.HAVE_WEBPANIM:
|
if not _webp.HAVE_WEBPANIM:
|
||||||
self.skipTest('WebP animation support not available')
|
self.skipTest("WebP animation support not available")
|
||||||
|
|
||||||
iccp_data = '<iccp_data>'.encode('utf-8')
|
iccp_data = "<iccp_data>".encode("utf-8")
|
||||||
exif_data = '<exif_data>'.encode('utf-8')
|
exif_data = "<exif_data>".encode("utf-8")
|
||||||
xmp_data = '<xmp_data>'.encode('utf-8')
|
xmp_data = "<xmp_data>".encode("utf-8")
|
||||||
|
|
||||||
temp_file = self.tempfile("temp.webp")
|
temp_file = self.tempfile("temp.webp")
|
||||||
frame1 = Image.open('Tests/images/anim_frame1.webp')
|
frame1 = Image.open("Tests/images/anim_frame1.webp")
|
||||||
frame2 = Image.open('Tests/images/anim_frame2.webp')
|
frame2 = Image.open("Tests/images/anim_frame2.webp")
|
||||||
frame1.save(temp_file, save_all=True,
|
frame1.save(
|
||||||
append_images=[frame2, frame1, frame2],
|
temp_file,
|
||||||
icc_profile=iccp_data, exif=exif_data, xmp=xmp_data)
|
save_all=True,
|
||||||
|
append_images=[frame2, frame1, frame2],
|
||||||
|
icc_profile=iccp_data,
|
||||||
|
exif=exif_data,
|
||||||
|
xmp=xmp_data,
|
||||||
|
)
|
||||||
|
|
||||||
image = Image.open(temp_file)
|
image = Image.open(temp_file)
|
||||||
self.assertIn('icc_profile', image.info)
|
self.assertIn("icc_profile", image.info)
|
||||||
self.assertIn('exif', image.info)
|
self.assertIn("exif", image.info)
|
||||||
self.assertIn('xmp', image.info)
|
self.assertIn("xmp", image.info)
|
||||||
self.assertEqual(iccp_data, image.info.get('icc_profile', None))
|
self.assertEqual(iccp_data, image.info.get("icc_profile", None))
|
||||||
self.assertEqual(exif_data, image.info.get('exif', None))
|
self.assertEqual(exif_data, image.info.get("exif", None))
|
||||||
self.assertEqual(xmp_data, image.info.get('xmp', None))
|
self.assertEqual(xmp_data, image.info.get("xmp", None))
|
||||||
|
|
|
@ -5,26 +5,25 @@ from PIL import WmfImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFileWmf(PillowTestCase):
|
class TestFileWmf(PillowTestCase):
|
||||||
|
|
||||||
def test_load_raw(self):
|
def test_load_raw(self):
|
||||||
|
|
||||||
# Test basic EMF open and rendering
|
# Test basic EMF open and rendering
|
||||||
im = Image.open('Tests/images/drawing.emf')
|
im = Image.open("Tests/images/drawing.emf")
|
||||||
if hasattr(Image.core, "drawwmf"):
|
if hasattr(Image.core, "drawwmf"):
|
||||||
# Currently, support for WMF/EMF is Windows-only
|
# Currently, support for WMF/EMF is Windows-only
|
||||||
im.load()
|
im.load()
|
||||||
# Compare to reference rendering
|
# Compare to reference rendering
|
||||||
imref = Image.open('Tests/images/drawing_emf_ref.png')
|
imref = Image.open("Tests/images/drawing_emf_ref.png")
|
||||||
imref.load()
|
imref.load()
|
||||||
self.assert_image_similar(im, imref, 0)
|
self.assert_image_similar(im, imref, 0)
|
||||||
|
|
||||||
# Test basic WMF open and rendering
|
# Test basic WMF open and rendering
|
||||||
im = Image.open('Tests/images/drawing.wmf')
|
im = Image.open("Tests/images/drawing.wmf")
|
||||||
if hasattr(Image.core, "drawwmf"):
|
if hasattr(Image.core, "drawwmf"):
|
||||||
# Currently, support for WMF/EMF is Windows-only
|
# Currently, support for WMF/EMF is Windows-only
|
||||||
im.load()
|
im.load()
|
||||||
# Compare to reference rendering
|
# Compare to reference rendering
|
||||||
imref = Image.open('Tests/images/drawing_wmf_ref.png')
|
imref = Image.open("Tests/images/drawing_wmf_ref.png")
|
||||||
imref.load()
|
imref.load()
|
||||||
self.assert_image_similar(im, imref, 2.0)
|
self.assert_image_similar(im, imref, 2.0)
|
||||||
|
|
||||||
|
@ -34,6 +33,7 @@ class TestFileWmf(PillowTestCase):
|
||||||
|
|
||||||
def save(self, im, fp, filename):
|
def save(self, im, fp, filename):
|
||||||
self.methodCalled = True
|
self.methodCalled = True
|
||||||
|
|
||||||
handler = TestHandler()
|
handler = TestHandler()
|
||||||
WmfImagePlugin.register_handler(handler)
|
WmfImagePlugin.register_handler(handler)
|
||||||
|
|
||||||
|
@ -47,16 +47,16 @@ class TestFileWmf(PillowTestCase):
|
||||||
|
|
||||||
def test_load_dpi_rounding(self):
|
def test_load_dpi_rounding(self):
|
||||||
# Round up
|
# Round up
|
||||||
im = Image.open('Tests/images/drawing.emf')
|
im = Image.open("Tests/images/drawing.emf")
|
||||||
self.assertEqual(im.info["dpi"], 1424)
|
self.assertEqual(im.info["dpi"], 1424)
|
||||||
|
|
||||||
# Round down
|
# Round down
|
||||||
im = Image.open('Tests/images/drawing_roundDown.emf')
|
im = Image.open("Tests/images/drawing_roundDown.emf")
|
||||||
self.assertEqual(im.info["dpi"], 1426)
|
self.assertEqual(im.info["dpi"], 1426)
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
||||||
for ext in [".wmf", ".emf"]:
|
for ext in [".wmf", ".emf"]:
|
||||||
tmpfile = self.tempfile("temp"+ext)
|
tmpfile = self.tempfile("temp" + ext)
|
||||||
self.assertRaises(IOError, im.save, tmpfile)
|
self.assertRaises(IOError, im.save, tmpfile)
|
||||||
|
|
|
@ -27,14 +27,13 @@ static char basic_bits[] = {
|
||||||
|
|
||||||
|
|
||||||
class TestFileXbm(PillowTestCase):
|
class TestFileXbm(PillowTestCase):
|
||||||
|
|
||||||
def test_pil151(self):
|
def test_pil151(self):
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
im = Image.open(BytesIO(PIL151))
|
im = Image.open(BytesIO(PIL151))
|
||||||
|
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, '1')
|
self.assertEqual(im.mode, "1")
|
||||||
self.assertEqual(im.size, (32, 32))
|
self.assertEqual(im.size, (32, 32))
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
|
@ -46,7 +45,7 @@ class TestFileXbm(PillowTestCase):
|
||||||
im = Image.open(filename)
|
im = Image.open(filename)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.mode, '1')
|
self.assertEqual(im.mode, "1")
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
|
|
||||||
def test_open_filename_with_underscore(self):
|
def test_open_filename_with_underscore(self):
|
||||||
|
@ -58,5 +57,5 @@ class TestFileXbm(PillowTestCase):
|
||||||
im = Image.open(filename)
|
im = Image.open(filename)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.mode, '1')
|
self.assertEqual(im.mode, "1")
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hopper.xpm"
|
||||||
|
|
||||||
|
|
||||||
class TestFileXpm(PillowTestCase):
|
class TestFileXpm(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
im.load()
|
im.load()
|
||||||
|
@ -15,13 +14,12 @@ class TestFileXpm(PillowTestCase):
|
||||||
self.assertEqual(im.format, "XPM")
|
self.assertEqual(im.format, "XPM")
|
||||||
|
|
||||||
# large error due to quantization->44 colors.
|
# large error due to quantization->44 colors.
|
||||||
self.assert_image_similar(im.convert('RGB'), hopper('RGB'), 60)
|
self.assert_image_similar(im.convert("RGB"), hopper("RGB"), 60)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, XpmImagePlugin.XpmImageFile, invalid_file)
|
||||||
XpmImagePlugin.XpmImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_load_read(self):
|
def test_load_read(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hopper.p7"
|
||||||
|
|
||||||
|
|
||||||
class TestFileXVThumb(PillowTestCase):
|
class TestFileXVThumb(PillowTestCase):
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Act
|
# Act
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
@ -24,13 +23,13 @@ class TestFileXVThumb(PillowTestCase):
|
||||||
bad_file = "Tests/images/hopper_bad.p7"
|
bad_file = "Tests/images/hopper_bad.p7"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(SyntaxError, XVThumbImagePlugin.XVThumbImageFile, bad_file)
|
||||||
XVThumbImagePlugin.XVThumbImageFile, bad_file)
|
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(SyntaxError,
|
self.assertRaises(
|
||||||
XVThumbImagePlugin.XVThumbImageFile, invalid_file)
|
SyntaxError, XVThumbImagePlugin.XVThumbImageFile, invalid_file
|
||||||
|
)
|
||||||
|
|
|
@ -6,7 +6,6 @@ filename = "Tests/images/courB08.bdf"
|
||||||
|
|
||||||
|
|
||||||
class TestFontBdf(PillowTestCase):
|
class TestFontBdf(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
with open(filename, "rb") as test_file:
|
with open(filename, "rb") as test_file:
|
||||||
|
|
|
@ -4,22 +4,24 @@ import sys
|
||||||
from PIL import Image, features, ImageDraw, ImageFont
|
from PIL import Image, features, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
class TestTTypeFontLeak(PillowLeakTestCase):
|
class TestTTypeFontLeak(PillowLeakTestCase):
|
||||||
# fails at iteration 3 in master
|
# fails at iteration 3 in master
|
||||||
iterations = 10
|
iterations = 10
|
||||||
mem_limit = 4096 # k
|
mem_limit = 4096 # k
|
||||||
|
|
||||||
def _test_font(self, font):
|
def _test_font(self, font):
|
||||||
im = Image.new('RGB', (255, 255), 'white')
|
im = Image.new("RGB", (255, 255), "white")
|
||||||
draw = ImageDraw.ImageDraw(im)
|
draw = ImageDraw.ImageDraw(im)
|
||||||
self._test_leak(lambda: draw.text((0, 0), "some text "*1024, # ~10k
|
self._test_leak(
|
||||||
font=font, fill="black"))
|
lambda: draw.text(
|
||||||
|
(0, 0), "some text " * 1024, font=font, fill="black" # ~10k
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@unittest.skipIf(not features.check('freetype2'),
|
@unittest.skipIf(not features.check("freetype2"), "Test requires freetype2")
|
||||||
"Test requires freetype2")
|
|
||||||
def test_leak(self):
|
def test_leak(self):
|
||||||
ttype = ImageFont.truetype('Tests/fonts/FreeMono.ttf', 20)
|
ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20)
|
||||||
self._test_font(ttype)
|
self._test_font(ttype)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ message = "hello, world"
|
||||||
|
|
||||||
|
|
||||||
class TestFontPcf(PillowTestCase):
|
class TestFontPcf(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
|
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
|
||||||
self.skipTest("zlib support not available")
|
self.skipTest("zlib support not available")
|
||||||
|
@ -25,15 +24,15 @@ class TestFontPcf(PillowTestCase):
|
||||||
self.assertEqual(len([_f for _f in font.glyph if _f]), 223)
|
self.assertEqual(len([_f for _f in font.glyph if _f]), 223)
|
||||||
|
|
||||||
tempname = self.tempfile("temp.pil")
|
tempname = self.tempfile("temp.pil")
|
||||||
self.addCleanup(self.delete_tempfile, tempname[:-4]+'.pbm')
|
self.addCleanup(self.delete_tempfile, tempname[:-4] + ".pbm")
|
||||||
font.save(tempname)
|
font.save(tempname)
|
||||||
|
|
||||||
with Image.open(tempname.replace('.pil', '.pbm')) as loaded:
|
with Image.open(tempname.replace(".pil", ".pbm")) as loaded:
|
||||||
with Image.open('Tests/fonts/10x20.pbm') as target:
|
with Image.open("Tests/fonts/10x20.pbm") as target:
|
||||||
self.assert_image_equal(loaded, target)
|
self.assert_image_equal(loaded, target)
|
||||||
|
|
||||||
with open(tempname, 'rb') as f_loaded:
|
with open(tempname, "rb") as f_loaded:
|
||||||
with open('Tests/fonts/10x20.pil', 'rb') as f_target:
|
with open("Tests/fonts/10x20.pil", "rb") as f_target:
|
||||||
self.assertEqual(f_loaded.read(), f_target.read())
|
self.assertEqual(f_loaded.read(), f_target.read())
|
||||||
return tempname
|
return tempname
|
||||||
|
|
||||||
|
@ -49,8 +48,8 @@ class TestFontPcf(PillowTestCase):
|
||||||
font = ImageFont.load(tempname)
|
font = ImageFont.load(tempname)
|
||||||
im = Image.new("L", (130, 30), "white")
|
im = Image.new("L", (130, 30), "white")
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
draw.text((0, 0), message, 'black', font=font)
|
draw.text((0, 0), message, "black", font=font)
|
||||||
with Image.open('Tests/images/test_draw_pbm_target.png') as target:
|
with Image.open("Tests/images/test_draw_pbm_target.png") as target:
|
||||||
self.assert_image_similar(im, target, 0)
|
self.assert_image_similar(im, target, 0)
|
||||||
|
|
||||||
def test_textsize(self):
|
def test_textsize(self):
|
||||||
|
@ -61,8 +60,8 @@ class TestFontPcf(PillowTestCase):
|
||||||
self.assertEqual(dy, 20)
|
self.assertEqual(dy, 20)
|
||||||
self.assertIn(dx, (0, 10))
|
self.assertIn(dx, (0, 10))
|
||||||
for l in range(len(message)):
|
for l in range(len(message)):
|
||||||
msg = message[:l+1]
|
msg = message[: l + 1]
|
||||||
self.assertEqual(font.getsize(msg), (len(msg)*10, 20))
|
self.assertEqual(font.getsize(msg), (len(msg) * 10, 20))
|
||||||
|
|
||||||
def _test_high_characters(self, message):
|
def _test_high_characters(self, message):
|
||||||
tempname = self.save_font()
|
tempname = self.save_font()
|
||||||
|
@ -70,12 +69,12 @@ class TestFontPcf(PillowTestCase):
|
||||||
im = Image.new("L", (750, 30), "white")
|
im = Image.new("L", (750, 30), "white")
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
draw.text((0, 0), message, "black", font=font)
|
draw.text((0, 0), message, "black", font=font)
|
||||||
with Image.open('Tests/images/high_ascii_chars.png') as target:
|
with Image.open("Tests/images/high_ascii_chars.png") as target:
|
||||||
self.assert_image_similar(im, target, 0)
|
self.assert_image_similar(im, target, 0)
|
||||||
|
|
||||||
def test_high_characters(self):
|
def test_high_characters(self):
|
||||||
message = "".join(chr(i+1) for i in range(140, 232))
|
message = "".join(chr(i + 1) for i in range(140, 232))
|
||||||
self._test_high_characters(message)
|
self._test_high_characters(message)
|
||||||
# accept bytes instances in Py3.
|
# accept bytes instances in Py3.
|
||||||
if py3:
|
if py3:
|
||||||
self._test_high_characters(message.encode('latin1'))
|
self._test_high_characters(message.encode("latin1"))
|
||||||
|
|
|
@ -8,19 +8,18 @@ import itertools
|
||||||
|
|
||||||
|
|
||||||
class TestFormatHSV(PillowTestCase):
|
class TestFormatHSV(PillowTestCase):
|
||||||
|
|
||||||
def int_to_float(self, i):
|
def int_to_float(self, i):
|
||||||
return float(i)/255.0
|
return float(i) / 255.0
|
||||||
|
|
||||||
def str_to_float(self, i):
|
def str_to_float(self, i):
|
||||||
return float(ord(i))/255.0
|
return float(ord(i)) / 255.0
|
||||||
|
|
||||||
def tuple_to_ints(self, tp):
|
def tuple_to_ints(self, tp):
|
||||||
x, y, z = tp
|
x, y, z = tp
|
||||||
return int(x*255.0), int(y*255.0), int(z*255.0)
|
return int(x * 255.0), int(y * 255.0), int(z * 255.0)
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
Image.new('HSV', (100, 100))
|
Image.new("HSV", (100, 100))
|
||||||
|
|
||||||
def wedge(self):
|
def wedge(self):
|
||||||
w = Image._wedge()
|
w = Image._wedge()
|
||||||
|
@ -28,7 +27,7 @@ class TestFormatHSV(PillowTestCase):
|
||||||
|
|
||||||
(px, h) = w.size
|
(px, h) = w.size
|
||||||
|
|
||||||
r = Image.new('L', (px*3, h))
|
r = Image.new("L", (px * 3, h))
|
||||||
g = r.copy()
|
g = r.copy()
|
||||||
b = r.copy()
|
b = r.copy()
|
||||||
|
|
||||||
|
@ -36,12 +35,12 @@ class TestFormatHSV(PillowTestCase):
|
||||||
r.paste(w90, (px, 0))
|
r.paste(w90, (px, 0))
|
||||||
|
|
||||||
g.paste(w90, (0, 0))
|
g.paste(w90, (0, 0))
|
||||||
g.paste(w, (2*px, 0))
|
g.paste(w, (2 * px, 0))
|
||||||
|
|
||||||
b.paste(w, (px, 0))
|
b.paste(w, (px, 0))
|
||||||
b.paste(w90, (2*px, 0))
|
b.paste(w90, (2 * px, 0))
|
||||||
|
|
||||||
img = Image.merge('RGB', (r, g, b))
|
img = Image.merge("RGB", (r, g, b))
|
||||||
|
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
@ -55,77 +54,101 @@ class TestFormatHSV(PillowTestCase):
|
||||||
else:
|
else:
|
||||||
conv_func = self.str_to_float
|
conv_func = self.str_to_float
|
||||||
|
|
||||||
if hasattr(itertools, 'izip'):
|
if hasattr(itertools, "izip"):
|
||||||
iter_helper = itertools.izip
|
iter_helper = itertools.izip
|
||||||
else:
|
else:
|
||||||
iter_helper = itertools.zip_longest
|
iter_helper = itertools.zip_longest
|
||||||
|
|
||||||
converted = [self.tuple_to_ints(func(conv_func(_r), conv_func(_g),
|
converted = [
|
||||||
conv_func(_b)))
|
self.tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
|
||||||
for (_r, _g, _b) in iter_helper(r.tobytes(), g.tobytes(),
|
for (_r, _g, _b) in iter_helper(r.tobytes(), g.tobytes(), b.tobytes())
|
||||||
b.tobytes())]
|
]
|
||||||
|
|
||||||
if py3:
|
if py3:
|
||||||
new_bytes = b''.join(bytes(chr(h)+chr(s)+chr(v), 'latin-1') for (
|
new_bytes = b"".join(
|
||||||
h, s, v) in converted)
|
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
new_bytes = b''.join(chr(h)+chr(s)+chr(v) for (
|
new_bytes = b"".join(chr(h) + chr(s) + chr(v) for (h, s, v) in converted)
|
||||||
h, s, v) in converted)
|
|
||||||
|
|
||||||
hsv = Image.frombytes(mode, r.size, new_bytes)
|
hsv = Image.frombytes(mode, r.size, new_bytes)
|
||||||
|
|
||||||
return hsv
|
return hsv
|
||||||
|
|
||||||
def to_hsv_colorsys(self, im):
|
def to_hsv_colorsys(self, im):
|
||||||
return self.to_xxx_colorsys(im, colorsys.rgb_to_hsv, 'HSV')
|
return self.to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
|
||||||
|
|
||||||
def to_rgb_colorsys(self, im):
|
def to_rgb_colorsys(self, im):
|
||||||
return self.to_xxx_colorsys(im, colorsys.hsv_to_rgb, 'RGB')
|
return self.to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
|
||||||
|
|
||||||
def test_wedge(self):
|
def test_wedge(self):
|
||||||
src = self.wedge().resize((3*32, 32), Image.BILINEAR)
|
src = self.wedge().resize((3 * 32, 32), Image.BILINEAR)
|
||||||
im = src.convert('HSV')
|
im = src.convert("HSV")
|
||||||
comparable = self.to_hsv_colorsys(src)
|
comparable = self.to_hsv_colorsys(src)
|
||||||
|
|
||||||
self.assert_image_similar(im.getchannel(0), comparable.getchannel(0),
|
self.assert_image_similar(
|
||||||
1, "Hue conversion is wrong")
|
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
|
||||||
self.assert_image_similar(im.getchannel(1), comparable.getchannel(1),
|
)
|
||||||
1, "Saturation conversion is wrong")
|
self.assert_image_similar(
|
||||||
self.assert_image_similar(im.getchannel(2), comparable.getchannel(2),
|
im.getchannel(1),
|
||||||
1, "Value conversion is wrong")
|
comparable.getchannel(1),
|
||||||
|
1,
|
||||||
|
"Saturation conversion is wrong",
|
||||||
|
)
|
||||||
|
self.assert_image_similar(
|
||||||
|
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
|
||||||
|
)
|
||||||
|
|
||||||
comparable = src
|
comparable = src
|
||||||
im = im.convert('RGB')
|
im = im.convert("RGB")
|
||||||
|
|
||||||
self.assert_image_similar(im.getchannel(0), comparable.getchannel(0),
|
self.assert_image_similar(
|
||||||
3, "R conversion is wrong")
|
im.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong"
|
||||||
self.assert_image_similar(im.getchannel(1), comparable.getchannel(1),
|
)
|
||||||
3, "G conversion is wrong")
|
self.assert_image_similar(
|
||||||
self.assert_image_similar(im.getchannel(2), comparable.getchannel(2),
|
im.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong"
|
||||||
3, "B conversion is wrong")
|
)
|
||||||
|
self.assert_image_similar(
|
||||||
|
im.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong"
|
||||||
|
)
|
||||||
|
|
||||||
def test_convert(self):
|
def test_convert(self):
|
||||||
im = hopper('RGB').convert('HSV')
|
im = hopper("RGB").convert("HSV")
|
||||||
comparable = self.to_hsv_colorsys(hopper('RGB'))
|
comparable = self.to_hsv_colorsys(hopper("RGB"))
|
||||||
|
|
||||||
self.assert_image_similar(im.getchannel(0), comparable.getchannel(0),
|
self.assert_image_similar(
|
||||||
1, "Hue conversion is wrong")
|
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
|
||||||
self.assert_image_similar(im.getchannel(1), comparable.getchannel(1),
|
)
|
||||||
1, "Saturation conversion is wrong")
|
self.assert_image_similar(
|
||||||
self.assert_image_similar(im.getchannel(2), comparable.getchannel(2),
|
im.getchannel(1),
|
||||||
1, "Value conversion is wrong")
|
comparable.getchannel(1),
|
||||||
|
1,
|
||||||
|
"Saturation conversion is wrong",
|
||||||
|
)
|
||||||
|
self.assert_image_similar(
|
||||||
|
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
|
||||||
|
)
|
||||||
|
|
||||||
def test_hsv_to_rgb(self):
|
def test_hsv_to_rgb(self):
|
||||||
comparable = self.to_hsv_colorsys(hopper('RGB'))
|
comparable = self.to_hsv_colorsys(hopper("RGB"))
|
||||||
converted = comparable.convert('RGB')
|
converted = comparable.convert("RGB")
|
||||||
comparable = self.to_rgb_colorsys(comparable)
|
comparable = self.to_rgb_colorsys(comparable)
|
||||||
|
|
||||||
self.assert_image_similar(converted.getchannel(0),
|
self.assert_image_similar(
|
||||||
comparable.getchannel(0),
|
converted.getchannel(0),
|
||||||
3, "R conversion is wrong")
|
comparable.getchannel(0),
|
||||||
self.assert_image_similar(converted.getchannel(1),
|
3,
|
||||||
comparable.getchannel(1),
|
"R conversion is wrong",
|
||||||
3, "G conversion is wrong")
|
)
|
||||||
self.assert_image_similar(converted.getchannel(2),
|
self.assert_image_similar(
|
||||||
comparable.getchannel(2),
|
converted.getchannel(1),
|
||||||
3, "B conversion is wrong")
|
comparable.getchannel(1),
|
||||||
|
3,
|
||||||
|
"G conversion is wrong",
|
||||||
|
)
|
||||||
|
self.assert_image_similar(
|
||||||
|
converted.getchannel(2),
|
||||||
|
comparable.getchannel(2),
|
||||||
|
3,
|
||||||
|
"B conversion is wrong",
|
||||||
|
)
|
||||||
|
|
|
@ -4,15 +4,14 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestFormatLab(PillowTestCase):
|
class TestFormatLab(PillowTestCase):
|
||||||
|
|
||||||
def test_white(self):
|
def test_white(self):
|
||||||
i = Image.open('Tests/images/lab.tif')
|
i = Image.open("Tests/images/lab.tif")
|
||||||
|
|
||||||
i.load()
|
i.load()
|
||||||
|
|
||||||
self.assertEqual(i.mode, 'LAB')
|
self.assertEqual(i.mode, "LAB")
|
||||||
|
|
||||||
self.assertEqual(i.getbands(), ('L', 'A', 'B'))
|
self.assertEqual(i.getbands(), ("L", "A", "B"))
|
||||||
|
|
||||||
k = i.getpixel((0, 0))
|
k = i.getpixel((0, 0))
|
||||||
self.assertEqual(k, (255, 128, 128))
|
self.assertEqual(k, (255, 128, 128))
|
||||||
|
@ -21,14 +20,14 @@ class TestFormatLab(PillowTestCase):
|
||||||
a = i.getdata(1)
|
a = i.getdata(1)
|
||||||
b = i.getdata(2)
|
b = i.getdata(2)
|
||||||
|
|
||||||
self.assertEqual(list(L), [255]*100)
|
self.assertEqual(list(L), [255] * 100)
|
||||||
self.assertEqual(list(a), [128]*100)
|
self.assertEqual(list(a), [128] * 100)
|
||||||
self.assertEqual(list(b), [128]*100)
|
self.assertEqual(list(b), [128] * 100)
|
||||||
|
|
||||||
def test_green(self):
|
def test_green(self):
|
||||||
# l= 50 (/100), a = -100 (-128 .. 128) b=0 in PS
|
# l= 50 (/100), a = -100 (-128 .. 128) b=0 in PS
|
||||||
# == RGB: 0, 152, 117
|
# == RGB: 0, 152, 117
|
||||||
i = Image.open('Tests/images/lab-green.tif')
|
i = Image.open("Tests/images/lab-green.tif")
|
||||||
|
|
||||||
k = i.getpixel((0, 0))
|
k = i.getpixel((0, 0))
|
||||||
self.assertEqual(k, (128, 28, 128))
|
self.assertEqual(k, (128, 28, 128))
|
||||||
|
@ -36,7 +35,7 @@ class TestFormatLab(PillowTestCase):
|
||||||
def test_red(self):
|
def test_red(self):
|
||||||
# l= 50 (/100), a = 100 (-128 .. 128) b=0 in PS
|
# l= 50 (/100), a = 100 (-128 .. 128) b=0 in PS
|
||||||
# == RGB: 255, 0, 124
|
# == RGB: 255, 0, 124
|
||||||
i = Image.open('Tests/images/lab-red.tif')
|
i = Image.open("Tests/images/lab-red.tif")
|
||||||
|
|
||||||
k = i.getpixel((0, 0))
|
k = i.getpixel((0, 0))
|
||||||
self.assertEqual(k, (128, 228, 128))
|
self.assertEqual(k, (128, 228, 128))
|
||||||
|
|
|
@ -8,37 +8,54 @@ import shutil
|
||||||
|
|
||||||
|
|
||||||
class TestImage(PillowTestCase):
|
class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_image_modes_success(self):
|
def test_image_modes_success(self):
|
||||||
for mode in [
|
for mode in [
|
||||||
'1', 'P', 'PA',
|
"1",
|
||||||
'L', 'LA', 'La',
|
"P",
|
||||||
'F', 'I', 'I;16', 'I;16L', 'I;16B', 'I;16N',
|
"PA",
|
||||||
'RGB', 'RGBX', 'RGBA', 'RGBa',
|
"L",
|
||||||
'CMYK', 'YCbCr', 'LAB', 'HSV',
|
"LA",
|
||||||
|
"La",
|
||||||
|
"F",
|
||||||
|
"I",
|
||||||
|
"I;16",
|
||||||
|
"I;16L",
|
||||||
|
"I;16B",
|
||||||
|
"I;16N",
|
||||||
|
"RGB",
|
||||||
|
"RGBX",
|
||||||
|
"RGBA",
|
||||||
|
"RGBa",
|
||||||
|
"CMYK",
|
||||||
|
"YCbCr",
|
||||||
|
"LAB",
|
||||||
|
"HSV",
|
||||||
]:
|
]:
|
||||||
Image.new(mode, (1, 1))
|
Image.new(mode, (1, 1))
|
||||||
|
|
||||||
def test_image_modes_fail(self):
|
def test_image_modes_fail(self):
|
||||||
for mode in [
|
for mode in [
|
||||||
'', 'bad', 'very very long',
|
"",
|
||||||
'BGR;15', 'BGR;16', 'BGR;24', 'BGR;32'
|
"bad",
|
||||||
|
"very very long",
|
||||||
|
"BGR;15",
|
||||||
|
"BGR;16",
|
||||||
|
"BGR;24",
|
||||||
|
"BGR;32",
|
||||||
]:
|
]:
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
Image.new(mode, (1, 1))
|
Image.new(mode, (1, 1))
|
||||||
self.assertEqual(str(e.exception), 'unrecognized image mode')
|
self.assertEqual(str(e.exception), "unrecognized image mode")
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
im = Image.new("L", (100, 100))
|
im = Image.new("L", (100, 100))
|
||||||
self.assertEqual(
|
self.assertEqual(repr(im)[:45], "<PIL.Image.Image image mode=L size=100x100 at")
|
||||||
repr(im)[:45], "<PIL.Image.Image image mode=L size=100x100 at")
|
|
||||||
self.assertEqual(im.mode, "L")
|
self.assertEqual(im.mode, "L")
|
||||||
self.assertEqual(im.size, (100, 100))
|
self.assertEqual(im.size, (100, 100))
|
||||||
|
|
||||||
im = Image.new("RGB", (100, 100))
|
im = Image.new("RGB", (100, 100))
|
||||||
self.assertEqual(
|
self.assertEqual(repr(im)[:45], "<PIL.Image.Image image mode=RGB size=100x100 ")
|
||||||
repr(im)[:45], "<PIL.Image.Image image mode=RGB size=100x100 ")
|
|
||||||
self.assertEqual(im.mode, "RGB")
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (100, 100))
|
self.assertEqual(im.size, (100, 100))
|
||||||
|
|
||||||
|
@ -64,10 +81,12 @@ class TestImage(PillowTestCase):
|
||||||
def test_invalid_image(self):
|
def test_invalid_image(self):
|
||||||
if py3:
|
if py3:
|
||||||
import io
|
import io
|
||||||
im = io.BytesIO(b'')
|
|
||||||
|
im = io.BytesIO(b"")
|
||||||
else:
|
else:
|
||||||
import StringIO
|
import StringIO
|
||||||
im = StringIO.StringIO('')
|
|
||||||
|
im = StringIO.StringIO("")
|
||||||
self.assertRaises(IOError, Image.open, im)
|
self.assertRaises(IOError, Image.open, im)
|
||||||
|
|
||||||
def test_bad_mode(self):
|
def test_bad_mode(self):
|
||||||
|
@ -76,6 +95,7 @@ class TestImage(PillowTestCase):
|
||||||
@unittest.skipUnless(Image.HAS_PATHLIB, "requires pathlib/pathlib2")
|
@unittest.skipUnless(Image.HAS_PATHLIB, "requires pathlib/pathlib2")
|
||||||
def test_pathlib(self):
|
def test_pathlib(self):
|
||||||
from PIL.Image import Path
|
from PIL.Image import Path
|
||||||
|
|
||||||
im = Image.open(Path("Tests/images/multipage-mmap.tiff"))
|
im = Image.open(Path("Tests/images/multipage-mmap.tiff"))
|
||||||
self.assertEqual(im.mode, "P")
|
self.assertEqual(im.mode, "P")
|
||||||
self.assertEqual(im.size, (10, 10))
|
self.assertEqual(im.size, (10, 10))
|
||||||
|
@ -95,6 +115,7 @@ class TestImage(PillowTestCase):
|
||||||
class FP(object):
|
class FP(object):
|
||||||
def write(a, b):
|
def write(a, b):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
fp = FP()
|
fp = FP()
|
||||||
fp.name = temp_file
|
fp.name = temp_file
|
||||||
|
|
||||||
|
@ -105,9 +126,10 @@ class TestImage(PillowTestCase):
|
||||||
# see #1460, pathlib support breaks tempfile.TemporaryFile on py27
|
# see #1460, pathlib support breaks tempfile.TemporaryFile on py27
|
||||||
# Will error out on save on 3.0.0
|
# Will error out on save on 3.0.0
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
im = hopper()
|
im = hopper()
|
||||||
with tempfile.TemporaryFile() as fp:
|
with tempfile.TemporaryFile() as fp:
|
||||||
im.save(fp, 'JPEG')
|
im.save(fp, "JPEG")
|
||||||
fp.seek(0)
|
fp.seek(0)
|
||||||
reloaded = Image.open(fp)
|
reloaded = Image.open(fp)
|
||||||
self.assert_image_similar(im, reloaded, 20)
|
self.assert_image_similar(im, reloaded, 20)
|
||||||
|
@ -127,8 +149,9 @@ class TestImage(PillowTestCase):
|
||||||
im.paste(0, (0, 0, 100, 100))
|
im.paste(0, (0, 0, 100, 100))
|
||||||
self.assertFalse(im.readonly)
|
self.assertFalse(im.readonly)
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith('win32'),
|
@unittest.skipIf(
|
||||||
"Test requires opening tempfile twice")
|
sys.platform.startswith("win32"), "Test requires opening tempfile twice"
|
||||||
|
)
|
||||||
def test_readonly_save(self):
|
def test_readonly_save(self):
|
||||||
temp_file = self.tempfile("temp.bmp")
|
temp_file = self.tempfile("temp.bmp")
|
||||||
shutil.copy("Tests/images/rgb32bf-rgba.bmp", temp_file)
|
shutil.copy("Tests/images/rgb32bf-rgba.bmp", temp_file)
|
||||||
|
@ -149,7 +172,7 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_comparison_with_other_type(self):
|
def test_comparison_with_other_type(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
item = Image.new('RGB', (25, 25), '#000')
|
item = Image.new("RGB", (25, 25), "#000")
|
||||||
num = 12
|
num = 12
|
||||||
|
|
||||||
# Act/Assert
|
# Act/Assert
|
||||||
|
@ -167,8 +190,8 @@ class TestImage(PillowTestCase):
|
||||||
im = im._expand(xmargin)
|
im = im._expand(xmargin)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size[0], orig_size[0] + 2*xmargin)
|
self.assertEqual(im.size[0], orig_size[0] + 2 * xmargin)
|
||||||
self.assertEqual(im.size[1], orig_size[1] + 2*xmargin)
|
self.assertEqual(im.size[1], orig_size[1] + 2 * xmargin)
|
||||||
|
|
||||||
def test_expand_xy(self):
|
def test_expand_xy(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -181,32 +204,32 @@ class TestImage(PillowTestCase):
|
||||||
im = im._expand(xmargin, ymargin)
|
im = im._expand(xmargin, ymargin)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size[0], orig_size[0] + 2*xmargin)
|
self.assertEqual(im.size[0], orig_size[0] + 2 * xmargin)
|
||||||
self.assertEqual(im.size[1], orig_size[1] + 2*ymargin)
|
self.assertEqual(im.size[1], orig_size[1] + 2 * ymargin)
|
||||||
|
|
||||||
def test_getbands(self):
|
def test_getbands(self):
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(hopper('RGB').getbands(), ('R', 'G', 'B'))
|
self.assertEqual(hopper("RGB").getbands(), ("R", "G", "B"))
|
||||||
self.assertEqual(hopper('YCbCr').getbands(), ('Y', 'Cb', 'Cr'))
|
self.assertEqual(hopper("YCbCr").getbands(), ("Y", "Cb", "Cr"))
|
||||||
|
|
||||||
def test_getchannel_wrong_params(self):
|
def test_getchannel_wrong_params(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
||||||
self.assertRaises(ValueError, im.getchannel, -1)
|
self.assertRaises(ValueError, im.getchannel, -1)
|
||||||
self.assertRaises(ValueError, im.getchannel, 3)
|
self.assertRaises(ValueError, im.getchannel, 3)
|
||||||
self.assertRaises(ValueError, im.getchannel, 'Z')
|
self.assertRaises(ValueError, im.getchannel, "Z")
|
||||||
self.assertRaises(ValueError, im.getchannel, '1')
|
self.assertRaises(ValueError, im.getchannel, "1")
|
||||||
|
|
||||||
def test_getchannel(self):
|
def test_getchannel(self):
|
||||||
im = hopper('YCbCr')
|
im = hopper("YCbCr")
|
||||||
Y, Cb, Cr = im.split()
|
Y, Cb, Cr = im.split()
|
||||||
|
|
||||||
self.assert_image_equal(Y, im.getchannel(0))
|
self.assert_image_equal(Y, im.getchannel(0))
|
||||||
self.assert_image_equal(Y, im.getchannel('Y'))
|
self.assert_image_equal(Y, im.getchannel("Y"))
|
||||||
self.assert_image_equal(Cb, im.getchannel(1))
|
self.assert_image_equal(Cb, im.getchannel(1))
|
||||||
self.assert_image_equal(Cb, im.getchannel('Cb'))
|
self.assert_image_equal(Cb, im.getchannel("Cb"))
|
||||||
self.assert_image_equal(Cr, im.getchannel(2))
|
self.assert_image_equal(Cr, im.getchannel(2))
|
||||||
self.assert_image_equal(Cr, im.getchannel('Cr'))
|
self.assert_image_equal(Cr, im.getchannel("Cr"))
|
||||||
|
|
||||||
def test_getbbox(self):
|
def test_getbbox(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -220,8 +243,8 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_ne(self):
|
def test_ne(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im1 = Image.new('RGB', (25, 25), 'black')
|
im1 = Image.new("RGB", (25, 25), "black")
|
||||||
im2 = Image.new('RGB', (25, 25), 'white')
|
im2 = Image.new("RGB", (25, 25), "white")
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertNotEqual(im1, im2)
|
self.assertNotEqual(im1, im2)
|
||||||
|
@ -231,20 +254,23 @@ class TestImage(PillowTestCase):
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ImageDraw
|
from PIL import ImageDraw
|
||||||
|
|
||||||
expected_colors = sorted([
|
expected_colors = sorted(
|
||||||
(1122, (128, 127, 0, 255)),
|
[
|
||||||
(1089, (0, 255, 0, 255)),
|
(1122, (128, 127, 0, 255)),
|
||||||
(3300, (255, 0, 0, 255)),
|
(1089, (0, 255, 0, 255)),
|
||||||
(1156, (170, 85, 0, 192)),
|
(3300, (255, 0, 0, 255)),
|
||||||
(1122, (0, 255, 0, 128)),
|
(1156, (170, 85, 0, 192)),
|
||||||
(1122, (255, 0, 0, 128)),
|
(1122, (0, 255, 0, 128)),
|
||||||
(1089, (0, 255, 0, 0))])
|
(1122, (255, 0, 0, 128)),
|
||||||
|
(1089, (0, 255, 0, 0)),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
dst = Image.new('RGBA', size=(100, 100), color=(0, 255, 0, 255))
|
dst = Image.new("RGBA", size=(100, 100), color=(0, 255, 0, 255))
|
||||||
draw = ImageDraw.Draw(dst)
|
draw = ImageDraw.Draw(dst)
|
||||||
draw.rectangle((0, 33, 100, 66), fill=(0, 255, 0, 128))
|
draw.rectangle((0, 33, 100, 66), fill=(0, 255, 0, 128))
|
||||||
draw.rectangle((0, 67, 100, 100), fill=(0, 255, 0, 0))
|
draw.rectangle((0, 67, 100, 100), fill=(0, 255, 0, 0))
|
||||||
src = Image.new('RGBA', size=(100, 100), color=(255, 0, 0, 255))
|
src = Image.new("RGBA", size=(100, 100), color=(255, 0, 0, 255))
|
||||||
draw = ImageDraw.Draw(src)
|
draw = ImageDraw.Draw(src)
|
||||||
draw.rectangle((33, 0, 66, 100), fill=(255, 0, 0, 128))
|
draw.rectangle((33, 0, 66, 100), fill=(255, 0, 0, 128))
|
||||||
draw.rectangle((67, 0, 100, 100), fill=(255, 0, 0, 0))
|
draw.rectangle((67, 0, 100, 100), fill=(255, 0, 0, 0))
|
||||||
|
@ -257,10 +283,10 @@ class TestImage(PillowTestCase):
|
||||||
self.assertEqual(img_colors, expected_colors)
|
self.assertEqual(img_colors, expected_colors)
|
||||||
|
|
||||||
def test_alpha_inplace(self):
|
def test_alpha_inplace(self):
|
||||||
src = Image.new('RGBA', (128, 128), 'blue')
|
src = Image.new("RGBA", (128, 128), "blue")
|
||||||
|
|
||||||
over = Image.new('RGBA', (128, 128), 'red')
|
over = Image.new("RGBA", (128, 128), "red")
|
||||||
mask = hopper('L')
|
mask = hopper("L")
|
||||||
over.putalpha(mask)
|
over.putalpha(mask)
|
||||||
|
|
||||||
target = Image.alpha_composite(src, over)
|
target = Image.alpha_composite(src, over)
|
||||||
|
@ -273,41 +299,36 @@ class TestImage(PillowTestCase):
|
||||||
# with offset down to right
|
# with offset down to right
|
||||||
offset = src.copy()
|
offset = src.copy()
|
||||||
offset.alpha_composite(over, (64, 64))
|
offset.alpha_composite(over, (64, 64))
|
||||||
self.assert_image_equal(offset.crop((64, 64, 127, 127)),
|
self.assert_image_equal(
|
||||||
target.crop((0, 0, 63, 63)))
|
offset.crop((64, 64, 127, 127)), target.crop((0, 0, 63, 63))
|
||||||
|
)
|
||||||
self.assertEqual(offset.size, (128, 128))
|
self.assertEqual(offset.size, (128, 128))
|
||||||
|
|
||||||
# offset and crop
|
# offset and crop
|
||||||
box = src.copy()
|
box = src.copy()
|
||||||
box.alpha_composite(over, (64, 64), (0, 0, 32, 32))
|
box.alpha_composite(over, (64, 64), (0, 0, 32, 32))
|
||||||
self.assert_image_equal(box.crop((64, 64, 96, 96)),
|
self.assert_image_equal(box.crop((64, 64, 96, 96)), target.crop((0, 0, 32, 32)))
|
||||||
target.crop((0, 0, 32, 32)))
|
self.assert_image_equal(box.crop((96, 96, 128, 128)), src.crop((0, 0, 32, 32)))
|
||||||
self.assert_image_equal(box.crop((96, 96, 128, 128)),
|
|
||||||
src.crop((0, 0, 32, 32)))
|
|
||||||
self.assertEqual(box.size, (128, 128))
|
self.assertEqual(box.size, (128, 128))
|
||||||
|
|
||||||
# source point
|
# source point
|
||||||
source = src.copy()
|
source = src.copy()
|
||||||
source.alpha_composite(over, (32, 32), (32, 32, 96, 96))
|
source.alpha_composite(over, (32, 32), (32, 32, 96, 96))
|
||||||
|
|
||||||
self.assert_image_equal(source.crop((32, 32, 96, 96)),
|
self.assert_image_equal(
|
||||||
target.crop((32, 32, 96, 96)))
|
source.crop((32, 32, 96, 96)), target.crop((32, 32, 96, 96))
|
||||||
|
)
|
||||||
self.assertEqual(source.size, (128, 128))
|
self.assertEqual(source.size, (128, 128))
|
||||||
|
|
||||||
# errors
|
# errors
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, source.alpha_composite, over, "invalid source")
|
||||||
source.alpha_composite, over, "invalid source")
|
self.assertRaises(
|
||||||
self.assertRaises(ValueError,
|
ValueError, source.alpha_composite, over, (0, 0), "invalid destination"
|
||||||
source.alpha_composite, over, (0, 0),
|
)
|
||||||
"invalid destination")
|
self.assertRaises(ValueError, source.alpha_composite, over, 0)
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, source.alpha_composite, over, (0, 0), 0)
|
||||||
source.alpha_composite, over, 0)
|
self.assertRaises(ValueError, source.alpha_composite, over, (0, -1))
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, source.alpha_composite, over, (0, 0), (0, -1))
|
||||||
source.alpha_composite, over, (0, 0), 0)
|
|
||||||
self.assertRaises(ValueError,
|
|
||||||
source.alpha_composite, over, (0, -1))
|
|
||||||
self.assertRaises(ValueError,
|
|
||||||
source.alpha_composite, over, (0, 0), (0, -1))
|
|
||||||
|
|
||||||
def test_registered_extensions_uninitialized(self):
|
def test_registered_extensions_uninitialized(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -328,14 +349,14 @@ class TestImage(PillowTestCase):
|
||||||
def test_registered_extensions(self):
|
def test_registered_extensions(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
# Open an image to trigger plugin registration
|
# Open an image to trigger plugin registration
|
||||||
Image.open('Tests/images/rgb.jpg')
|
Image.open("Tests/images/rgb.jpg")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
extensions = Image.registered_extensions()
|
extensions = Image.registered_extensions()
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(extensions)
|
self.assertTrue(extensions)
|
||||||
for ext in ['.cur', '.icns', '.tif', '.tiff']:
|
for ext in [".cur", ".icns", ".tif", ".tiff"]:
|
||||||
self.assertIn(ext, extensions)
|
self.assertIn(ext, extensions)
|
||||||
|
|
||||||
def test_effect_mandelbrot(self):
|
def test_effect_mandelbrot(self):
|
||||||
|
@ -349,7 +370,7 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (512, 512))
|
self.assertEqual(im.size, (512, 512))
|
||||||
im2 = Image.open('Tests/images/effect_mandelbrot.png')
|
im2 = Image.open("Tests/images/effect_mandelbrot.png")
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
def test_effect_mandelbrot_bad_arguments(self):
|
def test_effect_mandelbrot_bad_arguments(self):
|
||||||
|
@ -361,9 +382,7 @@ class TestImage(PillowTestCase):
|
||||||
quality = 1
|
quality = 1
|
||||||
|
|
||||||
# Act/Assert
|
# Act/Assert
|
||||||
self.assertRaises(
|
self.assertRaises(ValueError, Image.effect_mandelbrot, size, extent, quality)
|
||||||
ValueError,
|
|
||||||
Image.effect_mandelbrot, size, extent, quality)
|
|
||||||
|
|
||||||
def test_effect_noise(self):
|
def test_effect_noise(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -393,32 +412,32 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
im3 = Image.open('Tests/images/effect_spread.png')
|
im3 = Image.open("Tests/images/effect_spread.png")
|
||||||
self.assert_image_similar(im2, im3, 110)
|
self.assert_image_similar(im2, im3, 110)
|
||||||
|
|
||||||
def test_check_size(self):
|
def test_check_size(self):
|
||||||
# Checking that the _check_size function throws value errors
|
# Checking that the _check_size function throws value errors
|
||||||
# when we want it to.
|
# when we want it to.
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
Image.new('RGB', 0) # not a tuple
|
Image.new("RGB", 0) # not a tuple
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
Image.new('RGB', (0,)) # Tuple too short
|
Image.new("RGB", (0,)) # Tuple too short
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
Image.new('RGB', (-1, -1)) # w,h < 0
|
Image.new("RGB", (-1, -1)) # w,h < 0
|
||||||
|
|
||||||
# this should pass with 0 sized images, #2259
|
# this should pass with 0 sized images, #2259
|
||||||
im = Image.new('L', (0, 0))
|
im = Image.new("L", (0, 0))
|
||||||
self.assertEqual(im.size, (0, 0))
|
self.assertEqual(im.size, (0, 0))
|
||||||
|
|
||||||
im = Image.new('L', (0, 100))
|
im = Image.new("L", (0, 100))
|
||||||
self.assertEqual(im.size, (0, 100))
|
self.assertEqual(im.size, (0, 100))
|
||||||
|
|
||||||
im = Image.new('L', (100, 0))
|
im = Image.new("L", (100, 0))
|
||||||
self.assertEqual(im.size, (100, 0))
|
self.assertEqual(im.size, (100, 0))
|
||||||
|
|
||||||
self.assertTrue(Image.new('RGB', (1, 1)))
|
self.assertTrue(Image.new("RGB", (1, 1)))
|
||||||
# Should pass lists too
|
# Should pass lists too
|
||||||
i = Image.new('RGB', [1, 1])
|
i = Image.new("RGB", [1, 1])
|
||||||
self.assertIsInstance(i.size, tuple)
|
self.assertIsInstance(i.size, tuple)
|
||||||
|
|
||||||
def test_storage_neg(self):
|
def test_storage_neg(self):
|
||||||
|
@ -428,7 +447,7 @@ class TestImage(PillowTestCase):
|
||||||
# Storage.c, rather than the size check above
|
# Storage.c, rather than the size check above
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
Image.core.fill('RGB', (2, -2), (0, 0, 0))
|
Image.core.fill("RGB", (2, -2), (0, 0, 0))
|
||||||
|
|
||||||
def test_offset_not_implemented(self):
|
def test_offset_not_implemented(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -445,8 +464,7 @@ class TestImage(PillowTestCase):
|
||||||
wrong_mode = "RGB"
|
wrong_mode = "RGB"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, Image.linear_gradient, wrong_mode)
|
||||||
Image.linear_gradient, wrong_mode)
|
|
||||||
|
|
||||||
def test_linear_gradient(self):
|
def test_linear_gradient(self):
|
||||||
|
|
||||||
|
@ -470,8 +488,7 @@ class TestImage(PillowTestCase):
|
||||||
wrong_mode = "RGB"
|
wrong_mode = "RGB"
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, Image.radial_gradient, wrong_mode)
|
||||||
Image.radial_gradient, wrong_mode)
|
|
||||||
|
|
||||||
def test_radial_gradient(self):
|
def test_radial_gradient(self):
|
||||||
|
|
||||||
|
@ -514,11 +531,11 @@ class TestImage(PillowTestCase):
|
||||||
def test__new(self):
|
def test__new(self):
|
||||||
from PIL import ImagePalette
|
from PIL import ImagePalette
|
||||||
|
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
im_p = hopper('P')
|
im_p = hopper("P")
|
||||||
|
|
||||||
blank_p = Image.new('P', (10, 10))
|
blank_p = Image.new("P", (10, 10))
|
||||||
blank_pa = Image.new('PA', (10, 10))
|
blank_pa = Image.new("PA", (10, 10))
|
||||||
blank_p.palette = None
|
blank_p.palette = None
|
||||||
blank_pa.palette = None
|
blank_pa.palette = None
|
||||||
|
|
||||||
|
@ -528,8 +545,7 @@ class TestImage(PillowTestCase):
|
||||||
self.assertEqual(new_im.size, im.size)
|
self.assertEqual(new_im.size, im.size)
|
||||||
self.assertEqual(new_im.info, base_image.info)
|
self.assertEqual(new_im.info, base_image.info)
|
||||||
if palette_result is not None:
|
if palette_result is not None:
|
||||||
self.assertEqual(new_im.palette.tobytes(),
|
self.assertEqual(new_im.palette.tobytes(), palette_result.tobytes())
|
||||||
palette_result.tobytes())
|
|
||||||
else:
|
else:
|
||||||
self.assertIsNone(new_im.palette)
|
self.assertIsNone(new_im.palette)
|
||||||
|
|
||||||
|
@ -540,9 +556,9 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_p_from_rgb_rgba(self):
|
def test_p_from_rgb_rgba(self):
|
||||||
for mode, color in [
|
for mode, color in [
|
||||||
("RGB", '#DDEEFF'),
|
("RGB", "#DDEEFF"),
|
||||||
("RGB", (221, 238, 255)),
|
("RGB", (221, 238, 255)),
|
||||||
("RGBA", (221, 238, 255, 255))
|
("RGBA", (221, 238, 255, 255)),
|
||||||
]:
|
]:
|
||||||
im = Image.new("P", (100, 100), color)
|
im = Image.new("P", (100, 100), color)
|
||||||
expected = Image.new(mode, (100, 100), color)
|
expected = Image.new(mode, (100, 100), color)
|
||||||
|
@ -551,7 +567,7 @@ class TestImage(PillowTestCase):
|
||||||
def test_no_resource_warning_on_save(self):
|
def test_no_resource_warning_on_save(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/835
|
# https://github.com/python-pillow/Pillow/issues/835
|
||||||
# Arrange
|
# Arrange
|
||||||
test_file = 'Tests/images/hopper.png'
|
test_file = "Tests/images/hopper.png"
|
||||||
temp_file = self.tempfile("temp.jpg")
|
temp_file = self.tempfile("temp.jpg")
|
||||||
|
|
||||||
# Act/Assert
|
# Act/Assert
|
||||||
|
@ -560,9 +576,11 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
def test_load_on_nonexclusive_multiframe(self):
|
def test_load_on_nonexclusive_multiframe(self):
|
||||||
with open("Tests/images/frozenpond.mpo", "rb") as fp:
|
with open("Tests/images/frozenpond.mpo", "rb") as fp:
|
||||||
|
|
||||||
def act(fp):
|
def act(fp):
|
||||||
im = Image.open(fp)
|
im = Image.open(fp)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
act(fp)
|
act(fp)
|
||||||
|
|
||||||
with Image.open(fp) as im:
|
with Image.open(fp) as im:
|
||||||
|
@ -582,19 +600,22 @@ def mock_encode(*args):
|
||||||
|
|
||||||
|
|
||||||
class TestRegistry(PillowTestCase):
|
class TestRegistry(PillowTestCase):
|
||||||
|
|
||||||
def test_encode_registry(self):
|
def test_encode_registry(self):
|
||||||
|
|
||||||
Image.register_encoder('MOCK', mock_encode)
|
Image.register_encoder("MOCK", mock_encode)
|
||||||
self.assertIn('MOCK', Image.ENCODERS)
|
self.assertIn("MOCK", Image.ENCODERS)
|
||||||
|
|
||||||
enc = Image._getencoder('RGB', 'MOCK', ('args',), extra=('extra',))
|
enc = Image._getencoder("RGB", "MOCK", ("args",), extra=("extra",))
|
||||||
|
|
||||||
self.assertIsInstance(enc, MockEncoder)
|
self.assertIsInstance(enc, MockEncoder)
|
||||||
self.assertEqual(enc.args, ('RGB', 'args', 'extra'))
|
self.assertEqual(enc.args, ("RGB", "args", "extra"))
|
||||||
|
|
||||||
def test_encode_registry_fail(self):
|
def test_encode_registry_fail(self):
|
||||||
self.assertRaises(IOError, Image._getencoder, 'RGB',
|
self.assertRaises(
|
||||||
'DoesNotExist',
|
IOError,
|
||||||
('args',),
|
Image._getencoder,
|
||||||
extra=('extra',))
|
"RGB",
|
||||||
|
"DoesNotExist",
|
||||||
|
("args",),
|
||||||
|
extra=("extra",),
|
||||||
|
)
|
||||||
|
|
|
@ -70,11 +70,10 @@ class TestImagePutPixel(AccessTest):
|
||||||
|
|
||||||
width, height = im1.size
|
width, height = im1.size
|
||||||
self.assertEqual(im1.getpixel((0, 0)), im1.getpixel((-width, -height)))
|
self.assertEqual(im1.getpixel((0, 0)), im1.getpixel((-width, -height)))
|
||||||
self.assertEqual(im1.getpixel((-1, -1)),
|
self.assertEqual(im1.getpixel((-1, -1)), im1.getpixel((width - 1, height - 1)))
|
||||||
im1.getpixel((width-1, height-1)))
|
|
||||||
|
|
||||||
for y in range(-1, -im1.size[1]-1, -1):
|
for y in range(-1, -im1.size[1] - 1, -1):
|
||||||
for x in range(-1, -im1.size[0]-1, -1):
|
for x in range(-1, -im1.size[0] - 1, -1):
|
||||||
pos = x, y
|
pos = x, y
|
||||||
im2.putpixel(pos, im1.getpixel(pos))
|
im2.putpixel(pos, im1.getpixel(pos))
|
||||||
|
|
||||||
|
@ -83,8 +82,8 @@ class TestImagePutPixel(AccessTest):
|
||||||
im2 = Image.new(im1.mode, im1.size, 0)
|
im2 = Image.new(im1.mode, im1.size, 0)
|
||||||
im2.readonly = 1
|
im2.readonly = 1
|
||||||
|
|
||||||
for y in range(-1, -im1.size[1]-1, -1):
|
for y in range(-1, -im1.size[1] - 1, -1):
|
||||||
for x in range(-1, -im1.size[0]-1, -1):
|
for x in range(-1, -im1.size[0] - 1, -1):
|
||||||
pos = x, y
|
pos = x, y
|
||||||
im2.putpixel(pos, im1.getpixel(pos))
|
im2.putpixel(pos, im1.getpixel(pos))
|
||||||
|
|
||||||
|
@ -96,8 +95,8 @@ class TestImagePutPixel(AccessTest):
|
||||||
pix1 = im1.load()
|
pix1 = im1.load()
|
||||||
pix2 = im2.load()
|
pix2 = im2.load()
|
||||||
|
|
||||||
for y in range(-1, -im1.size[1]-1, -1):
|
for y in range(-1, -im1.size[1] - 1, -1):
|
||||||
for x in range(-1, -im1.size[0]-1, -1):
|
for x in range(-1, -im1.size[0] - 1, -1):
|
||||||
pix2[x, y] = pix1[x, y]
|
pix2[x, y] = pix1[x, y]
|
||||||
|
|
||||||
self.assert_image_equal(im1, im2)
|
self.assert_image_equal(im1, im2)
|
||||||
|
@ -120,15 +119,19 @@ class TestImageGetPixel(AccessTest):
|
||||||
im = Image.new(mode, (1, 1), None)
|
im = Image.new(mode, (1, 1), None)
|
||||||
im.putpixel((0, 0), c)
|
im.putpixel((0, 0), c)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.getpixel((0, 0)), c,
|
im.getpixel((0, 0)),
|
||||||
"put/getpixel roundtrip failed for mode %s, color %s" % (mode, c))
|
c,
|
||||||
|
"put/getpixel roundtrip failed for mode %s, color %s" % (mode, c),
|
||||||
|
)
|
||||||
|
|
||||||
# check putpixel negative index
|
# check putpixel negative index
|
||||||
im.putpixel((-1, -1), c)
|
im.putpixel((-1, -1), c)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.getpixel((-1, -1)), c,
|
im.getpixel((-1, -1)),
|
||||||
|
c,
|
||||||
"put/getpixel roundtrip negative index failed"
|
"put/getpixel roundtrip negative index failed"
|
||||||
" for mode %s, color %s" % (mode, c))
|
" for mode %s, color %s" % (mode, c),
|
||||||
|
)
|
||||||
|
|
||||||
# Check 0
|
# Check 0
|
||||||
im = Image.new(mode, (0, 0), None)
|
im = Image.new(mode, (0, 0), None)
|
||||||
|
@ -145,13 +148,17 @@ class TestImageGetPixel(AccessTest):
|
||||||
# check initial color
|
# check initial color
|
||||||
im = Image.new(mode, (1, 1), c)
|
im = Image.new(mode, (1, 1), c)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.getpixel((0, 0)), c,
|
im.getpixel((0, 0)),
|
||||||
"initial color failed for mode %s, color %s " % (mode, c))
|
c,
|
||||||
|
"initial color failed for mode %s, color %s " % (mode, c),
|
||||||
|
)
|
||||||
# check initial color negative index
|
# check initial color negative index
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.getpixel((-1, -1)), c,
|
im.getpixel((-1, -1)),
|
||||||
|
c,
|
||||||
"initial color failed with negative index"
|
"initial color failed with negative index"
|
||||||
"for mode %s, color %s " % (mode, c))
|
"for mode %s, color %s " % (mode, c),
|
||||||
|
)
|
||||||
|
|
||||||
# Check 0
|
# Check 0
|
||||||
im = Image.new(mode, (0, 0), c)
|
im = Image.new(mode, (0, 0), c)
|
||||||
|
@ -162,18 +169,32 @@ class TestImageGetPixel(AccessTest):
|
||||||
im.getpixel((-1, -1))
|
im.getpixel((-1, -1))
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
for mode in ("1", "L", "LA", "I", "I;16", "I;16B", "F",
|
for mode in (
|
||||||
"P", "PA", "RGB", "RGBA", "RGBX", "CMYK", "YCbCr"):
|
"1",
|
||||||
|
"L",
|
||||||
|
"LA",
|
||||||
|
"I",
|
||||||
|
"I;16",
|
||||||
|
"I;16B",
|
||||||
|
"F",
|
||||||
|
"P",
|
||||||
|
"PA",
|
||||||
|
"RGB",
|
||||||
|
"RGBA",
|
||||||
|
"RGBX",
|
||||||
|
"CMYK",
|
||||||
|
"YCbCr",
|
||||||
|
):
|
||||||
self.check(mode)
|
self.check(mode)
|
||||||
|
|
||||||
def test_signedness(self):
|
def test_signedness(self):
|
||||||
# see https://github.com/python-pillow/Pillow/issues/452
|
# see https://github.com/python-pillow/Pillow/issues/452
|
||||||
# pixelaccess is using signed int* instead of uint*
|
# pixelaccess is using signed int* instead of uint*
|
||||||
for mode in ("I;16", "I;16B"):
|
for mode in ("I;16", "I;16B"):
|
||||||
self.check(mode, 2**15-1)
|
self.check(mode, 2 ** 15 - 1)
|
||||||
self.check(mode, 2**15)
|
self.check(mode, 2 ** 15)
|
||||||
self.check(mode, 2**15+1)
|
self.check(mode, 2 ** 15 + 1)
|
||||||
self.check(mode, 2**16-1)
|
self.check(mode, 2 ** 16 - 1)
|
||||||
|
|
||||||
def test_p_putpixel_rgb_rgba(self):
|
def test_p_putpixel_rgb_rgba(self):
|
||||||
for color in [(255, 0, 0), (255, 0, 0, 255)]:
|
for color in [(255, 0, 0), (255, 0, 0, 255)]:
|
||||||
|
@ -210,29 +231,30 @@ class TestCffi(AccessTest):
|
||||||
self.assertEqual(access[(x, y)], caccess[(x, y)])
|
self.assertEqual(access[(x, y)], caccess[(x, y)])
|
||||||
|
|
||||||
# Access an out-of-range pixel
|
# Access an out-of-range pixel
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(
|
||||||
lambda: access[(access.xsize+1, access.ysize+1)])
|
ValueError, lambda: access[(access.xsize + 1, access.ysize + 1)]
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_vs_c(self):
|
def test_get_vs_c(self):
|
||||||
rgb = hopper('RGB')
|
rgb = hopper("RGB")
|
||||||
rgb.load()
|
rgb.load()
|
||||||
self._test_get_access(rgb)
|
self._test_get_access(rgb)
|
||||||
self._test_get_access(hopper('RGBA'))
|
self._test_get_access(hopper("RGBA"))
|
||||||
self._test_get_access(hopper('L'))
|
self._test_get_access(hopper("L"))
|
||||||
self._test_get_access(hopper('LA'))
|
self._test_get_access(hopper("LA"))
|
||||||
self._test_get_access(hopper('1'))
|
self._test_get_access(hopper("1"))
|
||||||
self._test_get_access(hopper('P'))
|
self._test_get_access(hopper("P"))
|
||||||
# self._test_get_access(hopper('PA')) # PA -- how do I make a PA image?
|
# self._test_get_access(hopper('PA')) # PA -- how do I make a PA image?
|
||||||
self._test_get_access(hopper('F'))
|
self._test_get_access(hopper("F"))
|
||||||
|
|
||||||
im = Image.new('I;16', (10, 10), 40000)
|
im = Image.new("I;16", (10, 10), 40000)
|
||||||
self._test_get_access(im)
|
self._test_get_access(im)
|
||||||
im = Image.new('I;16L', (10, 10), 40000)
|
im = Image.new("I;16L", (10, 10), 40000)
|
||||||
self._test_get_access(im)
|
self._test_get_access(im)
|
||||||
im = Image.new('I;16B', (10, 10), 40000)
|
im = Image.new("I;16B", (10, 10), 40000)
|
||||||
self._test_get_access(im)
|
self._test_get_access(im)
|
||||||
|
|
||||||
im = Image.new('I', (10, 10), 40000)
|
im = Image.new("I", (10, 10), 40000)
|
||||||
self._test_get_access(im)
|
self._test_get_access(im)
|
||||||
# These don't actually appear to be modes that I can actually make,
|
# These don't actually appear to be modes that I can actually make,
|
||||||
# as unpack sets them directly into the I mode.
|
# as unpack sets them directly into the I mode.
|
||||||
|
@ -261,25 +283,25 @@ class TestCffi(AccessTest):
|
||||||
access[(0, 0)] = color
|
access[(0, 0)] = color
|
||||||
|
|
||||||
def test_set_vs_c(self):
|
def test_set_vs_c(self):
|
||||||
rgb = hopper('RGB')
|
rgb = hopper("RGB")
|
||||||
rgb.load()
|
rgb.load()
|
||||||
self._test_set_access(rgb, (255, 128, 0))
|
self._test_set_access(rgb, (255, 128, 0))
|
||||||
self._test_set_access(hopper('RGBA'), (255, 192, 128, 0))
|
self._test_set_access(hopper("RGBA"), (255, 192, 128, 0))
|
||||||
self._test_set_access(hopper('L'), 128)
|
self._test_set_access(hopper("L"), 128)
|
||||||
self._test_set_access(hopper('LA'), (128, 128))
|
self._test_set_access(hopper("LA"), (128, 128))
|
||||||
self._test_set_access(hopper('1'), 255)
|
self._test_set_access(hopper("1"), 255)
|
||||||
self._test_set_access(hopper('P'), 128)
|
self._test_set_access(hopper("P"), 128)
|
||||||
# self._test_set_access(i, (128, 128)) #PA -- undone how to make
|
# self._test_set_access(i, (128, 128)) #PA -- undone how to make
|
||||||
self._test_set_access(hopper('F'), 1024.0)
|
self._test_set_access(hopper("F"), 1024.0)
|
||||||
|
|
||||||
im = Image.new('I;16', (10, 10), 40000)
|
im = Image.new("I;16", (10, 10), 40000)
|
||||||
self._test_set_access(im, 45000)
|
self._test_set_access(im, 45000)
|
||||||
im = Image.new('I;16L', (10, 10), 40000)
|
im = Image.new("I;16L", (10, 10), 40000)
|
||||||
self._test_set_access(im, 45000)
|
self._test_set_access(im, 45000)
|
||||||
im = Image.new('I;16B', (10, 10), 40000)
|
im = Image.new("I;16B", (10, 10), 40000)
|
||||||
self._test_set_access(im, 45000)
|
self._test_set_access(im, 45000)
|
||||||
|
|
||||||
im = Image.new('I', (10, 10), 40000)
|
im = Image.new("I", (10, 10), 40000)
|
||||||
self._test_set_access(im, 45000)
|
self._test_set_access(im, 45000)
|
||||||
# im = Image.new('I;32L', (10, 10), -(2**10))
|
# im = Image.new('I;32L', (10, 10), -(2**10))
|
||||||
# self._test_set_access(im, -(2**13)+1)
|
# self._test_set_access(im, -(2**13)+1)
|
||||||
|
@ -295,7 +317,7 @@ class TestCffi(AccessTest):
|
||||||
|
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
# Do not save references to the image, only to the access object
|
# Do not save references to the image, only to the access object
|
||||||
px = Image.new('L', (size, 1), 0).load()
|
px = Image.new("L", (size, 1), 0).load()
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
# pixels can contain garbage if image is released
|
# pixels can contain garbage if image is released
|
||||||
self.assertEqual(px[i, 0], 0)
|
self.assertEqual(px[i, 0], 0)
|
||||||
|
@ -309,16 +331,18 @@ class TestCffi(AccessTest):
|
||||||
|
|
||||||
|
|
||||||
class TestEmbeddable(unittest.TestCase):
|
class TestEmbeddable(unittest.TestCase):
|
||||||
@unittest.skipIf(not sys.platform.startswith('win32') or
|
@unittest.skipIf(
|
||||||
on_appveyor(),
|
not sys.platform.startswith("win32") or on_appveyor(),
|
||||||
"Failing on AppVeyor when run from subprocess, not from shell")
|
"Failing on AppVeyor when run from subprocess, not from shell",
|
||||||
|
)
|
||||||
def test_embeddable(self):
|
def test_embeddable(self):
|
||||||
import subprocess
|
import subprocess
|
||||||
import ctypes
|
import ctypes
|
||||||
from distutils import ccompiler, sysconfig
|
from distutils import ccompiler, sysconfig
|
||||||
|
|
||||||
with open('embed_pil.c', 'w') as fh:
|
with open("embed_pil.c", "w") as fh:
|
||||||
fh.write("""
|
fh.write(
|
||||||
|
"""
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
@ -345,24 +369,27 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
""" % sys.prefix.replace('\\', '\\\\'))
|
"""
|
||||||
|
% sys.prefix.replace("\\", "\\\\")
|
||||||
|
)
|
||||||
|
|
||||||
compiler = ccompiler.new_compiler()
|
compiler = ccompiler.new_compiler()
|
||||||
compiler.add_include_dir(sysconfig.get_python_inc())
|
compiler.add_include_dir(sysconfig.get_python_inc())
|
||||||
|
|
||||||
libdir = (sysconfig.get_config_var('LIBDIR') or
|
libdir = sysconfig.get_config_var(
|
||||||
sysconfig.get_python_inc().replace('include', 'libs'))
|
"LIBDIR"
|
||||||
|
) or sysconfig.get_python_inc().replace("include", "libs")
|
||||||
print(libdir)
|
print(libdir)
|
||||||
compiler.add_library_dir(libdir)
|
compiler.add_library_dir(libdir)
|
||||||
objects = compiler.compile(['embed_pil.c'])
|
objects = compiler.compile(["embed_pil.c"])
|
||||||
compiler.link_executable(objects, 'embed_pil')
|
compiler.link_executable(objects, "embed_pil")
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["PATH"] = sys.prefix + ';' + env["PATH"]
|
env["PATH"] = sys.prefix + ";" + env["PATH"]
|
||||||
|
|
||||||
# do not display the Windows Error Reporting dialog
|
# do not display the Windows Error Reporting dialog
|
||||||
ctypes.windll.kernel32.SetErrorMode(0x0002)
|
ctypes.windll.kernel32.SetErrorMode(0x0002)
|
||||||
|
|
||||||
process = subprocess.Popen(['embed_pil.exe'], env=env)
|
process = subprocess.Popen(["embed_pil.exe"], env=env)
|
||||||
process.communicate()
|
process.communicate()
|
||||||
self.assertEqual(process.returncode, 0)
|
self.assertEqual(process.returncode, 0)
|
||||||
|
|
|
@ -6,28 +6,25 @@ im = hopper().resize((128, 100))
|
||||||
|
|
||||||
|
|
||||||
class TestImageArray(PillowTestCase):
|
class TestImageArray(PillowTestCase):
|
||||||
|
|
||||||
def test_toarray(self):
|
def test_toarray(self):
|
||||||
def test(mode):
|
def test(mode):
|
||||||
ai = im.convert(mode).__array_interface__
|
ai = im.convert(mode).__array_interface__
|
||||||
return ai['version'], ai["shape"], ai["typestr"], len(ai["data"])
|
return ai["version"], ai["shape"], ai["typestr"], len(ai["data"])
|
||||||
|
|
||||||
# self.assertEqual(test("1"), (3, (100, 128), '|b1', 1600))
|
# self.assertEqual(test("1"), (3, (100, 128), '|b1', 1600))
|
||||||
self.assertEqual(test("L"), (3, (100, 128), '|u1', 12800))
|
self.assertEqual(test("L"), (3, (100, 128), "|u1", 12800))
|
||||||
|
|
||||||
# FIXME: wrong?
|
# FIXME: wrong?
|
||||||
self.assertEqual(test("I"), (3, (100, 128),
|
self.assertEqual(test("I"), (3, (100, 128), Image._ENDIAN + "i4", 51200))
|
||||||
Image._ENDIAN + 'i4', 51200))
|
|
||||||
# FIXME: wrong?
|
# FIXME: wrong?
|
||||||
self.assertEqual(test("F"), (3, (100, 128),
|
self.assertEqual(test("F"), (3, (100, 128), Image._ENDIAN + "f4", 51200))
|
||||||
Image._ENDIAN + 'f4', 51200))
|
|
||||||
|
|
||||||
self.assertEqual(test("LA"), (3, (100, 128, 2), '|u1', 25600))
|
self.assertEqual(test("LA"), (3, (100, 128, 2), "|u1", 25600))
|
||||||
self.assertEqual(test("RGB"), (3, (100, 128, 3), '|u1', 38400))
|
self.assertEqual(test("RGB"), (3, (100, 128, 3), "|u1", 38400))
|
||||||
self.assertEqual(test("RGBA"), (3, (100, 128, 4), '|u1', 51200))
|
self.assertEqual(test("RGBA"), (3, (100, 128, 4), "|u1", 51200))
|
||||||
self.assertEqual(test("RGBX"), (3, (100, 128, 4), '|u1', 51200))
|
self.assertEqual(test("RGBX"), (3, (100, 128, 4), "|u1", 51200))
|
||||||
|
|
||||||
def test_fromarray(self):
|
def test_fromarray(self):
|
||||||
|
|
||||||
class Wrapper(object):
|
class Wrapper(object):
|
||||||
""" Class with API matching Image.fromarray """
|
""" Class with API matching Image.fromarray """
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,26 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestImageConvert(PillowTestCase):
|
class TestImageConvert(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
def convert(im, mode):
|
def convert(im, mode):
|
||||||
out = im.convert(mode)
|
out = im.convert(mode)
|
||||||
self.assertEqual(out.mode, mode)
|
self.assertEqual(out.mode, mode)
|
||||||
self.assertEqual(out.size, im.size)
|
self.assertEqual(out.size, im.size)
|
||||||
|
|
||||||
modes = ("1", "L", "LA", "P", "PA", "I", "F",
|
modes = (
|
||||||
"RGB", "RGBA", "RGBX", "CMYK", "YCbCr")
|
"1",
|
||||||
|
"L",
|
||||||
|
"LA",
|
||||||
|
"P",
|
||||||
|
"PA",
|
||||||
|
"I",
|
||||||
|
"F",
|
||||||
|
"RGB",
|
||||||
|
"RGBA",
|
||||||
|
"RGBX",
|
||||||
|
"CMYK",
|
||||||
|
"YCbCr",
|
||||||
|
)
|
||||||
|
|
||||||
for mode in modes:
|
for mode in modes:
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
|
@ -38,162 +48,159 @@ class TestImageConvert(PillowTestCase):
|
||||||
|
|
||||||
def _test_float_conversion(self, im):
|
def _test_float_conversion(self, im):
|
||||||
orig = im.getpixel((5, 5))
|
orig = im.getpixel((5, 5))
|
||||||
converted = im.convert('F').getpixel((5, 5))
|
converted = im.convert("F").getpixel((5, 5))
|
||||||
self.assertEqual(orig, converted)
|
self.assertEqual(orig, converted)
|
||||||
|
|
||||||
def test_8bit(self):
|
def test_8bit(self):
|
||||||
im = Image.open('Tests/images/hopper.jpg')
|
im = Image.open("Tests/images/hopper.jpg")
|
||||||
self._test_float_conversion(im.convert('L'))
|
self._test_float_conversion(im.convert("L"))
|
||||||
|
|
||||||
def test_16bit(self):
|
def test_16bit(self):
|
||||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
im = Image.open("Tests/images/16bit.cropped.tif")
|
||||||
self._test_float_conversion(im)
|
self._test_float_conversion(im)
|
||||||
|
|
||||||
def test_16bit_workaround(self):
|
def test_16bit_workaround(self):
|
||||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
im = Image.open("Tests/images/16bit.cropped.tif")
|
||||||
self._test_float_conversion(im.convert('I'))
|
self._test_float_conversion(im.convert("I"))
|
||||||
|
|
||||||
def test_rgba_p(self):
|
def test_rgba_p(self):
|
||||||
im = hopper('RGBA')
|
im = hopper("RGBA")
|
||||||
im.putalpha(hopper('L'))
|
im.putalpha(hopper("L"))
|
||||||
|
|
||||||
converted = im.convert('P')
|
converted = im.convert("P")
|
||||||
comparable = converted.convert('RGBA')
|
comparable = converted.convert("RGBA")
|
||||||
|
|
||||||
self.assert_image_similar(im, comparable, 20)
|
self.assert_image_similar(im, comparable, 20)
|
||||||
|
|
||||||
def test_trns_p(self):
|
def test_trns_p(self):
|
||||||
im = hopper('P')
|
im = hopper("P")
|
||||||
im.info['transparency'] = 0
|
im.info["transparency"] = 0
|
||||||
|
|
||||||
f = self.tempfile('temp.png')
|
f = self.tempfile("temp.png")
|
||||||
|
|
||||||
im_l = im.convert('L')
|
im_l = im.convert("L")
|
||||||
self.assertEqual(im_l.info['transparency'], 0) # undone
|
self.assertEqual(im_l.info["transparency"], 0) # undone
|
||||||
im_l.save(f)
|
im_l.save(f)
|
||||||
|
|
||||||
im_rgb = im.convert('RGB')
|
im_rgb = im.convert("RGB")
|
||||||
self.assertEqual(im_rgb.info['transparency'], (0, 0, 0)) # undone
|
self.assertEqual(im_rgb.info["transparency"], (0, 0, 0)) # undone
|
||||||
im_rgb.save(f)
|
im_rgb.save(f)
|
||||||
|
|
||||||
# ref https://github.com/python-pillow/Pillow/issues/664
|
# ref https://github.com/python-pillow/Pillow/issues/664
|
||||||
|
|
||||||
def test_trns_p_rgba(self):
|
def test_trns_p_rgba(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper('P')
|
im = hopper("P")
|
||||||
im.info['transparency'] = 128
|
im.info["transparency"] = 128
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
im_rgba = im.convert('RGBA')
|
im_rgba = im.convert("RGBA")
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertNotIn('transparency', im_rgba.info)
|
self.assertNotIn("transparency", im_rgba.info)
|
||||||
# https://github.com/python-pillow/Pillow/issues/2702
|
# https://github.com/python-pillow/Pillow/issues/2702
|
||||||
self.assertIsNone(im_rgba.palette)
|
self.assertIsNone(im_rgba.palette)
|
||||||
|
|
||||||
def test_trns_l(self):
|
def test_trns_l(self):
|
||||||
im = hopper('L')
|
im = hopper("L")
|
||||||
im.info['transparency'] = 128
|
im.info["transparency"] = 128
|
||||||
|
|
||||||
f = self.tempfile('temp.png')
|
f = self.tempfile("temp.png")
|
||||||
|
|
||||||
im_rgb = im.convert('RGB')
|
im_rgb = im.convert("RGB")
|
||||||
self.assertEqual(im_rgb.info['transparency'],
|
self.assertEqual(im_rgb.info["transparency"], (128, 128, 128)) # undone
|
||||||
(128, 128, 128)) # undone
|
|
||||||
im_rgb.save(f)
|
im_rgb.save(f)
|
||||||
|
|
||||||
im_p = im.convert('P')
|
im_p = im.convert("P")
|
||||||
self.assertIn('transparency', im_p.info)
|
self.assertIn("transparency", im_p.info)
|
||||||
im_p.save(f)
|
im_p.save(f)
|
||||||
|
|
||||||
im_p = self.assert_warning(
|
im_p = self.assert_warning(UserWarning, im.convert, "P", palette=Image.ADAPTIVE)
|
||||||
UserWarning,
|
self.assertNotIn("transparency", im_p.info)
|
||||||
im.convert, 'P', palette=Image.ADAPTIVE)
|
|
||||||
self.assertNotIn('transparency', im_p.info)
|
|
||||||
im_p.save(f)
|
im_p.save(f)
|
||||||
|
|
||||||
def test_trns_RGB(self):
|
def test_trns_RGB(self):
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
im.info['transparency'] = im.getpixel((0, 0))
|
im.info["transparency"] = im.getpixel((0, 0))
|
||||||
|
|
||||||
f = self.tempfile('temp.png')
|
f = self.tempfile("temp.png")
|
||||||
|
|
||||||
im_l = im.convert('L')
|
im_l = im.convert("L")
|
||||||
self.assertEqual(im_l.info['transparency'],
|
self.assertEqual(im_l.info["transparency"], im_l.getpixel((0, 0))) # undone
|
||||||
im_l.getpixel((0, 0))) # undone
|
|
||||||
im_l.save(f)
|
im_l.save(f)
|
||||||
|
|
||||||
im_p = im.convert('P')
|
im_p = im.convert("P")
|
||||||
self.assertIn('transparency', im_p.info)
|
self.assertIn("transparency", im_p.info)
|
||||||
im_p.save(f)
|
im_p.save(f)
|
||||||
|
|
||||||
im_rgba = im.convert('RGBA')
|
im_rgba = im.convert("RGBA")
|
||||||
self.assertNotIn('transparency', im_rgba.info)
|
self.assertNotIn("transparency", im_rgba.info)
|
||||||
im_rgba.save(f)
|
im_rgba.save(f)
|
||||||
|
|
||||||
im_p = self.assert_warning(
|
im_p = self.assert_warning(UserWarning, im.convert, "P", palette=Image.ADAPTIVE)
|
||||||
UserWarning,
|
self.assertNotIn("transparency", im_p.info)
|
||||||
im.convert, 'P', palette=Image.ADAPTIVE)
|
|
||||||
self.assertNotIn('transparency', im_p.info)
|
|
||||||
im_p.save(f)
|
im_p.save(f)
|
||||||
|
|
||||||
def test_gif_with_rgba_palette_to_p(self):
|
def test_gif_with_rgba_palette_to_p(self):
|
||||||
# See https://github.com/python-pillow/Pillow/issues/2433
|
# See https://github.com/python-pillow/Pillow/issues/2433
|
||||||
im = Image.open('Tests/images/hopper.gif')
|
im = Image.open("Tests/images/hopper.gif")
|
||||||
im.info['transparency'] = 255
|
im.info["transparency"] = 255
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.palette.mode, 'RGBA')
|
self.assertEqual(im.palette.mode, "RGBA")
|
||||||
im_p = im.convert('P')
|
im_p = im.convert("P")
|
||||||
|
|
||||||
# Should not raise ValueError: unrecognized raw mode
|
# Should not raise ValueError: unrecognized raw mode
|
||||||
im_p.load()
|
im_p.load()
|
||||||
|
|
||||||
def test_p_la(self):
|
def test_p_la(self):
|
||||||
im = hopper('RGBA')
|
im = hopper("RGBA")
|
||||||
alpha = hopper('L')
|
alpha = hopper("L")
|
||||||
im.putalpha(alpha)
|
im.putalpha(alpha)
|
||||||
|
|
||||||
comparable = im.convert('P').convert('LA').getchannel('A')
|
comparable = im.convert("P").convert("LA").getchannel("A")
|
||||||
|
|
||||||
self.assert_image_similar(alpha, comparable, 5)
|
self.assert_image_similar(alpha, comparable, 5)
|
||||||
|
|
||||||
def test_matrix_illegal_conversion(self):
|
def test_matrix_illegal_conversion(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper('CMYK')
|
im = hopper("CMYK")
|
||||||
|
# fmt: off
|
||||||
matrix = (
|
matrix = (
|
||||||
0.412453, 0.357580, 0.180423, 0,
|
0.412453, 0.357580, 0.180423, 0,
|
||||||
0.212671, 0.715160, 0.072169, 0,
|
0.212671, 0.715160, 0.072169, 0,
|
||||||
0.019334, 0.119193, 0.950227, 0)
|
0.019334, 0.119193, 0.950227, 0)
|
||||||
self.assertNotEqual(im.mode, 'RGB')
|
# fmt: on
|
||||||
|
self.assertNotEqual(im.mode, "RGB")
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, im.convert, mode="CMYK", matrix=matrix)
|
||||||
im.convert, mode='CMYK', matrix=matrix)
|
|
||||||
|
|
||||||
def test_matrix_wrong_mode(self):
|
def test_matrix_wrong_mode(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper('L')
|
im = hopper("L")
|
||||||
|
# fmt: off
|
||||||
matrix = (
|
matrix = (
|
||||||
0.412453, 0.357580, 0.180423, 0,
|
0.412453, 0.357580, 0.180423, 0,
|
||||||
0.212671, 0.715160, 0.072169, 0,
|
0.212671, 0.715160, 0.072169, 0,
|
||||||
0.019334, 0.119193, 0.950227, 0)
|
0.019334, 0.119193, 0.950227, 0)
|
||||||
self.assertEqual(im.mode, 'L')
|
# fmt: on
|
||||||
|
self.assertEqual(im.mode, "L")
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, im.convert, mode="L", matrix=matrix)
|
||||||
im.convert, mode='L', matrix=matrix)
|
|
||||||
|
|
||||||
def test_matrix_xyz(self):
|
def test_matrix_xyz(self):
|
||||||
|
|
||||||
def matrix_convert(mode):
|
def matrix_convert(mode):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
im.info['transparency'] = (255, 0, 0)
|
im.info["transparency"] = (255, 0, 0)
|
||||||
|
# fmt: off
|
||||||
matrix = (
|
matrix = (
|
||||||
0.412453, 0.357580, 0.180423, 0,
|
0.412453, 0.357580, 0.180423, 0,
|
||||||
0.212671, 0.715160, 0.072169, 0,
|
0.212671, 0.715160, 0.072169, 0,
|
||||||
0.019334, 0.119193, 0.950227, 0)
|
0.019334, 0.119193, 0.950227, 0)
|
||||||
self.assertEqual(im.mode, 'RGB')
|
# fmt: on
|
||||||
|
self.assertEqual(im.mode, "RGB")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
# Convert an RGB image to the CIE XYZ colour space
|
# Convert an RGB image to the CIE XYZ colour space
|
||||||
|
@ -202,31 +209,31 @@ class TestImageConvert(PillowTestCase):
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(converted_im.mode, mode)
|
self.assertEqual(converted_im.mode, mode)
|
||||||
self.assertEqual(converted_im.size, im.size)
|
self.assertEqual(converted_im.size, im.size)
|
||||||
target = Image.open('Tests/images/hopper-XYZ.png')
|
target = Image.open("Tests/images/hopper-XYZ.png")
|
||||||
if converted_im.mode == 'RGB':
|
if converted_im.mode == "RGB":
|
||||||
self.assert_image_similar(converted_im, target, 3)
|
self.assert_image_similar(converted_im, target, 3)
|
||||||
self.assertEqual(converted_im.info['transparency'],
|
self.assertEqual(converted_im.info["transparency"], (105, 54, 4))
|
||||||
(105, 54, 4))
|
|
||||||
else:
|
else:
|
||||||
self.assert_image_similar(converted_im,
|
self.assert_image_similar(converted_im, target.getchannel(0), 1)
|
||||||
target.getchannel(0), 1)
|
self.assertEqual(converted_im.info["transparency"], 105)
|
||||||
self.assertEqual(converted_im.info['transparency'], 105)
|
|
||||||
|
|
||||||
matrix_convert('RGB')
|
matrix_convert("RGB")
|
||||||
matrix_convert('L')
|
matrix_convert("L")
|
||||||
|
|
||||||
def test_matrix_identity(self):
|
def test_matrix_identity(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper('RGB')
|
im = hopper("RGB")
|
||||||
|
# fmt: off
|
||||||
identity_matrix = (
|
identity_matrix = (
|
||||||
1, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, 1, 0, 0,
|
0, 1, 0, 0,
|
||||||
0, 0, 1, 0)
|
0, 0, 1, 0)
|
||||||
self.assertEqual(im.mode, 'RGB')
|
# fmt: on
|
||||||
|
self.assertEqual(im.mode, "RGB")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
# Convert with an identity matrix
|
# Convert with an identity matrix
|
||||||
converted_im = im.convert(mode='RGB', matrix=identity_matrix)
|
converted_im = im.convert(mode="RGB", matrix=identity_matrix)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
# No change
|
# No change
|
||||||
|
|
|
@ -6,7 +6,6 @@ import copy
|
||||||
|
|
||||||
|
|
||||||
class TestImageCopy(PillowTestCase):
|
class TestImageCopy(PillowTestCase):
|
||||||
|
|
||||||
def test_copy(self):
|
def test_copy(self):
|
||||||
croppedCoordinates = (10, 10, 20, 20)
|
croppedCoordinates = (10, 10, 20, 20)
|
||||||
croppedSize = (10, 10)
|
croppedSize = (10, 10)
|
||||||
|
@ -36,7 +35,7 @@ class TestImageCopy(PillowTestCase):
|
||||||
self.assertEqual(out.size, croppedSize)
|
self.assertEqual(out.size, croppedSize)
|
||||||
|
|
||||||
def test_copy_zero(self):
|
def test_copy_zero(self):
|
||||||
im = Image.new('RGB', (0, 0))
|
im = Image.new("RGB", (0, 0))
|
||||||
out = im.copy()
|
out = im.copy()
|
||||||
self.assertEqual(out.mode, im.mode)
|
self.assertEqual(out.mode, im.mode)
|
||||||
self.assertEqual(out.size, im.size)
|
self.assertEqual(out.size, im.size)
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestImageCrop(PillowTestCase):
|
class TestImageCrop(PillowTestCase):
|
||||||
|
|
||||||
def test_crop(self):
|
def test_crop(self):
|
||||||
def crop(mode):
|
def crop(mode):
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
|
@ -13,11 +12,11 @@ class TestImageCrop(PillowTestCase):
|
||||||
cropped = im.crop((50, 50, 100, 100))
|
cropped = im.crop((50, 50, 100, 100))
|
||||||
self.assertEqual(cropped.mode, mode)
|
self.assertEqual(cropped.mode, mode)
|
||||||
self.assertEqual(cropped.size, (50, 50))
|
self.assertEqual(cropped.size, (50, 50))
|
||||||
|
|
||||||
for mode in "1", "P", "L", "RGB", "I", "F":
|
for mode in "1", "P", "L", "RGB", "I", "F":
|
||||||
crop(mode)
|
crop(mode)
|
||||||
|
|
||||||
def test_wide_crop(self):
|
def test_wide_crop(self):
|
||||||
|
|
||||||
def crop(*bbox):
|
def crop(*bbox):
|
||||||
i = im.crop(bbox)
|
i = im.crop(bbox)
|
||||||
h = i.histogram()
|
h = i.histogram()
|
||||||
|
@ -74,7 +73,7 @@ class TestImageCrop(PillowTestCase):
|
||||||
# apparently a use after free on windows, see
|
# apparently a use after free on windows, see
|
||||||
# https://github.com/python-pillow/Pillow/issues/1077
|
# https://github.com/python-pillow/Pillow/issues/1077
|
||||||
|
|
||||||
test_img = 'Tests/images/bmp/g/pal8-0.bmp'
|
test_img = "Tests/images/bmp/g/pal8-0.bmp"
|
||||||
extents = (1, 1, 10, 10)
|
extents = (1, 1, 10, 10)
|
||||||
# works prepatch
|
# works prepatch
|
||||||
img = Image.open(test_img)
|
img = Image.open(test_img)
|
||||||
|
@ -88,7 +87,7 @@ class TestImageCrop(PillowTestCase):
|
||||||
|
|
||||||
def test_crop_zero(self):
|
def test_crop_zero(self):
|
||||||
|
|
||||||
im = Image.new('RGB', (0, 0), 'white')
|
im = Image.new("RGB", (0, 0), "white")
|
||||||
|
|
||||||
cropped = im.crop((0, 0, 0, 0))
|
cropped = im.crop((0, 0, 0, 0))
|
||||||
self.assertEqual(cropped.size, (0, 0))
|
self.assertEqual(cropped.size, (0, 0))
|
||||||
|
@ -97,7 +96,7 @@ class TestImageCrop(PillowTestCase):
|
||||||
self.assertEqual(cropped.size, (10, 10))
|
self.assertEqual(cropped.size, (10, 10))
|
||||||
self.assertEqual(cropped.getdata()[0], (0, 0, 0))
|
self.assertEqual(cropped.getdata()[0], (0, 0, 0))
|
||||||
|
|
||||||
im = Image.new('RGB', (0, 0))
|
im = Image.new("RGB", (0, 0))
|
||||||
|
|
||||||
cropped = im.crop((10, 10, 20, 20))
|
cropped = im.crop((10, 10, 20, 20))
|
||||||
self.assertEqual(cropped.size, (10, 10))
|
self.assertEqual(cropped.size, (10, 10))
|
||||||
|
|
|
@ -11,7 +11,7 @@ class TestImageDraft(PillowTestCase):
|
||||||
|
|
||||||
def draft_roundtrip(self, in_mode, in_size, req_mode, req_size):
|
def draft_roundtrip(self, in_mode, in_size, req_mode, req_size):
|
||||||
im = Image.new(in_mode, in_size)
|
im = Image.new(in_mode, in_size)
|
||||||
data = tostring(im, 'JPEG')
|
data = tostring(im, "JPEG")
|
||||||
im = fromstring(data)
|
im = fromstring(data)
|
||||||
im.draft(req_mode, req_size)
|
im.draft(req_mode, req_size)
|
||||||
return im
|
return im
|
||||||
|
@ -23,7 +23,6 @@ class TestImageDraft(PillowTestCase):
|
||||||
((128, 128), (64, 64), (64, 64)),
|
((128, 128), (64, 64), (64, 64)),
|
||||||
((128, 128), (32, 32), (32, 32)),
|
((128, 128), (32, 32), (32, 32)),
|
||||||
((128, 128), (16, 16), (16, 16)),
|
((128, 128), (16, 16), (16, 16)),
|
||||||
|
|
||||||
# large requested width
|
# large requested width
|
||||||
((435, 361), (218, 128), (435, 361)), # almost 2x
|
((435, 361), (218, 128), (435, 361)), # almost 2x
|
||||||
((435, 361), (217, 128), (218, 181)), # more than 2x
|
((435, 361), (217, 128), (218, 181)), # more than 2x
|
||||||
|
@ -32,7 +31,6 @@ class TestImageDraft(PillowTestCase):
|
||||||
((435, 361), (55, 32), (109, 91)), # almost 8x
|
((435, 361), (55, 32), (109, 91)), # almost 8x
|
||||||
((435, 361), (54, 32), (55, 46)), # more than 8x
|
((435, 361), (54, 32), (55, 46)), # more than 8x
|
||||||
((435, 361), (27, 16), (55, 46)), # more than 16x
|
((435, 361), (27, 16), (55, 46)), # more than 16x
|
||||||
|
|
||||||
# and vice versa
|
# and vice versa
|
||||||
((435, 361), (128, 181), (435, 361)), # almost 2x
|
((435, 361), (128, 181), (435, 361)), # almost 2x
|
||||||
((435, 361), (128, 180), (218, 181)), # more than 2x
|
((435, 361), (128, 180), (218, 181)), # more than 2x
|
||||||
|
@ -42,7 +40,7 @@ class TestImageDraft(PillowTestCase):
|
||||||
((435, 361), (32, 45), (55, 46)), # more than 8x
|
((435, 361), (32, 45), (55, 46)), # more than 8x
|
||||||
((435, 361), (16, 22), (55, 46)), # more than 16x
|
((435, 361), (16, 22), (55, 46)), # more than 16x
|
||||||
]:
|
]:
|
||||||
im = self.draft_roundtrip('L', in_size, None, req_size)
|
im = self.draft_roundtrip("L", in_size, None, req_size)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.size, out_size)
|
self.assertEqual(im.size, out_size)
|
||||||
|
|
||||||
|
@ -66,6 +64,6 @@ class TestImageDraft(PillowTestCase):
|
||||||
self.assertEqual(im.mode, out_mode)
|
self.assertEqual(im.mode, out_mode)
|
||||||
|
|
||||||
def test_several_drafts(self):
|
def test_several_drafts(self):
|
||||||
im = self.draft_roundtrip('L', (128, 128), None, (64, 64))
|
im = self.draft_roundtrip("L", (128, 128), None, (64, 64))
|
||||||
im.draft(None, (64, 64))
|
im.draft(None, (64, 64))
|
||||||
im.load()
|
im.load()
|
||||||
|
|
|
@ -4,9 +4,7 @@ from PIL import Image, ImageFilter
|
||||||
|
|
||||||
|
|
||||||
class TestImageFilter(PillowTestCase):
|
class TestImageFilter(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
def filter(filter):
|
def filter(filter):
|
||||||
for mode in ["L", "RGB", "CMYK"]:
|
for mode in ["L", "RGB", "CMYK"]:
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
|
@ -49,7 +47,6 @@ class TestImageFilter(PillowTestCase):
|
||||||
im.filter(ImageFilter.SMOOTH)
|
im.filter(ImageFilter.SMOOTH)
|
||||||
|
|
||||||
def test_modefilter(self):
|
def test_modefilter(self):
|
||||||
|
|
||||||
def modefilter(mode):
|
def modefilter(mode):
|
||||||
im = Image.new(mode, (3, 3), None)
|
im = Image.new(mode, (3, 3), None)
|
||||||
im.putdata(list(range(9)))
|
im.putdata(list(range(9)))
|
||||||
|
@ -68,7 +65,6 @@ class TestImageFilter(PillowTestCase):
|
||||||
self.assertEqual(modefilter("RGB"), ((4, 0, 0), (0, 0, 0)))
|
self.assertEqual(modefilter("RGB"), ((4, 0, 0), (0, 0, 0)))
|
||||||
|
|
||||||
def test_rankfilter(self):
|
def test_rankfilter(self):
|
||||||
|
|
||||||
def rankfilter(mode):
|
def rankfilter(mode):
|
||||||
im = Image.new(mode, (3, 3), None)
|
im = Image.new(mode, (3, 3), None)
|
||||||
im.putdata(list(range(9)))
|
im.putdata(list(range(9)))
|
||||||
|
@ -100,39 +96,48 @@ class TestImageFilter(PillowTestCase):
|
||||||
self.assertRaises(ValueError, builtinFilter.filter, hopper("P"))
|
self.assertRaises(ValueError, builtinFilter.filter, hopper("P"))
|
||||||
|
|
||||||
def test_kernel_not_enough_coefficients(self):
|
def test_kernel_not_enough_coefficients(self):
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError, lambda: ImageFilter.Kernel((3, 3), (0, 0)))
|
||||||
lambda: ImageFilter.Kernel((3, 3), (0, 0)))
|
|
||||||
|
|
||||||
def test_consistency_3x3(self):
|
def test_consistency_3x3(self):
|
||||||
source = Image.open("Tests/images/hopper.bmp")
|
source = Image.open("Tests/images/hopper.bmp")
|
||||||
reference = Image.open("Tests/images/hopper_emboss.bmp")
|
reference = Image.open("Tests/images/hopper_emboss.bmp")
|
||||||
kernel = ImageFilter.Kernel((3, 3), # noqa: E127
|
kernel = ImageFilter.Kernel( # noqa: E127
|
||||||
(-1, -1, 0,
|
(3, 3),
|
||||||
-1, 0, 1,
|
# fmt: off
|
||||||
0, 1, 1), .3)
|
(-1, -1, 0,
|
||||||
|
-1, 0, 1,
|
||||||
|
0, 1, 1),
|
||||||
|
# fmt: on
|
||||||
|
0.3,
|
||||||
|
)
|
||||||
source = source.split() * 2
|
source = source.split() * 2
|
||||||
reference = reference.split() * 2
|
reference = reference.split() * 2
|
||||||
|
|
||||||
for mode in ['L', 'LA', 'RGB', 'CMYK']:
|
for mode in ["L", "LA", "RGB", "CMYK"]:
|
||||||
self.assert_image_equal(
|
self.assert_image_equal(
|
||||||
Image.merge(mode, source[:len(mode)]).filter(kernel),
|
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
||||||
Image.merge(mode, reference[:len(mode)]),
|
Image.merge(mode, reference[: len(mode)]),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_consistency_5x5(self):
|
def test_consistency_5x5(self):
|
||||||
source = Image.open("Tests/images/hopper.bmp")
|
source = Image.open("Tests/images/hopper.bmp")
|
||||||
reference = Image.open("Tests/images/hopper_emboss_more.bmp")
|
reference = Image.open("Tests/images/hopper_emboss_more.bmp")
|
||||||
kernel = ImageFilter.Kernel((5, 5), # noqa: E127
|
kernel = ImageFilter.Kernel( # noqa: E127
|
||||||
(-1, -1, -1, -1, 0,
|
(5, 5),
|
||||||
-1, -1, -1, 0, 1,
|
# fmt: off
|
||||||
-1, -1, 0, 1, 1,
|
(-1, -1, -1, -1, 0,
|
||||||
-1, 0, 1, 1, 1,
|
-1, -1, -1, 0, 1,
|
||||||
0, 1, 1, 1, 1), 0.3)
|
-1, -1, 0, 1, 1,
|
||||||
|
-1, 0, 1, 1, 1,
|
||||||
|
0, 1, 1, 1, 1),
|
||||||
|
# fmt: on
|
||||||
|
0.3,
|
||||||
|
)
|
||||||
source = source.split() * 2
|
source = source.split() * 2
|
||||||
reference = reference.split() * 2
|
reference = reference.split() * 2
|
||||||
|
|
||||||
for mode in ['L', 'LA', 'RGB', 'CMYK']:
|
for mode in ["L", "LA", "RGB", "CMYK"]:
|
||||||
self.assert_image_equal(
|
self.assert_image_equal(
|
||||||
Image.merge(mode, source[:len(mode)]).filter(kernel),
|
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
||||||
Image.merge(mode, reference[:len(mode)]),
|
Image.merge(mode, reference[: len(mode)]),
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestImageFromBytes(PillowTestCase):
|
class TestImageFromBytes(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im1 = hopper()
|
im1 = hopper()
|
||||||
im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes())
|
im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes())
|
||||||
|
|
|
@ -8,8 +8,8 @@ class TestFromQImage(PillowQtTestCase, PillowTestCase):
|
||||||
|
|
||||||
files_to_test = [
|
files_to_test = [
|
||||||
hopper(),
|
hopper(),
|
||||||
Image.open('Tests/images/transparent.png'),
|
Image.open("Tests/images/transparent.png"),
|
||||||
Image.open('Tests/images/7x13.png'),
|
Image.open("Tests/images/7x13.png"),
|
||||||
]
|
]
|
||||||
|
|
||||||
def roundtrip(self, expected):
|
def roundtrip(self, expected):
|
||||||
|
@ -19,26 +19,26 @@ class TestFromQImage(PillowQtTestCase, PillowTestCase):
|
||||||
result = ImageQt.fromqimage(intermediate)
|
result = ImageQt.fromqimage(intermediate)
|
||||||
|
|
||||||
if intermediate.hasAlphaChannel():
|
if intermediate.hasAlphaChannel():
|
||||||
self.assert_image_equal(result, expected.convert('RGBA'))
|
self.assert_image_equal(result, expected.convert("RGBA"))
|
||||||
else:
|
else:
|
||||||
self.assert_image_equal(result, expected.convert('RGB'))
|
self.assert_image_equal(result, expected.convert("RGB"))
|
||||||
|
|
||||||
def test_sanity_1(self):
|
def test_sanity_1(self):
|
||||||
for im in self.files_to_test:
|
for im in self.files_to_test:
|
||||||
self.roundtrip(im.convert('1'))
|
self.roundtrip(im.convert("1"))
|
||||||
|
|
||||||
def test_sanity_rgb(self):
|
def test_sanity_rgb(self):
|
||||||
for im in self.files_to_test:
|
for im in self.files_to_test:
|
||||||
self.roundtrip(im.convert('RGB'))
|
self.roundtrip(im.convert("RGB"))
|
||||||
|
|
||||||
def test_sanity_rgba(self):
|
def test_sanity_rgba(self):
|
||||||
for im in self.files_to_test:
|
for im in self.files_to_test:
|
||||||
self.roundtrip(im.convert('RGBA'))
|
self.roundtrip(im.convert("RGBA"))
|
||||||
|
|
||||||
def test_sanity_l(self):
|
def test_sanity_l(self):
|
||||||
for im in self.files_to_test:
|
for im in self.files_to_test:
|
||||||
self.roundtrip(im.convert('L'))
|
self.roundtrip(im.convert("L"))
|
||||||
|
|
||||||
def test_sanity_p(self):
|
def test_sanity_p(self):
|
||||||
for im in self.files_to_test:
|
for im in self.files_to_test:
|
||||||
self.roundtrip(im.convert('P'))
|
self.roundtrip(im.convert("P"))
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestImageGetBands(PillowTestCase):
|
class TestImageGetBands(PillowTestCase):
|
||||||
|
|
||||||
def test_getbands(self):
|
def test_getbands(self):
|
||||||
self.assertEqual(Image.new("1", (1, 1)).getbands(), ("1",))
|
self.assertEqual(Image.new("1", (1, 1)).getbands(), ("1",))
|
||||||
self.assertEqual(Image.new("L", (1, 1)).getbands(), ("L",))
|
self.assertEqual(Image.new("L", (1, 1)).getbands(), ("L",))
|
||||||
|
@ -12,9 +11,6 @@ class TestImageGetBands(PillowTestCase):
|
||||||
self.assertEqual(Image.new("F", (1, 1)).getbands(), ("F",))
|
self.assertEqual(Image.new("F", (1, 1)).getbands(), ("F",))
|
||||||
self.assertEqual(Image.new("P", (1, 1)).getbands(), ("P",))
|
self.assertEqual(Image.new("P", (1, 1)).getbands(), ("P",))
|
||||||
self.assertEqual(Image.new("RGB", (1, 1)).getbands(), ("R", "G", "B"))
|
self.assertEqual(Image.new("RGB", (1, 1)).getbands(), ("R", "G", "B"))
|
||||||
self.assertEqual(
|
self.assertEqual(Image.new("RGBA", (1, 1)).getbands(), ("R", "G", "B", "A"))
|
||||||
Image.new("RGBA", (1, 1)).getbands(), ("R", "G", "B", "A"))
|
self.assertEqual(Image.new("CMYK", (1, 1)).getbands(), ("C", "M", "Y", "K"))
|
||||||
self.assertEqual(
|
self.assertEqual(Image.new("YCbCr", (1, 1)).getbands(), ("Y", "Cb", "Cr"))
|
||||||
Image.new("CMYK", (1, 1)).getbands(), ("C", "M", "Y", "K"))
|
|
||||||
self.assertEqual(
|
|
||||||
Image.new("YCbCr", (1, 1)).getbands(), ("Y", "Cb", "Cr"))
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class TestImageGetBbox(PillowTestCase):
|
class TestImageGetBbox(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
bbox = hopper().getbbox()
|
bbox = hopper().getbbox()
|
||||||
|
|
|
@ -2,9 +2,7 @@ from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageGetColors(PillowTestCase):
|
class TestImageGetColors(PillowTestCase):
|
||||||
|
|
||||||
def test_getcolors(self):
|
def test_getcolors(self):
|
||||||
|
|
||||||
def getcolors(mode, limit=None):
|
def getcolors(mode, limit=None):
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
if limit:
|
if limit:
|
||||||
|
@ -43,9 +41,11 @@ class TestImageGetColors(PillowTestCase):
|
||||||
|
|
||||||
im = hopper().quantize(3).convert("RGB")
|
im = hopper().quantize(3).convert("RGB")
|
||||||
|
|
||||||
expected = [(4039, (172, 166, 181)),
|
expected = [
|
||||||
(4385, (124, 113, 134)),
|
(4039, (172, 166, 181)),
|
||||||
(7960, (31, 20, 33))]
|
(4385, (124, 113, 134)),
|
||||||
|
(7960, (31, 20, 33)),
|
||||||
|
]
|
||||||
|
|
||||||
A = im.getcolors(maxcolors=2)
|
A = im.getcolors(maxcolors=2)
|
||||||
self.assertIsNone(A)
|
self.assertIsNone(A)
|
||||||
|
|
|
@ -2,7 +2,6 @@ from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageGetData(PillowTestCase):
|
class TestImageGetData(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
data = hopper().getdata()
|
data = hopper().getdata()
|
||||||
|
@ -13,7 +12,6 @@ class TestImageGetData(PillowTestCase):
|
||||||
self.assertEqual(data[0], (20, 20, 70))
|
self.assertEqual(data[0], (20, 20, 70))
|
||||||
|
|
||||||
def test_roundtrip(self):
|
def test_roundtrip(self):
|
||||||
|
|
||||||
def getdata(mode):
|
def getdata(mode):
|
||||||
im = hopper(mode).resize((32, 30))
|
im = hopper(mode).resize((32, 30))
|
||||||
data = im.getdata()
|
data = im.getdata()
|
||||||
|
|
|
@ -3,9 +3,7 @@ from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageGetExtrema(PillowTestCase):
|
class TestImageGetExtrema(PillowTestCase):
|
||||||
|
|
||||||
def test_extrema(self):
|
def test_extrema(self):
|
||||||
|
|
||||||
def extrema(mode):
|
def extrema(mode):
|
||||||
return hopper(mode).getextrema()
|
return hopper(mode).getextrema()
|
||||||
|
|
||||||
|
@ -14,16 +12,13 @@ class TestImageGetExtrema(PillowTestCase):
|
||||||
self.assertEqual(extrema("I"), (0, 255))
|
self.assertEqual(extrema("I"), (0, 255))
|
||||||
self.assertEqual(extrema("F"), (0, 255))
|
self.assertEqual(extrema("F"), (0, 255))
|
||||||
self.assertEqual(extrema("P"), (0, 225)) # fixed palette
|
self.assertEqual(extrema("P"), (0, 225)) # fixed palette
|
||||||
self.assertEqual(
|
self.assertEqual(extrema("RGB"), ((0, 255), (0, 255), (0, 255)))
|
||||||
extrema("RGB"), ((0, 255), (0, 255), (0, 255)))
|
self.assertEqual(extrema("RGBA"), ((0, 255), (0, 255), (0, 255), (255, 255)))
|
||||||
self.assertEqual(
|
self.assertEqual(extrema("CMYK"), ((0, 255), (0, 255), (0, 255), (0, 0)))
|
||||||
extrema("RGBA"), ((0, 255), (0, 255), (0, 255), (255, 255)))
|
|
||||||
self.assertEqual(
|
|
||||||
extrema("CMYK"), ((0, 255), (0, 255), (0, 255), (0, 0)))
|
|
||||||
self.assertEqual(extrema("I;16"), (0, 255))
|
self.assertEqual(extrema("I;16"), (0, 255))
|
||||||
|
|
||||||
def test_true_16(self):
|
def test_true_16(self):
|
||||||
im = Image.open("Tests/images/16_bit_noise.tif")
|
im = Image.open("Tests/images/16_bit_noise.tif")
|
||||||
self.assertEqual(im.mode, 'I;16')
|
self.assertEqual(im.mode, "I;16")
|
||||||
extrema = im.getextrema()
|
extrema = im.getextrema()
|
||||||
self.assertEqual(extrema, (106, 285))
|
self.assertEqual(extrema, (106, 285))
|
||||||
|
|
|
@ -3,7 +3,6 @@ from PIL._util import py3
|
||||||
|
|
||||||
|
|
||||||
class TestImageGetIm(PillowTestCase):
|
class TestImageGetIm(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
type_repr = repr(type(im.getim()))
|
type_repr = repr(type(im.getim()))
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user