Merge pull request #3909 from hugovk/run-black

Format code with Black
This commit is contained in:
Hugo 2019-06-22 06:46:15 +03:00 committed by GitHub
commit f5cd8b4b0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
175 changed files with 5131 additions and 4477 deletions

View File

@ -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)

View File

@ -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()

View File

@ -2,6 +2,7 @@ from . import helper
import timeit import timeit
import sys import sys
sys.path.insert(0, ".") sys.path.insert(0, ".")

View File

@ -12,5 +12,5 @@ class TestFliOverflow(PillowTestCase):
im.load() im.load()
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -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")))

View File

@ -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()

View File

@ -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"))
)

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -15,5 +15,5 @@ class TestLibtiffSegfault(PillowTestCase):
im.load() im.load()
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -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()

View File

@ -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):

View File

@ -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"):

View File

@ -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

View File

@ -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.

View File

@ -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")

View File

@ -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))

View File

@ -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,

View File

@ -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

View File

@ -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'}) )

View File

@ -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))

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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",
)

View File

@ -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:

View File

@ -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) )

View File

@ -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)

View 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)

View 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)

View File

@ -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)

View File

@ -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"

View File

@ -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))

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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) )

View File

@ -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)

View File

@ -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)

View File

@ -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"))

View File

@ -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()

View File

@ -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:

View File

@ -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

View File

@ -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"
)

View File

@ -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)

View File

@ -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

View File

@ -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)

View 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:

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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)

View 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

View File

@ -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")

View File

@ -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):

View File

@ -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")

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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.

View File

@ -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"

View File

@ -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)

View File

@ -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:

View File

@ -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()

View File

@ -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"

View File

@ -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))

View File

@ -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)

View File

@ -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))

View File

@ -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

View File

@ -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
)

View 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:

View 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)

View File

@ -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"))

View File

@ -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",
)

View File

@ -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))

View File

@ -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",),
)

View File

@ -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)

View File

@ -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 """

View File

@ -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

View File

@ -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)

View File

@ -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))

View File

@ -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()

View File

@ -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)]),
) )

View File

@ -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())

View File

@ -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"))

View File

@ -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"))

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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))

View File

@ -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