Merge branch 'master' into master

This commit is contained in:
Andrew Murray 2019-06-29 22:59:17 +10:00 committed by GitHub
commit c3e982e0c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
364 changed files with 10412 additions and 7641 deletions

View File

@ -34,6 +34,4 @@ The best reproductions are self-contained scripts with minimal dependencies. If
## Security vulnerabilities
To report sensitive vulnerability information, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
If your organisation/employer is a distributor of Pillow and would like advance notification of security-related bugs, please let us know your preferred contact method.
Please see our [security policy](https://github.com/python-pillow/Pillow/blob/master/.github/SECURITY.md).

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
tidelift: pypi/pillow

View File

@ -1,19 +0,0 @@
### What did you do?
### What did you expect to happen?
### What actually happened?
### What are your OS, Python and Pillow versions?
* OS:
* Python:
* Pillow:
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.
The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as plone, Django, or buildout, try to replicate the issue just using Pillow.
```python
code goes here
```

59
.github/ISSUE_TEMPLATE/ISSUE_REPORT.md vendored Normal file
View File

@ -0,0 +1,59 @@
---
name: Issue report
about: Create a report to help us improve Pillow
---
<!--
Thank you for reporting an issue.
Follow these guidelines to ensure your issue is handled properly.
If you have a ...
1. General question: consider asking the question on Stack Overflow
with the python-imaging-library tag:
* https://stackoverflow.com/questions/tagged/python-imaging-library
Do not ask a question in both places.
If you think you have found a bug or have an unexplained exception
then file a bug report here.
2. Bug report: include a self-contained, copy-pastable example that
generates the issue if possible. Be concise with code posted.
Guidelines on how to provide a good bug report:
* https://stackoverflow.com/help/mcve
Bug reports which follow these guidelines are easier to diagnose,
and are often handled much more quickly.
3. Feature request: do a quick search of existing issues
to make sure this has not been asked before.
We know asking good questions takes effort, and we appreciate your time.
Thank you.
-->
### What did you do?
### What did you expect to happen?
### What actually happened?
### What are your OS, Python and Pillow versions?
* OS:
* Python:
* Pillow:
<!--
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.
The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as Plone, Django, or Buildout, try to replicate the issue just using Pillow.
-->
```python
code goes here
```

5
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,5 @@
# Security policy
To report sensitive vulnerability information, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
If your organisation/employer is a distributor of Pillow and would like advance notification of security-related bugs, please let us know your preferred contact method.

3
.gitignore vendored
View File

@ -67,6 +67,9 @@ docs/_build/
\#*#
.#*
#VS Code
.vscode
#Komodo
*.komodoproject

View File

@ -16,9 +16,9 @@ matrix:
- python: "3.6"
name: "Lint"
env: LINT="true"
- python: "pypy2.7-6.0"
- python: "pypy"
name: "PyPy2 Xenial"
- python: "pypy3.5-6.0"
- python: "pypy3"
name: "PyPy3 Xenial"
- python: '3.7'
name: "3.7 Xenial"
@ -44,8 +44,8 @@ matrix:
- env: DOCKER="centos-7-amd64" DOCKER_TAG="master"
- env: DOCKER="amazon-1-amd64" DOCKER_TAG="master"
- env: DOCKER="amazon-2-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-28-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-29-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-30-amd64" DOCKER_TAG="master"
services:
- docker

View File

@ -7,7 +7,7 @@ make clean
make install-coverage
python selftest.py
python -m pytest -vx --cov PIL --cov-report term Tests
python -m pytest -v -x --cov PIL --cov-report term Tests
pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd

View File

@ -2,6 +2,96 @@
Changelog (Pillow)
==================
6.1.0 (unreleased)
------------------
- Fixed crash when loading non-font bytes #3912
[radarhere]
- Fix SPARC memory alignment issues in Pack/Unpack functions #3858
[kulikjak]
- Added CMYK;16B and CMYK;16N unpackers #3913
[radarhere]
- Fixed bugs in calculating text size #3864
[radarhere]
- Add __main__.py to output basic format and support information #3870
[jdufresne]
- Added variation font support #3802
[radarhere]
- Do not down-convert if image is LA when showing with PNG format #3869
[radarhere]
- Improve handling of PSD frames #3759
[radarhere]
- Improved ICO and ICNS loading #3897
[radarhere]
- Changed Preview application path so that it is no longer static #3896
[radarhere]
- Corrected ttb text positioning #3856
[radarhere]
- Handle unexpected ICO image sizes #3836
[radarhere]
- Fixed bits value for RGB;16N unpackers #3837
[kkopachev]
- Travis CI: Add Fedora 30, remove Fedora 28 #3821
[hugovk]
- Added reading of CMYK;16L TIFF images #3817
[radarhere]
- Fixed dimensions of 1-bit PDFs #3827
[radarhere]
- Fixed opening mmap image through Path on Windows #3825
[radarhere]
- Fixed ImageDraw arc gaps #3824
[radarhere]
- Expand GIF to include frames with extents outside the image size #3822
[radarhere]
- Fixed ImageTk getimage #3814
[radarhere]
- Fixed bug in decoding large images #3791
[radarhere]
- Fixed reading APP13 marker without Photoshop data #3771
[radarhere]
- Added option to include layered windows in ImageGrab.grab on Windows #3808
[radarhere]
- Detect libimagequant when installed by pacman on MingW #3812
[radarhere]
- Fixed raqm layout bug #3787
[radarhere]
- Fixed loading font with non-Unicode path on Windows #3785
[radarhere]
- Travis CI: Upgrade PyPy from 6.0.0 to 7.1.1 #3783
[hugovk, johnthagen]
- Depends: Updated openjpeg to 2.3.1 #3794, raqm to 0.7.0 #3877, libimagequant to 2.12.3 #3889
[radarhere]
- Fix numpy bool bug #3790
[radarhere]
6.0.0 (2019-04-01)
------------------
@ -1408,7 +1498,7 @@ Changelog (Pillow)
- Test: Faster assert_image_similar #2279
[homm]
- Removed depreciated internal "stretch" method #2276
- Removed deprecated internal "stretch" method #2276
[homm]
- Removed the handles_eof flag in decode.c #2223

View File

@ -4,7 +4,7 @@ Pillow
Python Imaging Library (Fork)
-----------------------------
Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. As of 2019, Pillow development is `supported by Tidelift <https://tidelift.com/subscription/pkg/pypi-pillow>`_.
.. start-badges

View File

@ -4,5 +4,5 @@ from PIL import Image
import sys
if sys.maxsize < 2**32:
im = Image.new('L', (999999, 999999), 0)
if sys.maxsize < 2 ** 32:
im = Image.new("L", (999999, 999999), 0)

View File

@ -26,18 +26,21 @@ def timer(func, label, *args):
starttime = time.time()
for x in range(iterations):
func(*args)
if time.time()-starttime > 10:
print("%s: breaking at %s iterations, %.6f per iteration" % (
label, x+1, (time.time()-starttime)/(x+1.0)))
if time.time() - starttime > 10:
print(
"%s: breaking at %s iterations, %.6f per iteration"
% (label, x + 1, (time.time() - starttime) / (x + 1.0))
)
break
if x == iterations-1:
if x == iterations - 1:
endtime = time.time()
print("%s: %.4f s %.6f per iteration" % (
label, endtime-starttime, (endtime-starttime)/(x+1.0)))
print(
"%s: %.4f s %.6f per iteration"
% (label, endtime - starttime, (endtime - starttime) / (x + 1.0))
)
class BenchCffiAccess(PillowTestCase):
def test_direct(self):
im = hopper()
im.load()
@ -48,11 +51,11 @@ class BenchCffiAccess(PillowTestCase):
self.assertEqual(caccess[(0, 0)], access[(0, 0)])
print("Size: %sx%s" % im.size)
timer(iterate_get, 'PyAccess - get', im.size, access)
timer(iterate_set, 'PyAccess - set', im.size, access)
timer(iterate_get, 'C-api - get', im.size, caccess)
timer(iterate_set, 'C-api - set', im.size, caccess)
timer(iterate_get, "PyAccess - get", im.size, access)
timer(iterate_set, "PyAccess - set", im.size, access)
timer(iterate_get, "C-api - get", im.size, caccess)
timer(iterate_set, "C-api - set", im.size, caccess)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

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

View File

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

View File

@ -6,7 +6,6 @@ from PIL._util import py3
from io import BytesIO
if py3:
Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00',
'latin-1')))
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00", "latin-1")))
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
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
class TestImagingLeaks(PillowTestCase):
def _get_mem_usage(self):
from resource import getpagesize, getrusage, RUSAGE_SELF
mem = getrusage(RUSAGE_SELF).ru_maxrss
return mem * getpagesize() / 1024 / 1024
@ -25,20 +25,22 @@ class TestImagingLeaks(PillowTestCase):
if i < min_iterations:
mem_limit = mem + 1
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)
def test_leak_putdata(self):
im = Image.new('RGB', (25, 25))
self._test_leak(min_iterations, max_iterations,
im.putdata, im.getdata())
im = Image.new("RGB", (25, 25))
self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
def test_leak_getlist(self):
im = Image.new('P', (25, 25))
self._test_leak(min_iterations, max_iterations,
# Pass a new list at each iteration.
lambda: im.point(range(256)))
im = Image.new("P", (25, 25))
self._test_leak(
min_iterations,
max_iterations,
# Pass a new list at each iteration.
lambda: im.point(range(256)),
)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@ -6,10 +6,16 @@ from PIL._util import py3
from io import BytesIO
if py3:
Image.open(BytesIO(bytes(
'\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang',
'latin-1')))
Image.open(
BytesIO(
bytes(
"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang",
"latin-1",
)
)
)
else:
Image.open(BytesIO(bytes(
'\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang')))
Image.open(
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
# Limits for testing the leak
mem_limit = 1024*1048576
stack_size = 8*1048576
iterations = int((mem_limit/stack_size)*2)
mem_limit = 1024 * 1048576
stack_size = 8 * 1048576
iterations = int((mem_limit / stack_size) * 2)
codecs = dir(Image.core)
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):
def setUp(self):
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):
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
for _ in range(iterations):
@ -27,6 +28,7 @@ class TestJpegLeaks(PillowTestCase):
def test_leak_save(self):
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
for _ in range(iterations):
@ -38,5 +40,5 @@ class TestJpegLeaks(PillowTestCase):
test_output.read()
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@ -5,11 +5,11 @@ from .helper import unittest, PillowTestCase
class TestJ2kEncodeOverflow(PillowTestCase):
def test_j2k_overflow(self):
im = Image.new('RGBA', (1024, 131584))
target = self.tempfile('temp.jpc')
im = Image.new("RGBA", (1024, 131584))
target = self.tempfile("temp.jpc")
with self.assertRaises(IOError):
im.save(target)
if __name__ == '__main__':
if __name__ == "__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):
"""
@ -74,9 +74,11 @@ post-patch:
"""
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
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
@ -85,9 +87,14 @@ post-patch:
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
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
18 21 26 66 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
""".split(None)]
""".split(
None
)
]
qtables = [standard_l_qtable,
standard_chrominance_qtable]
qtables = [standard_l_qtable, standard_chrominance_qtable]
for _ in range(iterations):
test_output = BytesIO()
@ -161,8 +170,8 @@ post patch:
0 11.33
"""
im = hopper('RGB')
exif = b'12345678'*4096
im = hopper("RGB")
exif = b"12345678" * 4096
for _ in range(iterations):
test_output = BytesIO()
@ -195,12 +204,12 @@ base case:
0 +----------------------------------------------------------------------->Gi
0 7.882
"""
im = hopper('RGB')
im = hopper("RGB")
for _ in range(iterations):
test_output = BytesIO()
im.save(test_output, "JPEG")
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@ -12,16 +12,21 @@ from .helper import unittest, PillowTestCase
# 2.7 and 3.2.
from PIL import Image
try:
import numpy
except ImportError:
numpy = None
YDIM = 32769
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):
def _write_png(self, xdim, ydim):
f = self.tempfile('temp.png')
im = Image.new('L', (xdim, ydim), 0)
f = self.tempfile("temp.png")
im = Image.new("L", (xdim, ydim), 0)
im.save(f)
def test_large(self):
@ -32,6 +37,11 @@ class LargeMemoryTest(PillowTestCase):
"""failed prepatch"""
self._write_png(XDIM, XDIM)
@unittest.skipIf(numpy is None, "Numpy is not installed")
def test_size_greater_than_int(self):
arr = numpy.ndarray(shape=(16394, 16394))
Image.fromarray(arr)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@ -11,6 +11,7 @@ from .helper import unittest, PillowTestCase
# Raspberry Pis).
from PIL import Image
try:
import numpy as np
except ImportError:
@ -20,14 +21,13 @@ YDIM = 32769
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):
def _write_png(self, xdim, ydim):
dtype = np.uint8
a = np.zeros((xdim, ydim), dtype=dtype)
f = self.tempfile('temp.png')
im = Image.fromarray(a, 'L')
f = self.tempfile("temp.png")
im = Image.fromarray(a, "L")
im.save(f)
def test_large(self):
@ -39,5 +39,5 @@ class LargeMemoryNumpyTest(PillowTestCase):
self._write_png(XDIM, XDIM)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

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

View File

@ -17,10 +17,10 @@ class TestPngDos(PillowTestCase):
ImageFile.LOAD_TRUNCATED_IMAGES = False
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():
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):
@ -32,20 +32,20 @@ class TestPngDos(PillowTestCase):
return
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):
im = Image.new('L', (1, 1))
compressed_data = zlib.compress(b'a'*1024*1023)
im = Image.new("L", (1, 1))
compressed_data = zlib.compress(b"a" * 1024 * 1023)
info = PngImagePlugin.PngInfo()
for x in range(64):
info.add_text('t%s' % x, compressed_data, zip=True)
info.add_itxt('i%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)
b = BytesIO()
im.save(b, 'PNG', pnginfo=info)
im.save(b, "PNG", pnginfo=info)
b.seek(0)
try:
@ -57,9 +57,10 @@ class TestPngDos(PillowTestCase):
total_len = 0
for txt in im2.text.values():
total_len += len(txt)
self.assertLess(total_len, 64*1024*1024,
"Total text chunks greater than 64M")
self.assertLess(
total_len, 64 * 1024 * 1024, "Total text chunks greater than 64M"
)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,13 +1,13 @@
NotoNastaliqUrdu-Regular.ttf:
NotoNastaliqUrdu-Regular.ttf, from https://github.com/googlei18n/noto-fonts
NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/
AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype
TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny
ArefRuqaa-Regular.ttf, from https://github.com/google/fonts/tree/master/ofl/arefruqaa
(from https://github.com/googlei18n/noto-fonts)
All Noto fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to.
All of the above fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to.
10x20-ISO8859-1.pcf
(from https://packages.ubuntu.com/xenial/xfonts-base)
10x20-ISO8859-1.pcf, from https://packages.ubuntu.com/xenial/xfonts-base
"Public domain font. Share and enjoy."

Binary file not shown.

BIN
Tests/fonts/TINY5x3GX.ttf Executable file

Binary file not shown.

View File

@ -11,12 +11,13 @@ from PIL import Image, ImageMath
from PIL._util import py3
import logging
logger = logging.getLogger(__name__)
HAS_UPLOADER = False
if os.environ.get('SHOW_ERRORS', None):
if os.environ.get("SHOW_ERRORS", None):
# local img.show for errors.
HAS_UPLOADER = True
@ -25,9 +26,12 @@ if os.environ.get('SHOW_ERRORS', None):
def upload(self, a, b):
a.show()
b.show()
else:
try:
import test_image_results
HAS_UPLOADER = True
except ImportError:
pass
@ -35,19 +39,18 @@ else:
def convert_to_comparable(a, b):
new_a, new_b = a, b
if a.mode == 'P':
new_a = Image.new('L', a.size)
new_b = Image.new('L', b.size)
if a.mode == "P":
new_a = Image.new("L", a.size)
new_b = Image.new("L", b.size)
new_a.putdata(a.getdata())
new_b.putdata(b.getdata())
elif a.mode == 'I;16':
new_a = a.convert('I')
new_b = b.convert('I')
elif a.mode == "I;16":
new_a = a.convert("I")
new_b = b.convert("I")
return new_a, new_b
class PillowTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
# 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):
try:
self.assertEqual(
len(a), len(b),
msg or "got length %s, expected %s" % (len(a), len(b)))
len(a), len(b), msg or "got length %s, expected %s" % (len(a), len(b))
)
self.assertTrue(
all(x == y for x, y in zip(a, b)),
msg or "got %s, expected %s" % (a, b))
all(x == y for x, y in zip(a, b)), msg or "got %s, expected %s" % (a, b)
)
except Exception:
self.assertEqual(a, b, msg)
def assert_image(self, im, mode, size, msg=None):
if mode is not None:
self.assertEqual(
im.mode, mode,
msg or "got mode %r, expected %r" % (im.mode, mode))
im.mode, mode, msg or "got mode %r, expected %r" % (im.mode, mode)
)
if size is not None:
self.assertEqual(
im.size, size,
msg or "got size %r, expected %r" % (im.size, size))
im.size, size, msg or "got size %r, expected %r" % (im.size, size)
)
def assert_image_equal(self, a, b, msg=None):
self.assertEqual(
a.mode, b.mode,
msg or "got mode %r, expected %r" % (a.mode, b.mode))
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
)
self.assertEqual(
a.size, b.size,
msg or "got size %r, expected %r" % (a.size, b.size))
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
)
if a.tobytes() != b.tobytes():
if HAS_UPLOADER:
try:
@ -120,26 +123,28 @@ class PillowTestCase(unittest.TestCase):
def assert_image_similar(self, a, b, epsilon, msg=None):
epsilon = float(epsilon)
self.assertEqual(
a.mode, b.mode,
msg or "got mode %r, expected %r" % (a.mode, b.mode))
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
)
self.assertEqual(
a.size, b.size,
msg or "got size %r, expected %r" % (a.size, b.size))
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
)
a, b = convert_to_comparable(a, b)
diff = 0
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()))
ave_diff = float(diff)/(a.size[0]*a.size[1])
ave_diff = float(diff) / (a.size[0] * a.size[1])
try:
self.assertGreaterEqual(
epsilon, ave_diff,
(msg or '') +
" average pixel value difference %.4f > epsilon %.4f" % (
ave_diff, epsilon))
epsilon,
ave_diff,
(msg or "")
+ " average pixel value difference %.4f > epsilon %.4f"
% (ave_diff, epsilon),
)
except Exception as e:
if HAS_UPLOADER:
try:
@ -149,8 +154,7 @@ class PillowTestCase(unittest.TestCase):
pass
raise e
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None,
mode=None):
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, mode=None):
with Image.open(filename) as img:
if mode:
img = img.convert(mode)
@ -168,9 +172,9 @@ class PillowTestCase(unittest.TestCase):
# Verify some things.
if warn_class is None:
self.assertEqual(len(w), 0,
"Expected no warnings, got %s" %
[v.category for v in w])
self.assertEqual(
len(w), 0, "Expected no warnings, got %s" % [v.category for v in w]
)
else:
self.assertGreaterEqual(len(w), 1)
found = False
@ -192,27 +196,26 @@ class PillowTestCase(unittest.TestCase):
value = True
for i, target in enumerate(targets):
value *= (target - threshold <= actuals[i] <= target + threshold)
value *= target - threshold <= actuals[i] <= target + threshold
self.assertTrue(value,
msg + ': ' + repr(actuals) + ' != ' + repr(targets))
self.assertTrue(value, msg + ": " + repr(actuals) + " != " + repr(targets))
def skipKnownBadTest(self, msg=None, platform=None,
travis=None, interpreter=None):
def skipKnownBadTest(self, msg=None, platform=None, travis=None, interpreter=None):
# Skip if platform/travis matches, and
# PILLOW_RUN_KNOWN_BAD is not true in the environment.
if os.environ.get('PILLOW_RUN_KNOWN_BAD', False):
print(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))
return
skip = True
if platform is not None:
skip = sys.platform.startswith(platform)
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:
skip = skip and (interpreter == 'pypy' and
hasattr(sys, 'pypy_version_info'))
skip = skip and (
interpreter == "pypy" and hasattr(sys, "pypy_version_info")
)
if skip:
self.skipTest(msg or "Known Bad Test")
@ -234,7 +237,7 @@ class PillowTestCase(unittest.TestCase):
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):
# requires unix/macOS
iterations = 100 # count
@ -249,8 +252,9 @@ class PillowLeakTestCase(PillowTestCase):
"""
from resource import getrusage, RUSAGE_SELF
mem = getrusage(RUSAGE_SELF).ru_maxrss
if sys.platform == 'darwin':
if sys.platform == "darwin":
# man 2 getrusage:
# ru_maxrss
# This is the maximum resident set size utilized (in bytes).
@ -266,8 +270,8 @@ class PillowLeakTestCase(PillowTestCase):
start_mem = self._get_mem_usage()
for cycle in range(self.iterations):
core()
mem = (self._get_mem_usage() - start_mem)
msg = 'memory usage limit exceeded in iteration %d' % cycle
mem = self._get_mem_usage() - start_mem
msg = "memory usage limit exceeded in iteration %d" % cycle
self.assertLess(mem, self.mem_limit, msg)
@ -281,11 +285,13 @@ if not py3:
def fromstring(data):
from io import BytesIO
return Image.open(BytesIO(data))
def tostring(im, string_format, **options):
from io import BytesIO
out = BytesIO()
im.save(out, string_format, **options)
return out.getvalue()
@ -318,7 +324,8 @@ def command_succeeds(cmd):
command succeeds, or False if an OSError was raised by subprocess.Popen.
"""
import subprocess
with open(os.devnull, 'wb') as f:
with open(os.devnull, "wb") as f:
try:
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)
except OSError:
@ -327,40 +334,41 @@ def command_succeeds(cmd):
def djpeg_available():
return command_succeeds(['djpeg', '-version'])
return command_succeeds(["djpeg", "-version"])
def cjpeg_available():
return command_succeeds(['cjpeg', '-version'])
return command_succeeds(["cjpeg", "-version"])
def netpbm_available():
return (command_succeeds(["ppmquant", "--version"]) and
command_succeeds(["ppmtogif", "--version"]))
return command_succeeds(["ppmquant", "--version"]) and command_succeeds(
["ppmtogif", "--version"]
)
def imagemagick_available():
return IMCONVERT and command_succeeds([IMCONVERT, '-version'])
return IMCONVERT and command_succeeds([IMCONVERT, "-version"])
def on_appveyor():
return 'APPVEYOR' in os.environ
return "APPVEYOR" in os.environ
if sys.platform == 'win32':
IMCONVERT = os.environ.get('MAGICK_HOME', '')
if sys.platform == "win32":
IMCONVERT = os.environ.get("MAGICK_HOME", "")
if IMCONVERT:
IMCONVERT = os.path.join(IMCONVERT, 'convert.exe')
IMCONVERT = os.path.join(IMCONVERT, "convert.exe")
else:
IMCONVERT = 'convert'
IMCONVERT = "convert"
def distro():
if os.path.exists('/etc/os-release'):
with open('/etc/os-release', 'r') as f:
if os.path.exists("/etc/os-release"):
with open("/etc/os-release", "r") as f:
for line in f:
if 'ID=' in line:
return line.strip().split('=')[1]
if "ID=" in line:
return line.strip().split("=")[1]
class cached_property(object):

BIN
Tests/images/app13.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -5,6 +5,7 @@ import os
import traceback
import sys
sys.path.insert(0, ".")
for file in glob.glob("src/PIL/*.py"):

View File

@ -4,21 +4,33 @@ from __future__ import print_function
modes = [
"1",
"L", "LA", "La",
"I", "I;16", "I;16L", "I;16B", "I;32L", "I;32B",
"L",
"LA",
"La",
"I",
"I;16",
"I;16L",
"I;16B",
"I;32L",
"I;32B",
"F",
"P", "PA",
"RGB", "RGBA", "RGBa", "RGBX",
"P",
"PA",
"RGB",
"RGBA",
"RGBa",
"RGBX",
"CMYK",
"YCbCr",
"LAB", "HSV",
]
"LAB",
"HSV",
]
def hash(s, i):
# djb2 hash: multiply by 33 and xor character
for c in s:
i = (((i << 5) + i) ^ ord(c)) & 0xffffffff
i = (((i << 5) + i) ^ ord(c)) & 0xFFFFFFFF
return i

View File

@ -5,7 +5,6 @@ import PIL.Image
class TestSanity(PillowTestCase):
def test_sanity(self):
# Make sure we have the binary extension
@ -13,7 +12,7 @@ class TestSanity(PillowTestCase):
# Create an image and do stuff with it.
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)
# Create images in all remaining major modes.

View File

@ -4,21 +4,20 @@ from PIL import _binary
class TestBinary(PillowTestCase):
def test_standard(self):
self.assertEqual(_binary.i8(b'*'), 42)
self.assertEqual(_binary.o8(42), b'*')
self.assertEqual(_binary.i8(b"*"), 42)
self.assertEqual(_binary.o8(42), b"*")
def test_little_endian(self):
self.assertEqual(_binary.i16le(b'\xff\xff\x00\x00'), 65535)
self.assertEqual(_binary.i32le(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.o16le(65535), b'\xff\xff')
self.assertEqual(_binary.o32le(65535), b'\xff\xff\x00\x00')
self.assertEqual(_binary.o16le(65535), b"\xff\xff")
self.assertEqual(_binary.o32le(65535), b"\xff\xff\x00\x00")
def test_big_endian(self):
self.assertEqual(_binary.i16be(b'\x00\x00\xff\xff'), 0)
self.assertEqual(_binary.i32be(b'\x00\x00\xff\xff'), 65535)
self.assertEqual(_binary.i16be(b"\x00\x00\xff\xff"), 0)
self.assertEqual(_binary.i32be(b"\x00\x00\xff\xff"), 65535)
self.assertEqual(_binary.o16be(65535), b'\xff\xff')
self.assertEqual(_binary.o32be(65535), b'\x00\x00\xff\xff')
self.assertEqual(_binary.o16be(65535), b"\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
import os
base = os.path.join('Tests', 'images', 'bmp')
base = os.path.join("Tests", "images", "bmp")
class TestBmpReference(PillowTestCase):
def get_files(self, d, ext='.bmp'):
return [os.path.join(base, d, f) for f
in os.listdir(os.path.join(base, d)) if ext in f]
def get_files(self, d, ext=".bmp"):
return [
os.path.join(base, d, f)
for f in os.listdir(os.path.join(base, d))
if ext in f
]
def test_bad(self):
""" These shouldn't crash/dos, but they shouldn't return anything
either """
for f in self.get_files('b'):
for f in self.get_files("b"):
def open(f):
try:
im = Image.open(f)
@ -41,13 +44,12 @@ class TestBmpReference(PillowTestCase):
"pal8os2sp.bmp",
"rgb32bf-xbgr.bmp",
]
for f in self.get_files('q'):
for f in self.get_files("q"):
try:
im = Image.open(f)
im.load()
if os.path.basename(f) not in supported:
print("Please add %s to the partially supported"
" bmp specs." % f)
print("Please add %s to the partially supported bmp specs." % f)
except Exception: # as msg:
if os.path.basename(f) in supported:
raise
@ -57,49 +59,52 @@ class TestBmpReference(PillowTestCase):
html directory that we can compare against. """
# Target files, if they're not just replacing the extension
file_map = {'pal1wb.bmp': 'pal1.png',
'pal4rle.bmp': 'pal4.png',
'pal8-0.bmp': 'pal8.png',
'pal8rle.bmp': 'pal8.png',
'pal8topdown.bmp': 'pal8.png',
'pal8nonsquare.bmp': 'pal8nonsquare-v.png',
'pal8os2.bmp': 'pal8.png',
'pal8os2sp.bmp': 'pal8.png',
'pal8os2v2.bmp': 'pal8.png',
'pal8os2v2-16.bmp': 'pal8.png',
'pal8v4.bmp': 'pal8.png',
'pal8v5.bmp': 'pal8.png',
'rgb16-565pal.bmp': 'rgb16-565.png',
'rgb24pal.bmp': 'rgb24.png',
'rgb32.bmp': 'rgb24.png',
'rgb32bf.bmp': 'rgb24.png'
}
file_map = {
"pal1wb.bmp": "pal1.png",
"pal4rle.bmp": "pal4.png",
"pal8-0.bmp": "pal8.png",
"pal8rle.bmp": "pal8.png",
"pal8topdown.bmp": "pal8.png",
"pal8nonsquare.bmp": "pal8nonsquare-v.png",
"pal8os2.bmp": "pal8.png",
"pal8os2sp.bmp": "pal8.png",
"pal8os2v2.bmp": "pal8.png",
"pal8os2v2-16.bmp": "pal8.png",
"pal8v4.bmp": "pal8.png",
"pal8v5.bmp": "pal8.png",
"rgb16-565pal.bmp": "rgb16-565.png",
"rgb24pal.bmp": "rgb24.png",
"rgb32.bmp": "rgb24.png",
"rgb32bf.bmp": "rgb24.png",
}
def get_compare(f):
name = os.path.split(f)[1]
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]
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:
im = Image.open(f)
im.load()
compare = Image.open(get_compare(f))
compare.load()
if im.mode == 'P':
if im.mode == "P":
# assert image similar doesn't really work
# with paletized image, since the palette might
# be differently ordered for an equivalent image.
im = im.convert('RGBA')
compare = im.convert('RGBA')
im = im.convert("RGBA")
compare = im.convert("RGBA")
self.assert_image_similar(im, compare, 5)
except Exception as msg:
# there are three here that are unsupported:
unsupported = (os.path.join(base, 'g', 'rgb32bf.bmp'),
os.path.join(base, 'g', 'pal8rle.bmp'),
os.path.join(base, 'g', 'pal4rle.bmp'))
unsupported = (
os.path.join(base, "g", "rgb32bf.bmp"),
os.path.join(base, "g", "pal8rle.bmp"),
os.path.join(base, "g", "pal4rle.bmp"),
)
if f not in unsupported:
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))
# fmt: off
sample.putdata(sum([
[210, 50, 20, 10, 220, 230, 80],
[190, 210, 20, 180, 170, 40, 110],
@ -11,10 +12,10 @@ sample.putdata(sum([
[220, 40, 230, 80, 130, 250, 40],
[250, 0, 80, 30, 60, 20, 110],
], []))
# fmt: on
class TestBoxBlurApi(PillowTestCase):
def test_imageops_box_blur(self):
i = sample.filter(ImageFilter.BoxBlur(1))
self.assertEqual(i.mode, sample.mode)
@ -23,7 +24,6 @@ class TestBoxBlurApi(PillowTestCase):
class TestBoxBlur(PillowTestCase):
def box_blur(self, image, radius=1, n=1):
return image._new(image.im.box_blur(radius, n))
@ -32,8 +32,7 @@ class TestBoxBlur(PillowTestCase):
for data_row in data:
im_row = [next(it) for _ in range(im.size[0])]
if any(
abs(data_v - im_v) > delta
for data_v, im_v in zip(data_row, im_row)
abs(data_v - im_v) > delta for data_v, im_v in zip(data_row, im_row)
):
self.assertEqual(im_row, data_row)
self.assertRaises(StopIteration, next, it)
@ -41,7 +40,7 @@ class TestBoxBlur(PillowTestCase):
def assertBlur(self, im, radius, data, passes=1, delta=0):
# check grayscale image
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():
self.assertImage(band, data, delta)
@ -61,110 +60,135 @@ class TestBoxBlur(PillowTestCase):
def test_radius_0(self):
self.assertBlur(
sample, 0,
sample,
0,
[
# fmt: off
[210, 50, 20, 10, 220, 230, 80],
[190, 210, 20, 180, 170, 40, 110],
[120, 210, 250, 60, 220, 0, 220],
[220, 40, 230, 80, 130, 250, 40],
[250, 0, 80, 30, 60, 20, 110],
]
# fmt: on
],
)
def test_radius_0_02(self):
self.assertBlur(
sample, 0.02,
sample,
0.02,
[
# fmt: off
[206, 55, 20, 17, 215, 223, 83],
[189, 203, 31, 171, 169, 46, 110],
[125, 206, 241, 69, 210, 13, 210],
[215, 49, 221, 82, 131, 235, 48],
[244, 7, 80, 32, 60, 27, 107],
# fmt: on
],
delta=2,
)
def test_radius_0_05(self):
self.assertBlur(
sample, 0.05,
sample,
0.05,
[
# fmt: off
[202, 62, 22, 27, 209, 215, 88],
[188, 194, 44, 161, 168, 56, 111],
[131, 201, 229, 81, 198, 31, 198],
[209, 62, 209, 86, 133, 216, 59],
[237, 17, 80, 36, 60, 35, 103],
# fmt: on
],
delta=2,
)
def test_radius_0_1(self):
self.assertBlur(
sample, 0.1,
sample,
0.1,
[
# fmt: off
[196, 72, 24, 40, 200, 203, 93],
[187, 183, 62, 148, 166, 68, 111],
[139, 193, 213, 96, 182, 54, 182],
[201, 78, 193, 91, 133, 191, 73],
[227, 31, 80, 42, 61, 47, 99],
# fmt: on
],
delta=1,
)
def test_radius_0_5(self):
self.assertBlur(
sample, 0.5,
sample,
0.5,
[
# fmt: off
[176, 101, 46, 83, 163, 165, 111],
[176, 149, 108, 122, 144, 120, 117],
[164, 171, 159, 141, 134, 119, 129],
[170, 136, 133, 114, 116, 124, 109],
[184, 95, 72, 70, 69, 81, 89],
# fmt: on
],
delta=1,
)
def test_radius_1(self):
self.assertBlur(
sample, 1,
sample,
1,
[
# fmt: off
[170, 109, 63, 97, 146, 153, 116],
[168, 142, 112, 128, 126, 143, 121],
[169, 166, 142, 149, 126, 131, 114],
[159, 156, 109, 127, 94, 117, 112],
[164, 128, 63, 87, 76, 89, 90],
# fmt: on
],
delta=1,
)
def test_radius_1_5(self):
self.assertBlur(
sample, 1.5,
sample,
1.5,
[
# fmt: off
[155, 120, 105, 112, 124, 137, 130],
[160, 136, 124, 125, 127, 134, 130],
[166, 147, 130, 125, 120, 121, 119],
[168, 145, 119, 109, 103, 105, 110],
[168, 134, 96, 85, 85, 89, 97],
# fmt: on
],
delta=1,
)
def test_radius_bigger_then_half(self):
self.assertBlur(
sample, 3,
sample,
3,
[
# fmt: off
[144, 145, 142, 128, 114, 115, 117],
[148, 145, 137, 122, 109, 111, 112],
[152, 145, 131, 117, 103, 107, 108],
[156, 144, 126, 111, 97, 102, 103],
[160, 144, 121, 106, 92, 98, 99],
# fmt: on
],
delta=1,
)
def test_radius_bigger_then_width(self):
self.assertBlur(
sample, 10,
sample,
10,
[
[158, 153, 147, 141, 135, 129, 123],
[159, 153, 147, 141, 136, 130, 124],
@ -175,9 +199,10 @@ class TestBoxBlur(PillowTestCase):
delta=0,
)
def test_exteme_large_radius(self):
def test_extreme_large_radius(self):
self.assertBlur(
sample, 600,
sample,
600,
[
[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):
self.assertBlur(
sample, 1,
sample,
1,
[
# fmt: off
[153, 123, 102, 109, 132, 135, 129],
[159, 138, 123, 121, 133, 131, 126],
[162, 147, 136, 124, 127, 121, 121],
[159, 140, 125, 108, 111, 106, 108],
[154, 126, 105, 87, 94, 93, 97],
# fmt: on
],
passes=2,
delta=1,
@ -204,13 +232,16 @@ class TestBoxBlur(PillowTestCase):
def test_three_passes(self):
self.assertBlur(
sample, 1,
sample,
1,
[
# fmt: off
[146, 131, 116, 118, 126, 131, 130],
[151, 138, 125, 123, 126, 128, 127],
[154, 143, 129, 123, 120, 120, 119],
[152, 139, 122, 113, 108, 108, 108],
[148, 132, 112, 102, 97, 99, 100],
# fmt: on
],
passes=3,
delta=1,

View File

@ -20,185 +20,197 @@ class TestColorLut3DCoreAPI(PillowTestCase):
table = [
[
r / float(size1D-1) if size1D != 1 else 0,
g / float(size2D-1) if size2D != 1 else 0,
b / float(size3D-1) if size3D != 1 else 0,
r / float(size1D-1) if size1D != 1 else 0,
g / float(size2D-1) if size2D != 1 else 0,
r / float(size1D - 1) if size1D != 1 else 0,
g / float(size2D - 1) if size2D != 1 else 0,
b / float(size3D - 1) if size3D != 1 else 0,
r / float(size1D - 1) if size1D != 1 else 0,
g / float(size2D - 1) if size2D != 1 else 0,
][:channels]
for b in range(size3D)
for g in range(size2D)
for r in range(size1D)
]
return (
channels, size1D, size2D, size3D,
[item for sublist in table for item in sublist])
channels,
size1D,
size2D,
size3D,
[item for sublist in table for item in sublist],
)
def test_wrong_args(self):
im = Image.new('RGB', (10, 10), 0)
im = Image.new("RGB", (10, 10), 0)
with self.assertRaisesRegex(ValueError, "filter"):
im.im.color_lut_3d('RGB',
Image.CUBIC,
*self.generate_identity_table(3, 3))
im.im.color_lut_3d("RGB", Image.CUBIC, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "image mode"):
im.im.color_lut_3d('wrong',
Image.LINEAR,
*self.generate_identity_table(3, 3))
im.im.color_lut_3d(
"wrong", Image.LINEAR, *self.generate_identity_table(3, 3)
)
with self.assertRaisesRegex(ValueError, "table_channels"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
*self.generate_identity_table(5, 3))
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(5, 3))
with self.assertRaisesRegex(ValueError, "table_channels"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
*self.generate_identity_table(1, 3))
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(1, 3))
with self.assertRaisesRegex(ValueError, "table_channels"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
*self.generate_identity_table(2, 3))
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(2, 3))
with self.assertRaisesRegex(ValueError, "Table size"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
*self.generate_identity_table(3, (1, 3, 3)))
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (1, 3, 3))
)
with self.assertRaisesRegex(ValueError, "Table size"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
*self.generate_identity_table(3, (66, 3, 3)))
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (66, 3, 3))
)
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
3, 2, 2, 2, [0, 0, 0] * 7)
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 7)
with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"):
im.im.color_lut_3d('RGB',
Image.LINEAR,
3, 2, 2, 2, [0, 0, 0] * 9)
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, 0] * 9)
with self.assertRaises(TypeError):
im.im.color_lut_3d('RGB',
Image.LINEAR,
3, 2, 2, 2, [0, 0, "0"] * 8)
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, [0, 0, "0"] * 8)
with self.assertRaises(TypeError):
im.im.color_lut_3d('RGB',
Image.LINEAR,
3, 2, 2, 2, 16)
im.im.color_lut_3d("RGB", Image.LINEAR, 3, 2, 2, 2, 16)
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,
*self.generate_identity_table(3, 3))
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(3, 3))
im.im.color_lut_3d('CMYK', Image.LINEAR,
*self.generate_identity_table(4, 3))
im.im.color_lut_3d("CMYK", Image.LINEAR, *self.generate_identity_table(4, 3))
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, (2, 3, 3)))
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (2, 3, 3))
)
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, (65, 3, 3)))
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (65, 3, 3))
)
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, (3, 65, 3)))
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (3, 65, 3))
)
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, (3, 3, 65)))
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (3, 3, 65))
)
def test_wrong_mode(self):
with self.assertRaisesRegex(ValueError, "wrong mode"):
im = Image.new('L', (10, 10), 0)
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, 3))
im = Image.new("L", (10, 10), 0)
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "wrong mode"):
im = Image.new('RGB', (10, 10), 0)
im.im.color_lut_3d('L', Image.LINEAR,
*self.generate_identity_table(3, 3))
im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "wrong mode"):
im = Image.new('L', (10, 10), 0)
im.im.color_lut_3d('L', Image.LINEAR,
*self.generate_identity_table(3, 3))
im = Image.new("L", (10, 10), 0)
im.im.color_lut_3d("L", Image.LINEAR, *self.generate_identity_table(3, 3))
with self.assertRaisesRegex(ValueError, "wrong mode"):
im = Image.new('RGB', (10, 10), 0)
im.im.color_lut_3d('RGBA', Image.LINEAR,
*self.generate_identity_table(3, 3))
im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d(
"RGBA", Image.LINEAR, *self.generate_identity_table(3, 3)
)
with self.assertRaisesRegex(ValueError, "wrong mode"):
im = Image.new('RGB', (10, 10), 0)
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(4, 3))
im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d("RGB", Image.LINEAR, *self.generate_identity_table(4, 3))
def test_correct_mode(self):
im = Image.new('RGBA', (10, 10), 0)
im.im.color_lut_3d('RGBA', Image.LINEAR,
*self.generate_identity_table(3, 3))
im = Image.new("RGBA", (10, 10), 0)
im.im.color_lut_3d("RGBA", Image.LINEAR, *self.generate_identity_table(3, 3))
im = Image.new('RGBA', (10, 10), 0)
im.im.color_lut_3d('RGBA', Image.LINEAR,
*self.generate_identity_table(4, 3))
im = Image.new("RGBA", (10, 10), 0)
im.im.color_lut_3d("RGBA", Image.LINEAR, *self.generate_identity_table(4, 3))
im = Image.new('RGB', (10, 10), 0)
im.im.color_lut_3d('HSV', Image.LINEAR,
*self.generate_identity_table(3, 3))
im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d("HSV", Image.LINEAR, *self.generate_identity_table(3, 3))
im = Image.new('RGB', (10, 10), 0)
im.im.color_lut_3d('RGBA', Image.LINEAR,
*self.generate_identity_table(4, 3))
im = Image.new("RGB", (10, 10), 0)
im.im.color_lut_3d("RGBA", Image.LINEAR, *self.generate_identity_table(4, 3))
def test_identities(self):
g = Image.linear_gradient('L')
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180)])
g = Image.linear_gradient("L")
im = Image.merge(
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
)
# Fast test with small cubes
for size in [2, 3, 5, 7, 11, 16, 17]:
self.assert_image_equal(im, im._new(
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, size))))
self.assert_image_equal(
im,
im._new(
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, size)
)
),
)
# Not so fast
self.assert_image_equal(im, im._new(
im.im.color_lut_3d('RGB', Image.LINEAR,
*self.generate_identity_table(3, (2, 2, 65)))))
self.assert_image_equal(
im,
im._new(
im.im.color_lut_3d(
"RGB", Image.LINEAR, *self.generate_identity_table(3, (2, 2, 65))
)
),
)
def test_identities_4_channels(self):
g = Image.linear_gradient('L')
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180)])
g = Image.linear_gradient("L")
im = Image.merge(
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
)
# Red channel copied to alpha
self.assert_image_equal(
Image.merge('RGBA', (im.split()*2)[:4]),
im._new(im.im.color_lut_3d('RGBA', Image.LINEAR,
*self.generate_identity_table(4, 17))))
Image.merge("RGBA", (im.split() * 2)[:4]),
im._new(
im.im.color_lut_3d(
"RGBA", Image.LINEAR, *self.generate_identity_table(4, 17)
)
),
)
def test_copy_alpha_channel(self):
g = Image.linear_gradient('L')
im = Image.merge('RGBA', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180),
g.transpose(Image.ROTATE_270)])
g = Image.linear_gradient("L")
im = Image.merge(
"RGBA",
[
g,
g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180),
g.transpose(Image.ROTATE_270),
],
)
self.assert_image_equal(im, im._new(
im.im.color_lut_3d('RGBA', Image.LINEAR,
*self.generate_identity_table(3, 17))))
self.assert_image_equal(
im,
im._new(
im.im.color_lut_3d(
"RGBA", Image.LINEAR, *self.generate_identity_table(3, 17)
)
),
)
def test_channels_order(self):
g = Image.linear_gradient('L')
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180)])
g = Image.linear_gradient("L")
im = Image.merge(
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
)
# Reverse channels by splitting and using table
# fmt: off
self.assert_image_equal(
Image.merge('RGB', im.split()[::-1]),
im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
@ -209,12 +221,15 @@ class TestColorLut3DCoreAPI(PillowTestCase):
1, 0, 0, 1, 0, 1,
1, 1, 0, 1, 1, 1,
])))
# fmt: on
def test_overflow(self):
g = Image.linear_gradient('L')
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180)])
g = Image.linear_gradient("L")
im = Image.merge(
"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,
3, 2, 2, 2,
[
@ -224,6 +239,7 @@ class TestColorLut3DCoreAPI(PillowTestCase):
-1, -1, 2, 2, -1, 2,
-1, 2, 2, 2, 2, 2,
])).load()
# fmt: on
self.assertEqual(transformed[0, 0], (0, 0, 255))
self.assertEqual(transformed[50, 50], (0, 0, 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[205, 205], (255, 255, 0))
# fmt: off
transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR,
3, 2, 2, 2,
[
@ -242,6 +259,7 @@ class TestColorLut3DCoreAPI(PillowTestCase):
-3, -3, 5, 5, -3, 5,
-3, 5, 5, 5, 5, 5,
])).load()
# fmt: on
self.assertEqual(transformed[0, 0], (0, 0, 255))
self.assertEqual(transformed[50, 50], (0, 0, 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(lut.name, "Color 3D LUT")
# fmt: off
lut = ImageFilter.Color3DLUT((2, 2, 2), [
(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11),
(12, 13, 14), (15, 16, 17), (18, 19, 20), (21, 22, 23)])
# fmt: on
self.assertEqual(tuple(lut.size), (2, 2, 2))
self.assertEqual(lut.table, list(range(24)))
lut = ImageFilter.Color3DLUT((2, 2, 2), [(0, 1, 2, 3)] * 8,
channels=4)
lut = ImageFilter.Color3DLUT((2, 2, 2), [(0, 1, 2, 3)] * 8, channels=4)
self.assertEqual(tuple(lut.size), (2, 2, 2))
self.assertEqual(lut.table, list(range(4)) * 8)
@ -318,7 +337,7 @@ class TestColorLut3DFilter(PillowTestCase):
self.assertEqual(lut.table.shape, (table.size,))
# Check application
Image.new('RGB', (10, 10), 0).filter(lut)
Image.new("RGB", (10, 10), 0).filter(lut)
# Check copy
table[0] = 33
@ -332,40 +351,34 @@ class TestColorLut3DFilter(PillowTestCase):
@unittest.skipIf(numpy is None, "Numpy is not installed")
def test_numpy_formats(self):
g = Image.linear_gradient('L')
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180)])
g = Image.linear_gradient("L")
im = Image.merge(
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
)
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
lambda r, g, b: (r, g, b))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float32)[:-1]
with self.assertRaisesRegex(ValueError, "should have table_channels"):
im.filter(lut)
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
lambda r, g, b: (r, g, b))
lut.table = (numpy.array(lut.table, dtype=numpy.float32)
.reshape((7 * 9 * 11), 3))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float32).reshape((7 * 9 * 11), 3)
with self.assertRaisesRegex(ValueError, "should have table_channels"):
im.filter(lut)
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
lambda r, g, b: (r, g, b))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float16)
self.assert_image_equal(im, im.filter(lut))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
lambda r, g, b: (r, g, b))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float32)
self.assert_image_equal(im, im.filter(lut))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
lambda r, g, b: (r, g, b))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.float64)
self.assert_image_equal(im, im.filter(lut))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11),
lambda r, g, b: (r, g, b))
lut = ImageFilter.Color3DLUT.generate((7, 9, 11), lambda r, g, b: (r, g, b))
lut.table = numpy.array(lut.table, dtype=numpy.int32)
im.filter(lut)
lut.table = numpy.array(lut.table, dtype=numpy.int8)
@ -373,54 +386,65 @@ class TestColorLut3DFilter(PillowTestCase):
def test_repr(self):
lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8)
self.assertEqual(repr(lut),
"<Color3DLUT from list size=2x2x2 channels=3>")
self.assertEqual(repr(lut), "<Color3DLUT from list size=2x2x2 channels=3>")
lut = ImageFilter.Color3DLUT(
(3, 4, 5), array('f', [0, 0, 0, 0] * (3 * 4 * 5)),
channels=4, target_mode='YCbCr', _copy_table=False)
(3, 4, 5),
array("f", [0, 0, 0, 0] * (3 * 4 * 5)),
channels=4,
target_mode="YCbCr",
_copy_table=False,
)
self.assertEqual(
repr(lut),
"<Color3DLUT from array size=3x4x5 channels=4 target_mode=YCbCr>")
repr(lut), "<Color3DLUT from array size=3x4x5 channels=4 target_mode=YCbCr>"
)
class TestGenerateColorLut3D(PillowTestCase):
def test_wrong_channels_count(self):
with self.assertRaisesRegex(ValueError, "3 or 4 output channels"):
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"):
ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b, r))
with self.assertRaisesRegex(ValueError, "should have either channels"):
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):
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
self.assertEqual(tuple(lut.size), (5, 5, 5))
self.assertEqual(lut.name, "Color 3D LUT")
# fmt: off
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,
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):
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(lut.name, "Color 3D LUT")
# fmt: off
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.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):
lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
g = Image.linear_gradient('L')
im = Image.merge('RGB', [g, g.transpose(Image.ROTATE_90),
g.transpose(Image.ROTATE_180)])
g = Image.linear_gradient("L")
im = Image.merge(
"RGB", [g, g.transpose(Image.ROTATE_90), g.transpose(Image.ROTATE_180)]
)
self.assertEqual(im, im.filter(lut))
@ -442,80 +466,96 @@ class TestTransformColorLut3D(PillowTestCase):
def test_target_mode(self):
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))
self.assertEqual(lut.mode, 'HSV')
self.assertEqual(lut.mode, "HSV")
lut = source.transform(lambda r, g, b: (r, g, b), target_mode='RGB')
self.assertEqual(lut.mode, 'RGB')
lut = source.transform(lambda r, g, b: (r, g, b), target_mode="RGB")
self.assertEqual(lut.mode, "RGB")
def test_3_to_3_channels(self):
source = ImageFilter.Color3DLUT.generate(
(3, 4, 5), lambda r, g, b: (r, g, b))
lut = source.transform(lambda r, g, b: (r*r, g*g, b*b))
source = ImageFilter.Color3DLUT.generate((3, 4, 5), lambda r, g, b: (r, g, b))
lut = source.transform(lambda r, g, b: (r * r, g * g, b * b))
self.assertEqual(tuple(lut.size), tuple(source.size))
self.assertEqual(len(lut.table), len(source.table))
self.assertNotEqual(lut.table, source.table)
self.assertEqual(lut.table[0:10], [
0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
self.assertEqual(
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):
source = ImageFilter.Color3DLUT.generate(
(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)
source = ImageFilter.Color3DLUT.generate((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)
self.assertEqual(tuple(lut.size), tuple(source.size))
self.assertNotEqual(len(lut.table), len(source.table))
self.assertNotEqual(lut.table, source.table)
# fmt: off
self.assertEqual(lut.table[0:16], [
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])
# fmt: on
def test_4_to_3_channels(self):
source = ImageFilter.Color3DLUT.generate(
(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)
(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
)
self.assertEqual(tuple(lut.size), tuple(source.size))
self.assertNotEqual(len(lut.table), len(source.table))
self.assertNotEqual(lut.table, source.table)
# fmt: off
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, 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):
source = ImageFilter.Color3DLUT.generate(
(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))
(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))
self.assertEqual(tuple(lut.size), tuple(source.size))
self.assertEqual(len(lut.table), len(source.table))
self.assertNotEqual(lut.table, source.table)
# fmt: off
self.assertEqual(lut.table[0:16], [
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])
# fmt: on
def test_with_normals_3_channels(self):
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(
lambda nr, ng, nb, r, g, b: (nr - r, ng - g, nb - b),
with_normals=True)
lambda nr, ng, nb, r, g, b: (nr - r, ng - g, nb - b), with_normals=True
)
self.assertEqual(tuple(lut.size), tuple(source.size))
self.assertEqual(len(lut.table), len(source.table))
self.assertNotEqual(lut.table, source.table)
# fmt: off
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.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0])
# fmt: on
def test_with_normals_4_channels(self):
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(
lambda nr, ng, nb, r, g, b, a: (nr - r, ng - g, nb - b, a-0.5),
with_normals=True)
lambda nr, ng, nb, r, g, b, a: (nr - r, ng - g, nb - b, a - 0.5),
with_normals=True,
)
self.assertEqual(tuple(lut.size), tuple(source.size))
self.assertEqual(len(lut.table), len(source.table))
self.assertNotEqual(lut.table, source.table)
# fmt: off
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.0, 0.16, 0.0, 0.5])
# fmt: on

View File

@ -6,39 +6,39 @@ from .helper import unittest, PillowTestCase
from PIL import Image
is_pypy = hasattr(sys, 'pypy_version_info')
is_pypy = hasattr(sys, "pypy_version_info")
class TestCoreStats(PillowTestCase):
def test_get_stats(self):
# Create at least one image
Image.new('RGB', (10, 10))
Image.new("RGB", (10, 10))
stats = Image.core.get_stats()
self.assertIn('new_count', stats)
self.assertIn('reused_blocks', stats)
self.assertIn('freed_blocks', stats)
self.assertIn('allocated_blocks', stats)
self.assertIn('reallocated_blocks', stats)
self.assertIn('blocks_cached', stats)
self.assertIn("new_count", stats)
self.assertIn("reused_blocks", stats)
self.assertIn("freed_blocks", stats)
self.assertIn("allocated_blocks", stats)
self.assertIn("reallocated_blocks", stats)
self.assertIn("blocks_cached", stats)
def test_reset_stats(self):
Image.core.reset_stats()
stats = Image.core.get_stats()
self.assertEqual(stats['new_count'], 0)
self.assertEqual(stats['reused_blocks'], 0)
self.assertEqual(stats['freed_blocks'], 0)
self.assertEqual(stats['allocated_blocks'], 0)
self.assertEqual(stats['reallocated_blocks'], 0)
self.assertEqual(stats['blocks_cached'], 0)
self.assertEqual(stats["new_count"], 0)
self.assertEqual(stats["reused_blocks"], 0)
self.assertEqual(stats["freed_blocks"], 0)
self.assertEqual(stats["allocated_blocks"], 0)
self.assertEqual(stats["reallocated_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 0)
class TestCoreMemory(PillowTestCase):
def tearDown(self):
# Restore default values
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.clear_cache()
@ -54,7 +54,7 @@ class TestCoreMemory(PillowTestCase):
self.assertEqual(alignment, i)
# 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, -1)
@ -66,13 +66,13 @@ class TestCoreMemory(PillowTestCase):
self.assertGreaterEqual(block_size, 4096)
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)
block_size = Image.core.get_block_size()
self.assertEqual(block_size, i)
# 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, -1)
@ -82,13 +82,13 @@ class TestCoreMemory(PillowTestCase):
Image.core.reset_stats()
Image.core.set_blocks_max(0)
Image.core.set_block_size(4096)
Image.new('RGB', (256, 256))
Image.new("RGB", (256, 256))
stats = Image.core.get_stats()
self.assertGreaterEqual(stats['new_count'], 1)
self.assertGreaterEqual(stats['allocated_blocks'], 64)
self.assertGreaterEqual(stats["new_count"], 1)
self.assertGreaterEqual(stats["allocated_blocks"], 64)
if not is_pypy:
self.assertGreaterEqual(stats['freed_blocks'], 64)
self.assertGreaterEqual(stats["freed_blocks"], 64)
def test_get_blocks_max(self):
blocks_max = Image.core.get_blocks_max()
@ -102,24 +102,26 @@ class TestCoreMemory(PillowTestCase):
self.assertEqual(blocks_max, i)
# Try to construct new image
Image.new('RGB', (10, 10))
Image.new("RGB", (10, 10))
self.assertRaises(ValueError, Image.core.set_blocks_max, -1)
if sys.maxsize < 2 ** 32:
self.assertRaises(ValueError, Image.core.set_blocks_max, 2 ** 29)
@unittest.skipIf(is_pypy, "images are not collected")
def test_set_blocks_max_stats(self):
Image.core.reset_stats()
Image.core.set_blocks_max(128)
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()
self.assertGreaterEqual(stats['new_count'], 2)
self.assertGreaterEqual(stats['allocated_blocks'], 64)
self.assertGreaterEqual(stats['reused_blocks'], 64)
self.assertEqual(stats['freed_blocks'], 0)
self.assertEqual(stats['blocks_cached'], 64)
self.assertGreaterEqual(stats["new_count"], 2)
self.assertGreaterEqual(stats["allocated_blocks"], 64)
self.assertGreaterEqual(stats["reused_blocks"], 64)
self.assertEqual(stats["freed_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 64)
@unittest.skipIf(is_pypy, "images are not collected")
def test_clear_cache_stats(self):
@ -127,55 +129,55 @@ class TestCoreMemory(PillowTestCase):
Image.core.clear_cache()
Image.core.set_blocks_max(128)
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
Image.core.clear_cache(16)
stats = Image.core.get_stats()
self.assertGreaterEqual(stats['new_count'], 2)
self.assertGreaterEqual(stats['allocated_blocks'], 64)
self.assertGreaterEqual(stats['reused_blocks'], 64)
self.assertGreaterEqual(stats['freed_blocks'], 48)
self.assertEqual(stats['blocks_cached'], 16)
self.assertGreaterEqual(stats["new_count"], 2)
self.assertGreaterEqual(stats["allocated_blocks"], 64)
self.assertGreaterEqual(stats["reused_blocks"], 64)
self.assertGreaterEqual(stats["freed_blocks"], 48)
self.assertEqual(stats["blocks_cached"], 16)
def test_large_images(self):
Image.core.reset_stats()
Image.core.set_blocks_max(0)
Image.core.set_block_size(4096)
Image.new('RGB', (2048, 16))
Image.new("RGB", (2048, 16))
Image.core.clear_cache()
stats = Image.core.get_stats()
self.assertGreaterEqual(stats['new_count'], 1)
self.assertGreaterEqual(stats['allocated_blocks'], 16)
self.assertGreaterEqual(stats['reused_blocks'], 0)
self.assertEqual(stats['blocks_cached'], 0)
self.assertGreaterEqual(stats["new_count"], 1)
self.assertGreaterEqual(stats["allocated_blocks"], 16)
self.assertGreaterEqual(stats["reused_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 0)
if not is_pypy:
self.assertGreaterEqual(stats['freed_blocks'], 16)
self.assertGreaterEqual(stats["freed_blocks"], 16)
class TestEnvVars(PillowTestCase):
def tearDown(self):
# Restore default values
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.clear_cache()
def test_units(self):
Image._apply_env_variables({'PILLOW_BLOCKS_MAX': '2K'})
self.assertEqual(Image.core.get_blocks_max(), 2*1024)
Image._apply_env_variables({'PILLOW_BLOCK_SIZE': '2m'})
self.assertEqual(Image.core.get_block_size(), 2*1024*1024)
Image._apply_env_variables({"PILLOW_BLOCKS_MAX": "2K"})
self.assertEqual(Image.core.get_blocks_max(), 2 * 1024)
Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"})
self.assertEqual(Image.core.get_block_size(), 2 * 1024 * 1024)
def test_warnings(self):
self.assert_warning(
UserWarning, Image._apply_env_variables,
{'PILLOW_ALIGNMENT': '15'})
UserWarning, Image._apply_env_variables, {"PILLOW_ALIGNMENT": "15"}
)
self.assert_warning(
UserWarning, Image._apply_env_variables,
{'PILLOW_BLOCK_SIZE': '1024'})
UserWarning, Image._apply_env_variables, {"PILLOW_BLOCK_SIZE": "1024"}
)
self.assert_warning(
UserWarning, Image._apply_env_variables,
{'PILLOW_BLOCKS_MAX': 'wat'})
UserWarning, Image._apply_env_variables, {"PILLOW_BLOCKS_MAX": "wat"}
)

View File

@ -8,7 +8,6 @@ ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS
class TestDecompressionBomb(PillowTestCase):
def tearDown(self):
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
@ -33,20 +32,17 @@ class TestDecompressionBomb(PillowTestCase):
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1)
self.assert_warning(Image.DecompressionBombWarning,
Image.open, TEST_FILE)
self.assert_warning(Image.DecompressionBombWarning, Image.open, TEST_FILE)
def test_exception(self):
# Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1)
self.assertRaises(Image.DecompressionBombError,
lambda: Image.open(TEST_FILE))
self.assertRaises(Image.DecompressionBombError, lambda: Image.open(TEST_FILE))
class TestDecompressionCrop(PillowTestCase):
def setUp(self):
self.src = hopper()
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
# same decompression bomb warnings on them.
box = (0, 0, self.src.width * 2, self.src.height * 2)
self.assert_warning(Image.DecompressionBombWarning,
self.src.crop, box)
self.assert_warning(Image.DecompressionBombWarning, self.src.crop, box)
def test_crop_decompression_checks(self):
im = Image.new("RGB", (100, 100))
good_values = ((-9999, -9999, -9990, -9990),
(-999, -999, -990, -990))
good_values = ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990))
warning_values = ((-160, -160, 99, 99),
(160, 160, -99, -99))
warning_values = ((-160, -160, 99, 99), (160, 160, -99, -99))
error_values = ((-99909, -99990, 99999, 99999),
(99909, 99990, -99999, -99999))
error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))
for value in good_values:
self.assertEqual(im.crop(value).size, (9, 9))

View File

@ -1,44 +1,43 @@
from __future__ import unicode_literals
import io
from .helper import unittest, PillowTestCase
from PIL import features
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
class TestFeatures(PillowTestCase):
def test_check(self):
# Check the correctness of the convenience function
for module in features.modules:
self.assertEqual(features.check_module(module),
features.check(module))
self.assertEqual(features.check_module(module), features.check(module))
for codec in features.codecs:
self.assertEqual(features.check_codec(codec),
features.check(codec))
self.assertEqual(features.check_codec(codec), features.check(codec))
for feature in features.features:
self.assertEqual(features.check_feature(feature),
features.check(feature))
self.assertEqual(features.check_feature(feature), features.check(feature))
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
def test_webp_transparency(self):
self.assertEqual(features.check('transp_webp'),
not _webp.WebPDecoderBuggyAlpha())
self.assertEqual(features.check('transp_webp'),
_webp.HAVE_TRANSPARENCY)
self.assertEqual(
features.check("transp_webp"), not _webp.WebPDecoderBuggyAlpha()
)
self.assertEqual(features.check("transp_webp"), _webp.HAVE_TRANSPARENCY)
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
def test_webp_mux(self):
self.assertEqual(features.check('webp_mux'),
_webp.HAVE_WEBPMUX)
self.assertEqual(features.check("webp_mux"), _webp.HAVE_WEBPMUX)
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
def test_webp_anim(self):
self.assertEqual(features.check('webp_anim'),
_webp.HAVE_WEBPANIM)
self.assertEqual(features.check("webp_anim"), _webp.HAVE_WEBPANIM)
def test_check_modules(self):
for feature in features.modules:
@ -63,3 +62,27 @@ class TestFeatures(PillowTestCase):
module = "unsupported_module"
# Act / Assert
self.assertRaises(ValueError, features.check_module, module)
def test_pilinfo(self):
buf = io.StringIO()
features.pilinfo(buf)
out = buf.getvalue()
lines = out.splitlines()
self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Pillow "))
self.assertEqual(lines[2], "-" * 68)
self.assertTrue(lines[3].startswith("Python modules loaded from "))
self.assertTrue(lines[4].startswith("Binary modules loaded from "))
self.assertEqual(lines[5], "-" * 68)
self.assertTrue(lines[6].startswith("Python "))
jpeg = (
"\n"
+ "-" * 68
+ "\n"
+ "JPEG image/jpeg\n"
+ "Extensions: .jfif, .jpe, .jpeg, .jpg\n"
+ "Features: open, save\n"
+ "-" * 68
+ "\n"
)
self.assertIn(jpeg, out)

View File

@ -5,11 +5,10 @@ import io
class TestFileBmp(PillowTestCase):
def roundtrip(self, im):
outfile = self.tempfile("temp.bmp")
im.save(outfile, 'BMP')
im.save(outfile, "BMP")
reloaded = Image.open(outfile)
reloaded.load()
@ -28,8 +27,7 @@ class TestFileBmp(PillowTestCase):
def test_invalid_file(self):
with open("Tests/images/flower.jpg", "rb") as fp:
self.assertRaises(SyntaxError,
BmpImagePlugin.BmpImageFile, fp)
self.assertRaises(SyntaxError, BmpImagePlugin.BmpImageFile, fp)
def test_save_to_bytes(self):
output = io.BytesIO()
@ -62,27 +60,27 @@ class TestFileBmp(PillowTestCase):
im = Image.open("Tests/images/hopper.bmp")
# Act
im.save(outfile, 'JPEG', dpi=im.info['dpi'])
im.save(outfile, "JPEG", dpi=im.info["dpi"])
# Assert
reloaded = Image.open(outfile)
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(reloaded.format, "JPEG")
def test_load_dpi_rounding(self):
# Round up
im = Image.open('Tests/images/hopper.bmp')
im = Image.open("Tests/images/hopper.bmp")
self.assertEqual(im.info["dpi"], (96, 96))
# 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))
def test_save_dpi_rounding(self):
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))
reloaded = Image.open(outfile)
@ -94,17 +92,17 @@ class TestFileBmp(PillowTestCase):
def test_load_dib(self):
# 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.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)
def test_save_dib(self):
outfile = self.tempfile("temp.dib")
im = Image.open('Tests/images/clipboard.dib')
im = Image.open("Tests/images/clipboard.dib")
im.save(outfile)
reloaded = Image.open(outfile)

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
class TestFileBufrStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
@ -23,8 +22,9 @@ class TestFileBufrStub(PillowTestCase):
invalid_file = "Tests/images/flower.jpg"
# Act / Assert
self.assertRaises(SyntaxError,
BufrStubImagePlugin.BufrStubImageFile, invalid_file)
self.assertRaises(
SyntaxError, BufrStubImagePlugin.BufrStubImageFile, invalid_file
)
def test_load(self):
# Arrange

View File

@ -7,7 +7,6 @@ TEST_FILE = "Tests/images/dummy.container"
class TestFileContainer(PillowTestCase):
def test_sanity(self):
dir(Image)
dir(ContainerIO)
@ -106,14 +105,16 @@ class TestFileContainer(PillowTestCase):
def test_readlines(self):
# Arrange
expected = ["This is line 1\n",
"This is line 2\n",
"This is line 3\n",
"This is line 4\n",
"This is line 5\n",
"This is line 6\n",
"This is line 7\n",
"This is line 8\n"]
expected = [
"This is line 1\n",
"This is line 2\n",
"This is line 3\n",
"This is line 4\n",
"This is line 5\n",
"This is line 6\n",
"This is line 7\n",
"This is line 8\n",
]
with open(TEST_FILE) as fh:
container = ContainerIO.ContainerIO(fh, 0, 120)

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/deerstalker.cur"
class TestFileCur(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
@ -20,8 +19,7 @@ class TestFileCur(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
CurImagePlugin.CurImageFile, invalid_file)
self.assertRaises(SyntaxError, CurImagePlugin.CurImageFile, invalid_file)
no_cursors_file = "Tests/images/no_cursors.cur"

View File

@ -7,7 +7,6 @@ TEST_FILE = "Tests/images/hopper.dcx"
class TestFileDcx(PillowTestCase):
def test_sanity(self):
# Arrange
@ -24,12 +23,12 @@ class TestFileDcx(PillowTestCase):
def open():
im = Image.open(TEST_FILE)
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
with open("Tests/images/flower.jpg", "rb") as fp:
self.assertRaises(SyntaxError,
DcxImagePlugin.DcxImageFile, fp)
self.assertRaises(SyntaxError, DcxImagePlugin.DcxImageFile, fp)
def test_tell(self):
# Arrange
@ -55,7 +54,7 @@ class TestFileDcx(PillowTestCase):
self.assertLess(im.tell(), n_frames)
# 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):
# Arrange

View File

@ -15,7 +15,7 @@ class TestFileDds(PillowTestCase):
def test_sanity_dxt1(self):
"""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.load()
@ -24,12 +24,12 @@ class TestFileDds(PillowTestCase):
self.assertEqual(im.mode, "RGBA")
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):
"""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.load()
@ -43,7 +43,7 @@ class TestFileDds(PillowTestCase):
def test_sanity_dxt3(self):
"""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.load()
@ -57,7 +57,7 @@ class TestFileDds(PillowTestCase):
def test_dx10_bc7(self):
"""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.load()
@ -69,13 +69,16 @@ class TestFileDds(PillowTestCase):
self.assert_image_equal(target, im)
def test_unimplemented_dxgi_format(self):
self.assertRaises(NotImplementedError, Image.open,
"Tests/images/unimplemented_dxgi_format.dds")
self.assertRaises(
NotImplementedError,
Image.open,
"Tests/images/unimplemented_dxgi_format.dds",
)
def test_uncompressed_rgb(self):
"""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.load()
@ -110,7 +113,7 @@ class TestFileDds(PillowTestCase):
def test_short_header(self):
""" Check a short header"""
with open(TEST_FILE_DXT5, 'rb') as f:
with open(TEST_FILE_DXT5, "rb") as f:
img_file = f.read()
def short_header():
@ -121,7 +124,7 @@ class TestFileDds(PillowTestCase):
def test_short_file(self):
""" 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()
def short_file():
@ -131,5 +134,8 @@ class TestFileDds(PillowTestCase):
self.assertRaises(IOError, short_file)
def test_unimplemented_pixel_format(self):
self.assertRaises(NotImplementedError, Image.open,
"Tests/images/unimplemented_pixel_format.dds")
self.assertRaises(
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):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_sanity(self):
# Regular scale
@ -53,8 +52,7 @@ class TestFileEps(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
EpsImagePlugin.EpsImageFile, invalid_file)
self.assertRaises(SyntaxError, EpsImagePlugin.EpsImageFile, invalid_file)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_cmyk(self):
@ -67,8 +65,8 @@ class TestFileEps(PillowTestCase):
cmyk_image.load()
self.assertEqual(cmyk_image.mode, "RGB")
if 'jpeg_decoder' in dir(Image.core):
target = Image.open('Tests/images/pil_sample_rgb.jpg')
if "jpeg_decoder" in dir(Image.core):
target = Image.open("Tests/images/pil_sample_rgb.jpg")
self.assert_image_similar(cmyk_image, target, 10)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@ -86,19 +84,19 @@ class TestFileEps(PillowTestCase):
def test_file_object(self):
# issue 479
image1 = Image.open(file1)
with open(self.tempfile('temp_file.eps'), 'wb') as fh:
image1.save(fh, 'EPS')
with open(self.tempfile("temp_file.eps"), "wb") as fh:
image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_iobase_object(self):
# issue 479
image1 = Image.open(file1)
with io.open(self.tempfile('temp_iobase.eps'), 'wb') as fh:
image1.save(fh, 'EPS')
with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh:
image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_bytesio_object(self):
with open(file1, 'rb') as f:
with open(file1, "rb") as f:
img_bytes = io.BytesIO(f.read())
img = Image.open(img_bytes)
@ -110,7 +108,7 @@ class TestFileEps(PillowTestCase):
def test_image_mode_not_supported(self):
im = hopper("RGBA")
tmpfile = self.tempfile('temp.eps')
tmpfile = self.tempfile("temp.eps")
self.assertRaises(ValueError, im.save, tmpfile)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@ -195,33 +193,33 @@ class TestFileEps(PillowTestCase):
Image.open(file3)
def _test_readline(self, t, ending):
ending = "Failure with line ending: %s" % ("".join(
"%s" % ord(s)
for s in 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'), 'baz', ending)
self.assertEqual(t.readline().strip('\r\n'), 'bif', ending)
ending = "Failure with line ending: %s" % (
"".join("%s" % ord(s) for s in 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"), "baz", ending)
self.assertEqual(t.readline().strip("\r\n"), "bif", 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)
self._test_readline(t, ending)
def _test_readline_file_psfile(self, test_string, ending):
f = self.tempfile('temp.txt')
with open(f, 'wb') as w:
w.write(test_string.encode('latin-1'))
f = self.tempfile("temp.txt")
with open(f, "wb") as w:
w.write(test_string.encode("latin-1"))
with open(f, 'rb') as r:
with open(f, "rb") as r:
t = EpsImagePlugin.PSFile(r)
self._test_readline(t, ending)
def test_readline(self):
# check all the freaking line endings possible from the spec
# test_string = u'something\r\nelse\n\rbaz\rbif\n'
line_endings = ['\r\n', '\n', '\n\r', '\r']
strings = ['something', 'else', 'baz', 'bif']
line_endings = ["\r\n", "\n", "\n\r", "\r"]
strings = ["something", "else", "baz", "bif"]
for ending in line_endings:
s = ending.join(strings)
@ -231,10 +229,12 @@ class TestFileEps(PillowTestCase):
def test_open_eps(self):
# https://github.com/python-pillow/Pillow/issues/1104
# Arrange
FILES = ["Tests/images/illu10_no_preview.eps",
"Tests/images/illu10_preview.eps",
"Tests/images/illuCS6_no_preview.eps",
"Tests/images/illuCS6_preview.eps"]
FILES = [
"Tests/images/illu10_no_preview.eps",
"Tests/images/illu10_preview.eps",
"Tests/images/illuCS6_no_preview.eps",
"Tests/images/illuCS6_preview.eps",
]
# Act / Assert
for filename in FILES:

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hopper.fits"
class TestFileFitsStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
@ -23,8 +22,9 @@ class TestFileFitsStub(PillowTestCase):
invalid_file = "Tests/images/flower.jpg"
# Act / Assert
self.assertRaises(SyntaxError,
FitsStubImagePlugin.FITSStubImageFile, invalid_file)
self.assertRaises(
SyntaxError, FitsStubImagePlugin.FITSStubImageFile, invalid_file
)
def test_load(self):
# Arrange
@ -42,5 +42,5 @@ class TestFileFitsStub(PillowTestCase):
# Act / Assert: stub cannot save without an implemented handler
self.assertRaises(IOError, im.save, dummy_filename)
self.assertRaises(
IOError,
FitsStubImagePlugin._save, im, dummy_fp, dummy_filename)
IOError, FitsStubImagePlugin._save, im, dummy_fp, dummy_filename
)

View File

@ -11,7 +11,6 @@ animated_test_file = "Tests/images/a.fli"
class TestFileFli(PillowTestCase):
def test_sanity(self):
im = Image.open(static_test_file)
im.load()
@ -31,6 +30,7 @@ class TestFileFli(PillowTestCase):
def open():
im = Image.open(static_test_file)
im.load()
self.assert_warning(None, open)
def test_tell(self):
@ -46,8 +46,7 @@ class TestFileFli(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
FliImagePlugin.FliImageFile, invalid_file)
self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
def test_n_frames(self):
im = Image.open(static_test_file)
@ -67,7 +66,7 @@ class TestFileFli(PillowTestCase):
self.assertLess(im.tell(), n_frames)
# 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):
im = Image.open(animated_test_file)

View File

@ -10,14 +10,11 @@ else:
@unittest.skipUnless(olefile_installed, "olefile package not installed")
class TestFileFpx(PillowTestCase):
def test_invalid_file(self):
# Test an invalid OLE file
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
FpxImagePlugin.FpxImageFile, invalid_file)
self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, invalid_file)
# Test a valid OLE file, but not an FPX file
ole_file = "Tests/images/test-ole-file.doc"
self.assertRaises(SyntaxError,
FpxImagePlugin.FpxImageFile, ole_file)
self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, ole_file)

View File

@ -3,14 +3,13 @@ from PIL import Image
class TestFileFtex(PillowTestCase):
def test_load_raw(self):
im = Image.open('Tests/images/ftex_uncompressed.ftu')
target = Image.open('Tests/images/ftex_uncompressed.png')
im = Image.open("Tests/images/ftex_uncompressed.ftu")
target = Image.open("Tests/images/ftex_uncompressed.png")
self.assert_image_equal(im, target)
def test_load_dxt1(self):
im = Image.open('Tests/images/ftex_dxt1.ftc')
target = Image.open('Tests/images/ftex_dxt1.png')
self.assert_image_similar(im, target.convert('RGBA'), 15)
im = Image.open("Tests/images/ftex_dxt1.ftc")
target = Image.open("Tests/images/ftex_dxt1.png")
self.assert_image_similar(im, target.convert("RGBA"), 15)

View File

@ -4,16 +4,14 @@ from PIL import Image, GbrImagePlugin
class TestFileGbr(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
GbrImagePlugin.GbrImageFile, invalid_file)
self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file)
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)

View File

@ -6,15 +6,13 @@ TEST_GD_FILE = "Tests/images/hopper.gd"
class TestFileGd(PillowTestCase):
def test_sanity(self):
im = GdImageFile.open(TEST_GD_FILE)
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GD")
def test_bad_mode(self):
self.assertRaises(ValueError,
GdImageFile.open, TEST_GD_FILE, 'bad mode')
self.assertRaises(ValueError, GdImageFile.open, TEST_GD_FILE, "bad mode")
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"

View File

@ -6,6 +6,7 @@ from io import BytesIO
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
@ -20,7 +21,6 @@ with open(TEST_GIF, "rb") as f:
class TestFileGif(PillowTestCase):
def setUp(self):
if "gif_encoder" not in codecs or "gif_decoder" not in codecs:
self.skipTest("gif support not available") # can this happen?
@ -37,13 +37,13 @@ class TestFileGif(PillowTestCase):
def open():
im = Image.open(TEST_GIF)
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
GifImagePlugin.GifImageFile, invalid_file)
self.assertRaises(SyntaxError, GifImagePlugin.GifImageFile, invalid_file)
def test_optimize(self):
def test_grayscale(optimize):
@ -70,19 +70,22 @@ class TestFileGif(PillowTestCase):
# Check for correctness after conversion back to RGB
def check(colors, size, expected_palette_length):
# make an image with empty colors in the start of the palette range
im = Image.frombytes('P', (colors, colors),
bytes(bytearray(range(256-colors, 256))*colors))
im = Image.frombytes(
"P",
(colors, colors),
bytes(bytearray(range(256 - colors, 256)) * colors),
)
im = im.resize((size, size))
outfile = BytesIO()
im.save(outfile, 'GIF')
im.save(outfile, "GIF")
outfile.seek(0)
reloaded = Image.open(outfile)
# 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.assert_image_equal(im.convert('RGB'), reloaded.convert('RGB'))
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
# These do optimize the palette
check(128, 511, 128)
@ -106,79 +109,76 @@ class TestFileGif(PillowTestCase):
self.assertEqual(im.mode, "L")
def test_roundtrip(self):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im = hopper()
im.save(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):
# see https://github.com/python-pillow/Pillow/issues/403
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im = Image.open(TEST_GIF)
im2 = im.copy()
im2.save(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):
# Single frame image
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im = hopper()
im.save(out, save_all=True)
reread = Image.open(out)
self.assert_image_similar(reread.convert('RGB'), im, 50)
self.assert_image_similar(reread.convert("RGB"), im, 50)
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
reread = Image.open(out)
self.assertEqual(reread.n_frames, 5)
def test_headers_saving_for_animated_gifs(self):
important_headers = ['background', 'version', 'duration', 'loop']
important_headers = ["background", "version", "duration", "loop"]
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
info = im.info.copy()
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
reread = Image.open(out)
for header in important_headers:
self.assertEqual(
info[header],
reread.info[header]
)
self.assertEqual(info[header], reread.info[header])
def test_palette_handling(self):
# see https://github.com/python-pillow/Pillow/issues/513
im = Image.open(TEST_GIF)
im = im.convert('RGB')
im = im.convert("RGB")
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)
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):
# see https://github.com/python-pillow/Pillow/issues/434
def roundtrip(im, *args, **kwargs):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im.copy().save(out, *args, **kwargs)
reloaded = Image.open(out)
@ -192,7 +192,7 @@ class TestFileGif(PillowTestCase):
im = im.convert("RGB")
# check automatic P conversion
reloaded = roundtrip(im).convert('RGB')
reloaded = roundtrip(im).convert("RGB")
self.assert_image_equal(im, reloaded)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
@ -240,10 +240,7 @@ class TestFileGif(PillowTestCase):
self.assert_image_equal(im, expected)
def test_n_frames(self):
for path, n_frames in [
[TEST_GIF, 1],
['Tests/images/iss634.gif', 42]
]:
for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]:
# Test is_animated before n_frames
im = Image.open(path)
self.assertEqual(im.is_animated, n_frames != 1)
@ -262,7 +259,7 @@ class TestFileGif(PillowTestCase):
self.assertLess(im.tell(), n_frames)
# 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):
img = Image.open("Tests/images/dispose_none.gif")
@ -292,18 +289,15 @@ class TestFileGif(PillowTestCase):
pass
def test_save_dispose(self):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im_list = [
Image.new('L', (100, 100), '#000'),
Image.new('L', (100, 100), '#111'),
Image.new('L', (100, 100), '#222'),
Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#111"),
Image.new("L", (100, 100), "#222"),
]
for method in range(0, 4):
im_list[0].save(
out,
save_all=True,
append_images=im_list[1:],
disposal=method
out, save_all=True, append_images=im_list[1:], disposal=method
)
img = Image.open(out)
for _ in range(2):
@ -315,14 +309,14 @@ class TestFileGif(PillowTestCase):
out,
save_all=True,
append_images=im_list[1:],
disposal=tuple(range(len(im_list)))
)
disposal=tuple(range(len(im_list))),
)
img = Image.open(out)
for i in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, i+1)
self.assertEqual(img.disposal_method, i + 1)
def test_dispose2_palette(self):
out = self.tempfile('temp.gif')
@ -411,42 +405,39 @@ class TestFileGif(PillowTestCase):
img.seek(img.tell() + 1)
# all transparent pixels should be replaced with the color from the
# first frame
self.assertEqual(img.histogram()[img.info['transparency']], 0)
self.assertEqual(img.histogram()[img.info["transparency"]], 0)
def test_duration(self):
duration = 1000
out = self.tempfile('temp.gif')
im = Image.new('L', (100, 100), '#000')
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
# Check that the argument has priority over the info settings
im.info['duration'] = 100
im.info["duration"] = 100
im.save(out, duration=duration)
reread = Image.open(out)
self.assertEqual(reread.info['duration'], duration)
self.assertEqual(reread.info["duration"], duration)
def test_multiple_duration(self):
duration_list = [1000, 2000, 3000]
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im_list = [
Image.new('L', (100, 100), '#000'),
Image.new('L', (100, 100), '#111'),
Image.new('L', (100, 100), '#222')
Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#111"),
Image.new("L", (100, 100), "#222"),
]
# duration as list
im_list[0].save(
out,
save_all=True,
append_images=im_list[1:],
duration=duration_list
out, save_all=True, append_images=im_list[1:], duration=duration_list
)
reread = Image.open(out)
for duration in duration_list:
self.assertEqual(reread.info['duration'], duration)
self.assertEqual(reread.info["duration"], duration)
try:
reread.seek(reread.tell() + 1)
except EOFError:
@ -454,15 +445,12 @@ class TestFileGif(PillowTestCase):
# duration as tuple
im_list[0].save(
out,
save_all=True,
append_images=im_list[1:],
duration=tuple(duration_list)
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
)
reread = Image.open(out)
for duration in duration_list:
self.assertEqual(reread.info['duration'], duration)
self.assertEqual(reread.info["duration"], duration)
try:
reread.seek(reread.tell() + 1)
except EOFError:
@ -471,20 +459,17 @@ class TestFileGif(PillowTestCase):
def test_identical_frames(self):
duration_list = [1000, 1500, 2000, 4000]
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
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), '#111')
Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#000"),
Image.new("L", (100, 100), "#111"),
]
# duration as list
im_list[0].save(
out,
save_all=True,
append_images=im_list[1:],
duration=duration_list
out, save_all=True, append_images=im_list[1:], duration=duration_list
)
reread = Image.open(out)
@ -492,64 +477,63 @@ class TestFileGif(PillowTestCase):
self.assertEqual(reread.n_frames, 2)
# 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):
number_of_loops = 2
out = self.tempfile('temp.gif')
im = Image.new('L', (100, 100), '#000')
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.save(out, loop=number_of_loops)
reread = Image.open(out)
self.assertEqual(reread.info['loop'], number_of_loops)
self.assertEqual(reread.info["loop"], number_of_loops)
def test_background(self):
out = self.tempfile('temp.gif')
im = Image.new('L', (100, 100), '#000')
im.info['background'] = 1
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.info["background"] = 1
im.save(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:
im = Image.open("Tests/images/hopper.webp")
self.assertIsInstance(im.info['background'], tuple)
self.assertIsInstance(im.info["background"], tuple)
im.save(out)
def test_comment(self):
im = Image.open(TEST_GIF)
self.assertEqual(im.info['comment'],
b"File written by Adobe Photoshop\xa8 4.0")
self.assertEqual(im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0")
out = self.tempfile('temp.gif')
im = Image.new('L', (100, 100), '#000')
im.info['comment'] = b"Test comment text"
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.info["comment"] = b"Test comment text"
im.save(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):
out = self.tempfile('temp.gif')
im = Image.new('L', (100, 100), '#000')
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
comment = b"Test comment text"
while len(comment) < 256:
comment += comment
im.info['comment'] = comment
im.info["comment"] = comment
im.save(out)
reread = Image.open(out)
self.assertEqual(reread.info['comment'], comment)
self.assertEqual(reread.info["comment"], comment)
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)
self.assert_image_equal(im, expected)
def test_version(self):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
def assertVersionAfterSave(im, version):
im.save(out)
@ -557,11 +541,11 @@ class TestFileGif(PillowTestCase):
self.assertEqual(reread.info["version"], version)
# 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")
# 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"
assertVersionAfterSave(im, b"GIF89a")
@ -578,12 +562,11 @@ class TestFileGif(PillowTestCase):
assertVersionAfterSave(im, b"GIF87a")
def test_append_images(self):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
# Test appending single frame images
im = Image.new('RGB', (100, 100), '#f00')
ims = [Image.new('RGB', (100, 100), color) for color
in ['#0f0', '#00f']]
im = Image.new("RGB", (100, 100), "#f00")
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
im.copy().save(out, save_all=True, append_images=ims)
reread = Image.open(out)
@ -593,6 +576,7 @@ class TestFileGif(PillowTestCase):
def imGenerator(ims):
for im in ims:
yield im
im.save(out, save_all=True, append_images=imGenerator(ims))
reread = Image.open(out)
@ -614,44 +598,43 @@ class TestFileGif(PillowTestCase):
# the top palette entry to trigger the bug.
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.putpalette(palette)
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im.save(out, transparency=253)
reloaded = Image.open(out)
self.assertEqual(reloaded.info['transparency'], 253)
self.assertEqual(reloaded.info["transparency"], 253)
def test_rgb_transparency(self):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
# Single frame
im = Image.new('RGB', (1, 1))
im.info['transparency'] = (255, 0, 0)
im = Image.new("RGB", (1, 1))
im.info["transparency"] = (255, 0, 0)
self.assert_warning(UserWarning, im.save, out)
reloaded = Image.open(out)
self.assertNotIn('transparency', reloaded.info)
self.assertNotIn("transparency", reloaded.info)
# Multiple frames
im = Image.new('RGB', (1, 1))
im.info['transparency'] = b""
ims = [Image.new('RGB', (1, 1))]
self.assert_warning(UserWarning,
im.save, out, save_all=True, append_images=ims)
im = Image.new("RGB", (1, 1))
im.info["transparency"] = b""
ims = [Image.new("RGB", (1, 1))]
self.assert_warning(UserWarning, im.save, out, save_all=True, append_images=ims)
reloaded = Image.open(out)
self.assertNotIn('transparency', reloaded.info)
self.assertNotIn("transparency", reloaded.info)
def test_bbox(self):
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im = Image.new('RGB', (100, 100), '#fff')
ims = [Image.new("RGB", (100, 100), '#000')]
im = Image.new("RGB", (100, 100), "#fff")
ims = [Image.new("RGB", (100, 100), "#000")]
im.save(out, save_all=True, append_images=ims)
reread = Image.open(out)
@ -660,26 +643,26 @@ class TestFileGif(PillowTestCase):
def test_palette_save_L(self):
# generate an L mode image with a separate palette
im = hopper('P')
im_l = Image.frombytes('L', im.size, im.tobytes())
im = hopper("P")
im_l = Image.frombytes("L", im.size, im.tobytes())
palette = bytes(bytearray(im.getpalette()))
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im_l.save(out, palette=palette)
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):
# pass in a different palette, then construct what the image
# would look like.
# Forcing a non-straight grayscale palette.
im = hopper('P')
palette = bytes(bytearray([255-i//3 for i in range(768)]))
im = hopper("P")
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)
reloaded = Image.open(out)
@ -690,10 +673,10 @@ class TestFileGif(PillowTestCase):
# pass in a different palette, as an ImagePalette.ImagePalette
# effectively the same as test_palette_save_P
im = hopper('P')
palette = ImagePalette.ImagePalette('RGB', list(range(256))[::-1]*3)
im = hopper("P")
palette = ImagePalette.ImagePalette("RGB", list(range(256))[::-1] * 3)
out = self.tempfile('temp.gif')
out = self.tempfile("temp.gif")
im.save(out, palette=palette)
reloaded = Image.open(out)
@ -703,22 +686,22 @@ class TestFileGif(PillowTestCase):
def test_save_I(self):
# 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)
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):
# test getheader/getdata against legacy values
# Create a 'P' image with holes in the palette
im = Image._wedge().resize((16, 16))
im.putpalette(ImagePalette.ImagePalette('RGB'))
im.info = {'background': 0}
im.putpalette(ImagePalette.ImagePalette("RGB"))
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
try:
@ -726,10 +709,11 @@ class TestFileGif(PillowTestCase):
d = GifImagePlugin.getdata(im)
import pickle
# Enable to get target values on pre-refactor version
# with open('Tests/images/gif_header_data.pkl', 'wb') as f:
# 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)
self.assertEqual(h, h_target)
@ -739,8 +723,14 @@ class TestFileGif(PillowTestCase):
def test_lzw_bits(self):
# 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
# codec error prepatch
im.load()
def test_extents(self):
im = Image.open("Tests/images/test_extents.gif")
self.assertEqual(im.size, (100, 100))
im.seek(1)
self.assertEqual(im.size, (150, 150))

View File

@ -4,7 +4,6 @@ from PIL import GimpGradientFile
class TestImage(PillowTestCase):
def test_linear_pos_le_middle(self):
# Arrange
middle = 0.5
@ -96,6 +95,7 @@ class TestImage(PillowTestCase):
def test_load_via_imagepalette(self):
# Arrange
from PIL import ImagePalette
test_file = "Tests/images/gimp_gradient.ggr"
# Act
@ -109,6 +109,7 @@ class TestImage(PillowTestCase):
def test_load_1_3_via_imagepalette(self):
# Arrange
from PIL import ImagePalette
# GIMP 1.3 gradient files contain a name field
test_file = "Tests/images/gimp_gradient_with_name.ggr"

View File

@ -4,23 +4,22 @@ from PIL.GimpPaletteFile import GimpPaletteFile
class TestImage(PillowTestCase):
def test_sanity(self):
with open('Tests/images/test.gpl', 'rb') as fp:
with open("Tests/images/test.gpl", "rb") as 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)
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)
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)
def test_get_palette(self):
# 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)
# Act

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
class TestFileGribStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
@ -23,8 +22,9 @@ class TestFileGribStub(PillowTestCase):
invalid_file = "Tests/images/flower.jpg"
# Act / Assert
self.assertRaises(SyntaxError,
GribStubImagePlugin.GribStubImageFile, invalid_file)
self.assertRaises(
SyntaxError, GribStubImagePlugin.GribStubImageFile, invalid_file
)
def test_load(self):
# Arrange

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hdf5.h5"
class TestFileHdf5Stub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
@ -23,8 +22,9 @@ class TestFileHdf5Stub(PillowTestCase):
invalid_file = "Tests/images/flower.jpg"
# Act / Assert
self.assertRaises(SyntaxError,
Hdf5StubImagePlugin.HDF5StubImageFile, invalid_file)
self.assertRaises(
SyntaxError, Hdf5StubImagePlugin.HDF5StubImageFile, invalid_file
)
def test_load(self):
# Arrange
@ -42,5 +42,5 @@ class TestFileHdf5Stub(PillowTestCase):
# Act / Assert: stub cannot save without an implemented handler
self.assertRaises(IOError, im.save, dummy_filename)
self.assertRaises(
IOError,
Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename)
IOError, Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename
)

View File

@ -8,11 +8,10 @@ import sys
# sample icon file
TEST_FILE = "Tests/images/pillow.icns"
enable_jpeg2k = hasattr(Image.core, 'jp2klib_version')
enable_jpeg2k = hasattr(Image.core, "jp2klib_version")
class TestFileIcns(PillowTestCase):
def test_sanity(self):
# Loading this icon by default should result in the largest size
# (512x512@2x) being loaded
@ -25,7 +24,7 @@ class TestFileIcns(PillowTestCase):
self.assertEqual(im.size, (1024, 1024))
self.assertEqual(im.format, "ICNS")
@unittest.skipIf(sys.platform != 'darwin', "requires macOS")
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
def test_save(self):
im = Image.open(TEST_FILE)
@ -38,12 +37,12 @@ class TestFileIcns(PillowTestCase):
self.assertEqual(reread.size, (1024, 1024))
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):
im = Image.open(TEST_FILE)
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])
reread = Image.open(temp_file)
@ -58,14 +57,13 @@ class TestFileIcns(PillowTestCase):
# Check that we can load all of the sizes, and that the final pixel
# dimensions are as expected
im = Image.open(TEST_FILE)
for w, h, r in im.info['sizes']:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open(TEST_FILE)
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, 'RGBA')
self.assertEqual(im2.size, (wr, hr))
im.size = (w, h, r)
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (wr, hr))
# Check that we cannot load an incorrect size
with self.assertRaises(ValueError):
@ -74,14 +72,14 @@ class TestFileIcns(PillowTestCase):
def test_older_icon(self):
# 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).
im = Image.open('Tests/images/pillow2.icns')
for w, h, r in im.info['sizes']:
im = Image.open("Tests/images/pillow2.icns")
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open('Tests/images/pillow2.icns')
im2 = Image.open("Tests/images/pillow2.icns")
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, 'RGBA')
self.assertEqual(im2.mode, "RGBA")
self.assertEqual(im2.size, (wr, hr))
def test_jp2_icon(self):
@ -95,18 +93,18 @@ class TestFileIcns(PillowTestCase):
if not enable_jpeg2k:
return
im = Image.open('Tests/images/pillow3.icns')
for w, h, r in im.info['sizes']:
im = Image.open("Tests/images/pillow3.icns")
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open('Tests/images/pillow3.icns')
im2 = Image.open("Tests/images/pillow3.icns")
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, 'RGBA')
self.assertEqual(im2.mode, "RGBA")
self.assertEqual(im2.size, (wr, hr))
def test_getimage(self):
with open(TEST_FILE, 'rb') as fp:
with open(TEST_FILE, "rb") as fp:
icns_file = IcnsImagePlugin.IcnsFile(fp)
im = icns_file.getimage()
@ -118,6 +116,5 @@ class TestFileIcns(PillowTestCase):
self.assertEqual(im.size, (512, 512))
def test_not_an_icns_file(self):
with io.BytesIO(b'invalid\n') as fp:
self.assertRaises(SyntaxError,
IcnsImagePlugin.IcnsFile, fp)
with io.BytesIO(b"invalid\n") as fp:
self.assertRaises(SyntaxError, IcnsImagePlugin.IcnsFile, fp)

View File

@ -1,13 +1,12 @@
from .helper import PillowTestCase, hopper
import io
from PIL import Image, IcoImagePlugin
from PIL import Image, ImageDraw, IcoImagePlugin
TEST_ICO_FILE = "Tests/images/hopper.ico"
class TestFileIco(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_ICO_FILE)
im.load()
@ -18,8 +17,7 @@ class TestFileIco(PillowTestCase):
def test_invalid_file(self):
with open("Tests/images/flower.jpg", "rb") as fp:
self.assertRaises(SyntaxError,
IcoImagePlugin.IcoImageFile, fp)
self.assertRaises(SyntaxError, IcoImagePlugin.IcoImageFile, fp)
def test_save_to_bytes(self):
output = io.BytesIO()
@ -29,13 +27,12 @@ class TestFileIco(PillowTestCase):
# the default image
output.seek(0)
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((64, 64), reloaded.size)
self.assertEqual(reloaded.format, "ICO")
self.assert_image_equal(reloaded,
hopper().resize((64, 64), Image.LANCZOS))
self.assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS))
# the other one
output.seek(0)
@ -45,8 +42,7 @@ class TestFileIco(PillowTestCase):
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual((32, 32), reloaded.size)
self.assertEqual(reloaded.format, "ICO")
self.assert_image_equal(reloaded,
hopper().resize((32, 32), Image.LANCZOS))
self.assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
def test_incorrect_size(self):
im = Image.open(TEST_ICO_FILE)
@ -81,5 +77,26 @@ class TestFileIco(PillowTestCase):
# Assert
self.assertEqual(
im_saved.info['sizes'],
{(16, 16), (24, 24), (32, 32), (48, 48)})
im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)}
)
def test_unexpected_size(self):
# This image has been manually hexedited to state that it is 16x32
# while the image within is still 16x16
im = self.assert_warning(
UserWarning, Image.open, "Tests/images/hopper_unexpected.ico"
)
self.assertEqual(im.size, (16, 16))
def test_draw_reloaded(self):
im = Image.open(TEST_ICO_FILE)
outfile = self.tempfile("temp_saved_hopper_draw.ico")
draw = ImageDraw.Draw(im)
draw.line((0, 0) + im.size, "#f00")
im.save(outfile)
im = Image.open(outfile)
im.save("Tests/images/hopper_draw.ico")
reloaded = Image.open("Tests/images/hopper_draw.ico")
self.assert_image_equal(im, reloaded)

View File

@ -7,7 +7,6 @@ TEST_IM = "Tests/images/hopper.im"
class TestFileIm(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_IM)
im.load()
@ -19,6 +18,7 @@ class TestFileIm(PillowTestCase):
def open():
im = Image.open(TEST_IM)
im.load()
self.assert_warning(None, open)
def test_tell(self):
@ -45,11 +45,11 @@ class TestFileIm(PillowTestCase):
self.assertLess(im.tell(), n_frames)
# 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):
for mode in ["RGB", "P"]:
out = self.tempfile('temp.im')
for mode in ["RGB", "P", "PA"]:
out = self.tempfile("temp.im")
im = hopper(mode)
im.save(out)
reread = Image.open(out)
@ -57,15 +57,14 @@ class TestFileIm(PillowTestCase):
self.assert_image_equal(reread, im)
def test_save_unsupported_mode(self):
out = self.tempfile('temp.im')
out = self.tempfile("temp.im")
im = hopper("HSV")
self.assertRaises(ValueError, im.save, out)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
ImImagePlugin.ImImageFile, invalid_file)
self.assertRaises(SyntaxError, ImImagePlugin.ImImageFile, invalid_file)
def test_number(self):
self.assertEqual(1.2, ImImagePlugin.number("1.2"))

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/iptc.jpg"
class TestFileIptc(PillowTestCase):
def test_getiptcinfo_jpg_none(self):
# Arrange
im = hopper()
@ -58,6 +57,7 @@ class TestFileIptc(PillowTestCase):
except ImportError:
from io import StringIO
import sys
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()

View File

@ -15,7 +15,6 @@ TEST_FILE = "Tests/images/hopper.jpg"
class TestFileJpeg(PillowTestCase):
def setUp(self):
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
self.skipTest("jpeg support not available")
@ -29,14 +28,13 @@ class TestFileJpeg(PillowTestCase):
im.bytes = test_bytes # for testing only
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
:param size: tuple
:param mode: optional image mode
"""
return Image.frombytes(mode, size,
os.urandom(size[0]*size[1]*len(mode)))
return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode)))
def test_sanity(self):
@ -54,10 +52,11 @@ class TestFileJpeg(PillowTestCase):
# Test APP/COM reader (@PIL135)
im = Image.open(TEST_FILE)
self.assertEqual(
im.applist[0],
("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00"))
self.assertEqual(im.applist[1], (
"COM", b"File written by Adobe Photoshop\xa8 4.0\x00"))
im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")
)
self.assertEqual(
im.applist[1], ("COM", b"File written by Adobe Photoshop\xa8 4.0\x00")
)
self.assertEqual(len(im.applist), 2)
def test_cmyk(self):
@ -72,8 +71,7 @@ class TestFileJpeg(PillowTestCase):
self.assertGreater(y, 0.8)
self.assertEqual(k, 0.0)
# the opposite corner is black
c, m, y, k = [x / 255.0 for x in im.getpixel((
im.size[0]-1, im.size[1]-1))]
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))]
self.assertGreater(k, 0.9)
# roundtrip, and check again
im = self.roundtrip(im)
@ -82,8 +80,7 @@ class TestFileJpeg(PillowTestCase):
self.assertGreater(m, 0.8)
self.assertGreater(y, 0.8)
self.assertEqual(k, 0.0)
c, m, y, k = [x / 255.0 for x in im.getpixel((
im.size[0]-1, im.size[1]-1))]
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))]
self.assertGreater(k, 0.9)
def test_dpi(self):
@ -91,6 +88,7 @@ class TestFileJpeg(PillowTestCase):
im = Image.open(TEST_FILE)
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
return im.info.get("dpi")
self.assertEqual(test(72), (72, 72))
self.assertEqual(test(300), (300, 300))
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
# using a 4-byte test code should allow us to detect out of
# 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
im1 = self.roundtrip(hopper(), icc_profile=icc_profile)
self.assertEqual(im1.info.get("icc_profile"), icc_profile or None)
test(0)
test(1)
test(3)
test(4)
test(5)
test(65533-14) # full JPEG marker block
test(65533-14+1) # full block plus one byte
test(65533 - 14) # full JPEG marker block
test(65533 - 14 + 1) # full block plus one byte
test(ImageFile.MAXBLOCK) # full buffer block
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
test(ImageFile.MAXBLOCK*4+3) # large block
test(ImageFile.MAXBLOCK + 1) # full buffer block plus one byte
test(ImageFile.MAXBLOCK * 4 + 3) # large block
def test_large_icc_meta(self):
# https://github.com/python-pillow/Pillow/issues/148
# Sometimes the meta data on the icc_profile block is bigger than
# 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")
icc_profile = im.info["icc_profile"]
# Should not raise IOError for image with icc larger than image size.
im.save(f, format='JPEG', progressive=True, quality=95,
icc_profile=icc_profile, optimize=True)
im.save(
f,
format="JPEG",
progressive=True,
quality=95,
icc_profile=icc_profile,
optimize=True,
)
def test_optimize(self):
im1 = self.roundtrip(hopper())
@ -156,9 +161,9 @@ class TestFileJpeg(PillowTestCase):
def test_optimize_large_buffer(self):
# https://github.com/python-pillow/Pillow/issues/148
f = self.tempfile('temp.jpg')
f = self.tempfile("temp.jpg")
# 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)
def test_progressive(self):
@ -173,13 +178,13 @@ class TestFileJpeg(PillowTestCase):
self.assertGreaterEqual(im1.bytes, im3.bytes)
def test_progressive_large_buffer(self):
f = self.tempfile('temp.jpg')
f = self.tempfile("temp.jpg")
# 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)
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))
# this requires more bytes than pixels in the image
im.save(f, format="JPEG", progressive=True, quality=100)
@ -187,30 +192,31 @@ class TestFileJpeg(PillowTestCase):
def test_progressive_cmyk_buffer(self):
# Issue 2272, quality 90 cmyk image is tripping the large buffer bug.
f = BytesIO()
im = self.gen_random_image((256, 256), 'CMYK')
im.save(f, format='JPEG', progressive=True, quality=94)
im = self.gen_random_image((256, 256), "CMYK")
im.save(f, format="JPEG", progressive=True, quality=94)
def test_large_exif(self):
# https://github.com/python-pillow/Pillow/issues/148
f = self.tempfile('temp.jpg')
f = self.tempfile("temp.jpg")
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):
im = Image.open('Tests/images/exif_typeerror.jpg')
im = Image.open("Tests/images/exif_typeerror.jpg")
# Should not raise a TypeError
im._getexif()
def test_exif_gps(self):
# Arrange
im = Image.open('Tests/images/exif_gps.jpg')
im = Image.open("Tests/images/exif_gps.jpg")
gps_index = 34853
expected_exif_gps = {
0: b'\x00\x00\x00\x01',
0: b"\x00\x00\x00\x01",
2: (4294967295, 1),
5: b'\x01',
5: b"\x01",
30: 65535,
29: '1999:99:99 99:99:99'}
29: "1999:99:99 99:99:99",
}
# Act
exif = im._getexif()
@ -222,35 +228,39 @@ class TestFileJpeg(PillowTestCase):
# 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
# this test passes on 2.9 and 3.1, but not 3.0
expected_exif = {34867: 4294967295,
258: (24, 24, 24),
36867: '2099:09:29 10:10:10',
34853: {0: b'\x00\x00\x00\x01',
2: (4294967295, 1),
5: b'\x01',
30: 65535,
29: '1999:99:99 99:99:99'},
296: 65535,
34665: 185,
41994: 65535,
514: 4294967295,
271: 'Make',
272: 'XXX-XXX',
305: 'PIL',
42034: ((1, 1), (1, 1), (1, 1), (1, 1)),
42035: 'LensMake',
34856: b'\xaa\xaa\xaa\xaa\xaa\xaa',
282: (4294967295, 1),
33434: (4294967295, 1)}
expected_exif = {
34867: 4294967295,
258: (24, 24, 24),
36867: "2099:09:29 10:10:10",
34853: {
0: b"\x00\x00\x00\x01",
2: (4294967295, 1),
5: b"\x01",
30: 65535,
29: "1999:99:99 99:99:99",
},
296: 65535,
34665: 185,
41994: 65535,
514: 4294967295,
271: "Make",
272: "XXX-XXX",
305: "PIL",
42034: ((1, 1), (1, 1), (1, 1), (1, 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()
for tag, value in expected_exif.items():
self.assertEqual(value, exif[tag])
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
im._getexif()
@ -291,6 +301,7 @@ class TestFileJpeg(PillowTestCase):
def getsampling(im):
layer = im.layer
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
# experimental API
im = self.roundtrip(hopper(), subsampling=-1) # default
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")
self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
self.assertRaises(
TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
self.assertRaises(TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
def test_exif(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
info = im._getexif()
self.assertEqual(info[305], 'Adobe Photoshop CS Macintosh')
self.assertEqual(info[305], "Adobe Photoshop CS Macintosh")
def test_mp(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
@ -327,16 +337,16 @@ class TestFileJpeg(PillowTestCase):
def test_quality_keep(self):
# RGB
im = Image.open("Tests/images/hopper.jpg")
f = self.tempfile('temp.jpg')
im.save(f, quality='keep')
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
# Grayscale
im = Image.open("Tests/images/hopper_gray.jpg")
f = self.tempfile('temp.jpg')
im.save(f, quality='keep')
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
# CMYK
im = Image.open("Tests/images/pil_sample_cmyk.jpg")
f = self.tempfile('temp.jpg')
im.save(f, quality='keep')
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
def test_junk_jpeg_header(self):
# https://github.com/python-pillow/Pillow/issues/630
@ -364,8 +374,8 @@ class TestFileJpeg(PillowTestCase):
def _n_qtables_helper(self, n, test_file):
im = Image.open(test_file)
f = self.tempfile('temp.jpg')
im.save(f, qtables=[[n]*64]*n)
f = self.tempfile("temp.jpg")
im.save(f, qtables=[[n] * 64] * n)
im = Image.open(f)
self.assertEqual(len(im.quantization), n)
reloaded = self.roundtrip(im, qtables="keep")
@ -376,18 +386,18 @@ class TestFileJpeg(PillowTestCase):
qtables = im.quantization
reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
self.assertEqual(im.quantization, reloaded.quantization)
self.assert_image_similar(im, self.roundtrip(im, qtables='web_low'),
30)
self.assert_image_similar(im, self.roundtrip(im, qtables='web_high'),
30)
self.assert_image_similar(im, self.roundtrip(im, qtables='keep'), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="web_low"), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="web_high"), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="keep"), 30)
# valid bounds for baseline qtable
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
self.roundtrip(im, qtables=[bounds_qtable])
# 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
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
@ -396,9 +406,14 @@ class TestFileJpeg(PillowTestCase):
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
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
18 21 26 66 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
""".split(None)]
""".split(
None
)
]
# list of qtable lists
self.assert_image_similar(
im, self.roundtrip(
im, qtables=[standard_l_qtable, standard_chrominance_qtable]),
30)
im,
self.roundtrip(
im, qtables=[standard_l_qtable, standard_chrominance_qtable]
),
30,
)
# tuple of qtable lists
self.assert_image_similar(
im, self.roundtrip(
im, qtables=(standard_l_qtable, standard_chrominance_qtable)),
30)
im,
self.roundtrip(
im, qtables=(standard_l_qtable, standard_chrominance_qtable)
),
30,
)
# dict of qtable lists
self.assert_image_similar(im,
self.roundtrip(im, qtables={
0: standard_l_qtable,
1: standard_chrominance_qtable
}), 30)
self.assert_image_similar(
im,
self.roundtrip(
im, qtables={0: standard_l_qtable, 1: standard_chrominance_qtable}
),
30,
)
self._n_qtables_helper(1, "Tests/images/hopper_gray.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")
# not a sequence
self.assertRaises(ValueError, self.roundtrip, im, qtables='a')
self.assertRaises(ValueError, self.roundtrip, im, qtables="a")
# sequence wrong length
self.assertRaises(ValueError, self.roundtrip, im, qtables=[])
# sequence wrong length
self.assertRaises(ValueError,
self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
# qtable entry not a sequence
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1])
# qtable entry has wrong number of items
self.assertRaises(ValueError,
self.roundtrip, im, qtables=[[1, 2, 3, 4]])
self.assertRaises(ValueError, self.roundtrip, im, qtables=[[1, 2, 3, 4]])
@unittest.skipUnless(djpeg_available(), "djpeg not available")
def test_load_djpeg(self):
@ -468,11 +492,12 @@ class TestFileJpeg(PillowTestCase):
def test_no_duplicate_0x1001_tag(self):
# Arrange
from PIL import ExifTags
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
# Assert
self.assertEqual(tag_ids['RelatedImageWidth'], 0x1001)
self.assertEqual(tag_ids['RelatedImageLength'], 0x1002)
self.assertEqual(tag_ids["RelatedImageWidth"], 0x1001)
self.assertEqual(tag_ids["RelatedImageLength"], 0x1002)
def test_MAXBLOCK_scaling(self):
im = self.gen_random_image((512, 512))
@ -482,9 +507,9 @@ class TestFileJpeg(PillowTestCase):
reloaded = Image.open(f)
# none of these should crash
reloaded.save(f, quality='keep')
reloaded.save(f, quality='keep', progressive=True)
reloaded.save(f, quality='keep', optimize=True)
reloaded.save(f, quality="keep")
reloaded.save(f, quality="keep", progressive=True)
reloaded.save(f, quality="keep", optimize=True)
def test_bad_mpo_header(self):
""" Treat unknown MPO as JPEG """
@ -500,14 +525,14 @@ class TestFileJpeg(PillowTestCase):
def test_save_correct_modes(self):
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.save(out, "JPEG")
def test_save_wrong_modes(self):
# ref https://github.com/python-pillow/Pillow/issues/2005
out = BytesIO()
for mode in ['LA', 'La', 'RGBA', 'RGBa', 'P']:
for mode in ["LA", "La", "RGBA", "RGBa", "P"]:
img = Image.new(mode, (20, 20))
self.assertRaises(IOError, img.save, out, "JPEG")
@ -517,25 +542,25 @@ class TestFileJpeg(PillowTestCase):
im = Image.open("Tests/images/hopper.tif")
# Act
im.save(outfile, 'JPEG', dpi=im.info['dpi'])
im.save(outfile, "JPEG", dpi=im.info["dpi"])
# Assert
reloaded = Image.open(outfile)
reloaded.load()
self.assertEqual(im.info['dpi'], reloaded.info['dpi'])
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
def test_load_dpi_rounding(self):
# 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))
# 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))
def test_save_dpi_rounding(self):
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))
reloaded = Image.open(outfile)
@ -609,19 +634,26 @@ class TestFileJpeg(PillowTestCase):
im = Image.open("Tests/images/exif-ifd-offset.jpg")
# 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):
im = Image.open("Tests/images/photoshop-200dpi.jpg")
self.assertEqual(im.info["photoshop"][0x03ed], {
'XResolution': 200.0,
'DisplayedUnitsX': 1,
'YResolution': 200.0,
'DisplayedUnitsY': 1,
})
self.assertEqual(
im.info["photoshop"][0x03ED],
{
"XResolution": 200.0,
"DisplayedUnitsX": 1,
"YResolution": 200.0,
"DisplayedUnitsY": 1,
},
)
# This image does not contain a Photoshop header string
im = Image.open("Tests/images/app13.jpg")
self.assertNotIn("photoshop", im.info)
@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only")
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
class TestFileCloseW32(PillowTestCase):
def setUp(self):
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)
test_card = Image.open('Tests/images/test-card.png')
test_card = Image.open("Tests/images/test-card.png")
test_card.load()
# OpenJPEG 2.0.0 outputs this debugging message sometimes; we should
@ -14,10 +14,9 @@ test_card.load()
class TestFileJpeg2k(PillowTestCase):
def setUp(self):
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):
out = BytesIO()
@ -31,29 +30,28 @@ class TestFileJpeg2k(PillowTestCase):
def test_sanity(self):
# 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()
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.format, 'JPEG2000')
self.assertEqual(im.get_format_mimetype(), 'image/jp2')
self.assertEqual(im.format, "JPEG2000")
self.assertEqual(im.get_format_mimetype(), "image/jp2")
def test_jpf(self):
im = Image.open('Tests/images/balloon.jpf')
self.assertEqual(im.format, 'JPEG2000')
self.assertEqual(im.get_format_mimetype(), 'image/jpx')
im = Image.open("Tests/images/balloon.jpf")
self.assertEqual(im.format, "JPEG2000")
self.assertEqual(im.get_format_mimetype(), "image/jpx")
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
Jpeg2KImagePlugin.Jpeg2KImageFile, invalid_file)
self.assertRaises(SyntaxError, Jpeg2KImagePlugin.Jpeg2KImageFile, invalid_file)
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())
im = Image.open(data)
im.load()
@ -63,14 +61,14 @@ class TestFileJpeg2k(PillowTestCase):
# PIL (they were made using Adobe Photoshop)
def test_lossless(self):
im = Image.open('Tests/images/test-card-lossless.jp2')
im = Image.open("Tests/images/test-card-lossless.jp2")
im.load()
outfile = self.tempfile('temp_test-card.png')
outfile = self.tempfile("temp_test-card.png")
im.save(outfile)
self.assert_image_similar(im, test_card, 1.0e-3)
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()
self.assert_image_similar(im, test_card, 2.0)
@ -88,8 +86,8 @@ class TestFileJpeg2k(PillowTestCase):
def test_tiled_offset_rt(self):
im = self.roundtrip(
test_card, tile_size=(128, 128),
tile_offset=(0, 0), offset=(32, 32))
test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32)
)
self.assert_image_equal(im, test_card)
def test_irreversible_rt(self):
@ -97,40 +95,34 @@ class TestFileJpeg2k(PillowTestCase):
self.assert_image_similar(im, test_card, 2.0)
def test_prog_qual_rt(self):
im = self.roundtrip(
test_card, quality_layers=[60, 40, 20], progression='LRCP')
im = self.roundtrip(test_card, quality_layers=[60, 40, 20], progression="LRCP")
self.assert_image_similar(im, test_card, 2.0)
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)
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.load()
self.assertEqual(im.size, (160, 120))
def test_layers_type(self):
outfile = self.tempfile('temp_layers.jp2')
for quality_layers in [
[100, 50, 10],
(100, 50, 10),
None
]:
outfile = self.tempfile("temp_layers.jp2")
for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
test_card.save(outfile, quality_layers=quality_layers)
for quality_layers in [
'quality_layers',
('100', '50', '10')
]:
self.assertRaises(ValueError, test_card.save, outfile,
quality_layers=quality_layers)
for quality_layers in ["quality_layers", ("100", "50", "10")]:
self.assertRaises(
ValueError, test_card.save, outfile, quality_layers=quality_layers
)
def test_layers(self):
out = BytesIO()
test_card.save(out, 'JPEG2000', quality_layers=[100, 50, 10],
progression='LRCP')
test_card.save(
out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP"
)
out.seek(0)
im = Image.open(out)
@ -146,49 +138,49 @@ class TestFileJpeg2k(PillowTestCase):
def test_rgba(self):
# Arrange
j2k = Image.open('Tests/images/rgb_trns_ycbc.j2k')
jp2 = Image.open('Tests/images/rgb_trns_ycbc.jp2')
j2k = Image.open("Tests/images/rgb_trns_ycbc.j2k")
jp2 = Image.open("Tests/images/rgb_trns_ycbc.jp2")
# Act
j2k.load()
jp2.load()
# Assert
self.assertEqual(j2k.mode, 'RGBA')
self.assertEqual(jp2.mode, 'RGBA')
self.assertEqual(j2k.mode, "RGBA")
self.assertEqual(jp2.mode, "RGBA")
def test_16bit_monochrome_has_correct_mode(self):
j2k = Image.open('Tests/images/16bit.cropped.j2k')
jp2 = Image.open('Tests/images/16bit.cropped.jp2')
j2k = Image.open("Tests/images/16bit.cropped.j2k")
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
j2k.load()
jp2.load()
self.assertEqual(j2k.mode, 'I;16')
self.assertEqual(jp2.mode, 'I;16')
self.assertEqual(j2k.mode, "I;16")
self.assertEqual(jp2.mode, "I;16")
def test_16bit_monochrome_jp2_like_tiff(self):
tiff_16bit = Image.open('Tests/images/16bit.cropped.tif')
jp2 = Image.open('Tests/images/16bit.cropped.jp2')
tiff_16bit = Image.open("Tests/images/16bit.cropped.tif")
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
self.assert_image_similar(jp2, tiff_16bit, 1e-3)
def test_16bit_monochrome_j2k_like_tiff(self):
tiff_16bit = Image.open('Tests/images/16bit.cropped.tif')
j2k = Image.open('Tests/images/16bit.cropped.j2k')
tiff_16bit = Image.open("Tests/images/16bit.cropped.tif")
j2k = Image.open("Tests/images/16bit.cropped.j2k")
self.assert_image_similar(j2k, tiff_16bit, 1e-3)
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)
self.assert_image_equal(im, j2k)
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)
self.assert_image_equal(im, jp2)
@ -196,12 +188,13 @@ class TestFileJpeg2k(PillowTestCase):
# prepatch, a malformed jp2 file could cause an UnboundLocalError
# exception.
with self.assertRaises(IOError):
Image.open('Tests/images/unbound_variable.jp2')
Image.open("Tests/images/unbound_variable.jp2")
def test_parser_feed(self):
# Arrange
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()
# Act

View File

@ -16,9 +16,8 @@ logger = logging.getLogger(__name__)
class LibTiffTestCase(PillowTestCase):
def setUp(self):
if not features.check('libtiff'):
if not features.check("libtiff"):
self.skipTest("tiff support not available")
def _assert_noerr(self, im):
@ -31,7 +30,7 @@ class LibTiffTestCase(PillowTestCase):
im.getdata()
try:
self.assertEqual(im._compression, 'group4')
self.assertEqual(im._compression, "group4")
except AttributeError:
print("No _compression")
print(dir(im))
@ -41,11 +40,10 @@ class LibTiffTestCase(PillowTestCase):
im.save(out)
out_bytes = io.BytesIO()
im.save(out_bytes, format='tiff', compression='group4')
im.save(out_bytes, format="tiff", compression="group4")
class TestFileLibTiff(LibTiffTestCase):
def test_g4_tiff(self):
"""Test the ordinary file path load path"""
@ -64,7 +62,7 @@ class TestFileLibTiff(LibTiffTestCase):
"""Testing the string load path"""
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)
self.assertEqual(im.size, (500, 500))
@ -74,7 +72,7 @@ class TestFileLibTiff(LibTiffTestCase):
"""Testing the stringio loading code path"""
test_file = "Tests/images/hopper_g4_500.tif"
s = io.BytesIO()
with open(test_file, 'rb') as f:
with open(test_file, "rb") as f:
s.write(f.read())
s.seek(0)
im = Image.open(s)
@ -84,16 +82,16 @@ class TestFileLibTiff(LibTiffTestCase):
def test_g4_eq_png(self):
""" Checking that we're actually getting the data that we expect"""
png = Image.open('Tests/images/hopper_bw_500.png')
g4 = Image.open('Tests/images/hopper_g4_500.tif')
png = Image.open("Tests/images/hopper_bw_500.png")
g4 = Image.open("Tests/images/hopper_g4_500.tif")
self.assert_image_equal(g4, png)
# see https://github.com/python-pillow/Pillow/issues/279
def test_g4_fillorder_eq_png(self):
""" Checking that we're actually getting the data that we expect"""
png = Image.open('Tests/images/g4-fillorder-test.png')
g4 = Image.open('Tests/images/g4-fillorder-test.tif')
png = Image.open("Tests/images/g4-fillorder-test.png")
g4 = Image.open("Tests/images/g4-fillorder-test.tif")
self.assert_image_equal(g4, png)
@ -111,9 +109,9 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(reread.size, (500, 500))
self._assert_noerr(reread)
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())
@ -123,18 +121,16 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (278, 374))
self.assertEqual(
im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0))
self.assertEqual(im.tile[0][:3], ("libtiff", (0, 0, 278, 374), 0))
im.load()
self.assert_image_equal_tofile(im,
'Tests/images/tiff_adobe_deflate.png')
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_write_metadata(self):
""" Test metadata writing through libtiff """
for legacy_api in [False, True]:
img = Image.open('Tests/images/hopper_g4.tif')
f = self.tempfile('temp.tiff')
img = Image.open("Tests/images/hopper_g4.tif")
f = self.tempfile("temp.tiff")
img.save(f, tiffinfo=img.tag)
@ -145,8 +141,12 @@ class TestFileLibTiff(LibTiffTestCase):
# PhotometricInterpretation is set from SAVE_INFO,
# not the original image.
ignored = ['StripByteCounts', 'RowsPerStrip', 'PageNumber',
'PhotometricInterpretation']
ignored = [
"StripByteCounts",
"RowsPerStrip",
"PageNumber",
"PhotometricInterpretation",
]
loaded = Image.open(f)
if legacy_api:
@ -154,28 +154,27 @@ class TestFileLibTiff(LibTiffTestCase):
else:
reloaded = loaded.tag_v2.named()
for tag, value in itertools.chain(reloaded.items(),
original.items()):
for tag, value in itertools.chain(reloaded.items(), original.items()):
if tag not in ignored:
val = original[tag]
if tag.endswith('Resolution'):
if tag.endswith("Resolution"):
if legacy_api:
self.assertEqual(
c_float(val[0][0] / val[0][1]).value,
c_float(value[0][0] / value[0][1]).value,
msg="%s didn't roundtrip" % tag)
msg="%s didn't roundtrip" % tag,
)
else:
self.assertEqual(
c_float(val).value, c_float(value).value,
msg="%s didn't roundtrip" % tag)
c_float(val).value,
c_float(value).value,
msg="%s didn't roundtrip" % tag,
)
else:
self.assertEqual(
val, value, msg="%s didn't roundtrip" % tag)
self.assertEqual(val, value, msg="%s didn't roundtrip" % tag)
# https://github.com/python-pillow/Pillow/issues/1561
requested_fields = ['StripByteCounts',
'RowsPerStrip',
'StripOffsets']
requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"]
for field in requested_fields:
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
core_items = {tag: info for tag, info in ((s, TiffTags.lookup(s)) for s
in TiffTags.LIBTIFF_CORE)
if info.type is not None}
core_items = {
tag: info
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
# 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:
try:
del core_items[tag]
@ -206,11 +207,13 @@ class TestFileLibTiff(LibTiffTestCase):
# 5: "rational",
# 12: "double",
# Type: dummy value
values = {2: 'test',
3: 1,
4: 2**20,
5: TiffImagePlugin.IFDRational(100, 1),
12: 1.05}
values = {
2: "test",
3: 1,
4: 2 ** 20,
5: TiffImagePlugin.IFDRational(100, 1),
12: 1.05,
}
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
for tag, info in core_items.items():
@ -219,8 +222,7 @@ class TestFileLibTiff(LibTiffTestCase):
if info.length == 0:
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
else:
new_ifd[tag] = tuple(values[info.type]
for _ in range(info.length))
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
# Extra samples really doesn't make sense in this application.
del new_ifd[338]
@ -236,16 +238,17 @@ class TestFileLibTiff(LibTiffTestCase):
custom = {
37000: [4, TiffTags.SHORT],
37001: [4.2, TiffTags.RATIONAL],
37002: ['custom tag value', TiffTags.ASCII],
37003: [u'custom tag value', TiffTags.ASCII],
37004: [b'custom tag value', TiffTags.BYTE]
37002: ["custom tag value", TiffTags.ASCII],
37003: [u"custom tag value", TiffTags.ASCII],
37004: [b"custom tag value", TiffTags.BYTE],
}
libtiff_version = TiffImagePlugin._libtiff_version()
libtiffs = [False]
if distutils.version.StrictVersion(libtiff_version) >= \
distutils.version.StrictVersion("4.0"):
if distutils.version.StrictVersion(
libtiff_version
) >= distutils.version.StrictVersion("4.0"):
libtiffs.append(True)
for libtiff in libtiffs:
@ -281,68 +284,68 @@ class TestFileLibTiff(LibTiffTestCase):
def test_int_dpi(self):
# issue #1765
im = hopper('RGB')
out = self.tempfile('temp.tif')
im = hopper("RGB")
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out, dpi=(72, 72))
TiffImagePlugin.WRITE_LIBTIFF = False
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):
i = Image.open('Tests/images/hopper_g4_500.tif')
i = Image.open("Tests/images/hopper_g4_500.tif")
out = self.tempfile("temp.tif")
i.save(out, compression='group3')
i.save(out, compression="group3")
reread = Image.open(out)
self.assertEqual(reread.info['compression'], 'group3')
self.assertEqual(reread.info["compression"], "group3")
self.assert_image_equal(reread, i)
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.mode, 'I;16')
self.assertEqual(im.mode, "I;16")
b = im.tobytes()
# Bytes are in image native order (little endian)
if py3:
self.assertEqual(b[0], ord(b'\xe0'))
self.assertEqual(b[1], ord(b'\x01'))
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
else:
self.assertEqual(b[0], b'\xe0')
self.assertEqual(b[1], b'\x01')
self.assertEqual(b[0], b"\xe0")
self.assertEqual(b[1], b"\x01")
out = self.tempfile("temp.tif")
# out = "temp.le.tif"
im.save(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)
# UNDONE - libtiff defaults to writing in native endian, so
# on big endian, we'll get back mode = 'I;16B' here.
def test_big_endian(self):
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.mode, 'I;16B')
self.assertEqual(im.mode, "I;16B")
b = im.tobytes()
# Bytes are in image native order (big endian)
if py3:
self.assertEqual(b[0], ord(b'\x01'))
self.assertEqual(b[1], ord(b'\xe0'))
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
else:
self.assertEqual(b[0], b'\x01')
self.assertEqual(b[1], b'\xe0')
self.assertEqual(b[0], b"\x01")
self.assertEqual(b[1], b"\xe0")
out = self.tempfile("temp.tif")
im.save(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)
def test_g4_string_info(self):
@ -352,18 +355,18 @@ class TestFileLibTiff(LibTiffTestCase):
out = self.tempfile("temp.tif")
orig.tag[269] = 'temp.tif'
orig.tag[269] = "temp.tif"
orig.save(out)
reread = Image.open(out)
self.assertEqual('temp.tif', reread.tag_v2[269])
self.assertEqual('temp.tif', reread.tag[269][0])
self.assertEqual("temp.tif", reread.tag_v2[269])
self.assertEqual("temp.tif", reread.tag[269][0])
def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open('Tests/images/12bit.cropped.tif')
im = Image.open("Tests/images/12bit.cropped.tif")
im.load()
TiffImagePlugin.READ_LIBTIFF = False
# to make the target --
@ -372,18 +375,19 @@ class TestFileLibTiff(LibTiffTestCase):
# 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.
self.assert_image_equal_tofile(im, 'Tests/images/12in16bit.tif')
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
def test_blur(self):
# test case from irc, how to do blur on b/w image
# and save to compressed tif.
from PIL import ImageFilter
out = self.tempfile('temp.tif')
im = Image.open('Tests/images/pport_g4.tif')
im = im.convert('L')
out = self.tempfile("temp.tif")
im = Image.open("Tests/images/pport_g4.tif")
im = im.convert("L")
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.load()
@ -391,23 +395,23 @@ class TestFileLibTiff(LibTiffTestCase):
self.assert_image_equal(im, im2)
def test_compressions(self):
im = hopper('RGB')
out = self.tempfile('temp.tif')
im = hopper("RGB")
out = self.tempfile("temp.tif")
for compression in ('packbits', 'tiff_lzw'):
for compression in ("packbits", "tiff_lzw"):
im.save(out, compression=compression)
im2 = Image.open(out)
self.assert_image_equal(im, im2)
im.save(out, compression='jpeg')
im.save(out, compression="jpeg")
im2 = Image.open(out)
self.assert_image_similar(im, im2, 30)
def test_cmyk_save(self):
im = hopper('CMYK')
out = self.tempfile('temp.tif')
im = hopper("CMYK")
out = self.tempfile("temp.tif")
im.save(out, compression='tiff_adobe_deflate')
im.save(out, compression="tiff_adobe_deflate")
im2 = Image.open(out)
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
capture that but not now"""
im = hopper('RGB')
out = self.tempfile('temp.tif')
im = hopper("RGB")
out = self.tempfile("temp.tif")
self.assertRaises(IOError, im.save, out, compression='tiff_ccitt')
self.assertRaises(IOError, im.save, out, compression='group3')
self.assertRaises(IOError, im.save, out, compression='group4')
self.assertRaises(IOError, im.save, out, compression="tiff_ccitt")
self.assertRaises(IOError, im.save, out, compression="group3")
self.assertRaises(IOError, im.save, out, compression="group4")
def test_fp_leak(self):
im = Image.open("Tests/images/hopper_g4_500.tif")
@ -437,30 +441,30 @@ class TestFileLibTiff(LibTiffTestCase):
def test_multipage(self):
# issue #862
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
im.seek(0)
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)
im.seek(1)
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)
im.seek(2)
self.assertFalse(im.tag.next)
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
def test_multipage_nframes(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open('Tests/images/multipage.tiff')
im = Image.open("Tests/images/multipage.tiff")
frames = im.n_frames
self.assertEqual(frames, 3)
for _ in range(frames):
@ -472,7 +476,7 @@ class TestFileLibTiff(LibTiffTestCase):
def test__next(self):
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open('Tests/images/hopper.tif')
im = Image.open("Tests/images/hopper.tif")
self.assertFalse(im.tag.next)
im.load()
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/hopper2R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
)
),
),
(
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/hopper4R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
)
),
),
)
original = hopper("L")
@ -545,7 +549,7 @@ class TestFileLibTiff(LibTiffTestCase):
self.assert_image_similar(pilim, pilim_load, 0)
save_bytesio()
save_bytesio('raw')
save_bytesio("raw")
save_bytesio("packbits")
save_bytesio("tiff_lzw")
@ -554,12 +558,12 @@ class TestFileLibTiff(LibTiffTestCase):
def test_crashing_metadata(self):
# issue 1597
im = Image.open('Tests/images/rdf.tif')
out = self.tempfile('temp.tif')
im = Image.open("Tests/images/rdf.tif")
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
# this shouldn't crash
im.save(out, format='TIFF')
im.save(out, format="TIFF")
TiffImagePlugin.WRITE_LIBTIFF = False
def test_page_number_x_0(self):
@ -580,8 +584,8 @@ class TestFileLibTiff(LibTiffTestCase):
# https://github.com/python-pillow/Pillow/issues/1651
tmpfile = self.tempfile("temp.tif")
with open(tmpfile, 'wb') as f:
with open("Tests/images/g4-multi.tiff", 'rb') as src:
with open(tmpfile, "wb") as f:
with open("Tests/images/g4-multi.tiff", "rb") as src:
f.write(src.read())
im = Image.open(tmpfile)
@ -592,29 +596,29 @@ class TestFileLibTiff(LibTiffTestCase):
def test_read_icc(self):
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)
TiffImagePlugin.READ_LIBTIFF = True
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)
TiffImagePlugin.READ_LIBTIFF = False
self.assertEqual(icc, icc_libtiff)
def test_multipage_compression(self):
im = Image.open('Tests/images/compression.tif')
im = Image.open("Tests/images/compression.tif")
im.seek(0)
self.assertEqual(im._compression, 'tiff_ccitt')
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.seek(1)
self.assertEqual(im._compression, 'packbits')
self.assertEqual(im._compression, "packbits")
self.assertEqual(im.size, (10, 10))
im.load()
im.seek(0)
self.assertEqual(im._compression, 'tiff_ccitt')
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.load()
@ -631,6 +635,26 @@ class TestFileLibTiff(LibTiffTestCase):
# Should not raise UnicodeDecodeError or anything else
im.save(outfile)
def test_16bit_RGB_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGB.tiff")
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
[
(
"libtiff",
(0, 0, 100, 40),
0,
("RGB;16N", "tiff_adobe_deflate", False, 8),
)
],
)
im.load()
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
def test_16bit_RGBa_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGBa.tiff")
@ -638,12 +662,11 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
[('tiff_lzw', (0, 0, 100, 40), 0, ('RGBa;16N', 'tiff_lzw', False))]
[("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236))],
)
im.load()
self.assert_image_equal_tofile(
im, "Tests/images/tiff_16bit_RGBa_target.png")
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
def test_gimp_tiff(self):
# Read TIFF JPEG images from GIMP [@PIL168]
@ -658,7 +681,7 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (256, 256))
self.assertEqual(
im.tile, [('jpeg', (0, 0, 256, 256), 0, ('RGB', 'jpeg', False))]
im.tile, [("libtiff", (0, 0, 256, 256), 0, ("RGB", "jpeg", False, 5122))]
)
im.load()
@ -667,15 +690,14 @@ class TestFileLibTiff(LibTiffTestCase):
def test_sampleformat(self):
# https://github.com/python-pillow/Pillow/issues/1466
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",
mode='RGB')
self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")
def test_lzw(self):
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.format, "TIFF")
im2 = hopper()
@ -687,6 +709,12 @@ class TestFileLibTiff(LibTiffTestCase):
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
def test_strip_cmyk_16l_jpeg(self):
infile = "Tests/images/tiff_strip_cmyk_16l_jpeg.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
def test_strip_ycbcr_jpeg_2x2_sampling(self):
infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif"
im = Image.open(infile)
@ -721,5 +749,6 @@ class TestFileLibTiff(LibTiffTestCase):
infile = "Tests/images/old-style-jpeg-compression.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im,
"Tests/images/old-style-jpeg-compression.png")
self.assert_image_equal_tofile(
im, "Tests/images/old-style-jpeg-compression.png"
)

View File

@ -17,7 +17,7 @@ class TestFileLibTiffSmall(LibTiffTestCase):
"""Testing the open file load path"""
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)
self.assertEqual(im.size, (128, 128))
@ -26,9 +26,10 @@ class TestFileLibTiffSmall(LibTiffTestCase):
def test_g4_hopper_bytesio(self):
"""Testing the bytesio loading code path"""
from io import BytesIO
test_file = "Tests/images/hopper_g4.tif"
s = BytesIO()
with open(test_file, 'rb') as f:
with open(test_file, "rb") as f:
s.write(f.read())
s.seek(0)
im = Image.open(s)

View File

@ -4,12 +4,10 @@ from PIL import Image, McIdasImagePlugin
class TestFileMcIdas(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
McIdasImagePlugin.McIdasImageFile, invalid_file)
self.assertRaises(SyntaxError, McIdasImagePlugin.McIdasImageFile, invalid_file)
def test_valid_file(self):
# Arrange

View File

@ -13,9 +13,8 @@ TEST_FILE = "Tests/images/hopper.mic"
@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):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
@ -24,8 +23,8 @@ class TestFileMic(PillowTestCase):
self.assertEqual(im.format, "MIC")
# Adjust for the gamma of 2.2 encoded into the file
lut = ImagePalette.make_gamma_lut(1/2.2)
im = Image.merge('RGBA', [chan.point(lut) for chan in im.split()])
lut = ImagePalette.make_gamma_lut(1 / 2.2)
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
im2 = hopper("RGBA")
self.assert_image_similar(im, im2, 10)
@ -57,10 +56,8 @@ class TestFileMic(PillowTestCase):
def test_invalid_file(self):
# Test an invalid OLE file
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
MicImagePlugin.MicImageFile, invalid_file)
self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, invalid_file)
# Test a valid OLE file, but not a MIC file
ole_file = "Tests/images/test-ole-file.doc"
self.assertRaises(SyntaxError,
MicImagePlugin.MicImageFile, ole_file)
self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, ole_file)

View File

@ -7,7 +7,6 @@ test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
class TestFileMpo(PillowTestCase):
def setUp(self):
codecs = dir(Image.core)
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
@ -35,23 +34,25 @@ class TestFileMpo(PillowTestCase):
def open():
im = Image.open(test_files[0])
im.load()
self.assert_warning(None, open)
def test_app(self):
for test_file in test_files:
# Test APP/COM reader (@PIL135)
im = Image.open(test_file)
self.assertEqual(im.applist[0][0], 'APP1')
self.assertEqual(im.applist[1][0], 'APP2')
self.assertEqual(im.applist[1][1][:16],
b'MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00')
self.assertEqual(im.applist[0][0], "APP1")
self.assertEqual(im.applist[1][0], "APP2")
self.assertEqual(
im.applist[1][1][:16], b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
)
self.assertEqual(len(im.applist), 2)
def test_exif(self):
for test_file in test_files:
im = Image.open(test_file)
info = im._getexif()
self.assertEqual(info[272], 'Nintendo 3DS')
self.assertEqual(info[272], "Nintendo 3DS")
self.assertEqual(info[296], 2)
self.assertEqual(info[34665], 188)
@ -68,19 +69,19 @@ class TestFileMpo(PillowTestCase):
# Nintendo
im = Image.open("Tests/images/sugarshack.mpo")
exif = im.getexif()
self.assertEqual(exif.get_ifd(0x927c)[0x1101]["Parallax"], -44.798187255859375)
self.assertEqual(exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375)
# Fujifilm
im = Image.open("Tests/images/fujifilm.mpo")
im.seek(1)
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):
for test_file in test_files:
im = Image.open(test_file)
mpinfo = im._getmp()
self.assertEqual(mpinfo[45056], b'0100')
self.assertEqual(mpinfo[45056], b"0100")
self.assertEqual(mpinfo[45057], 2)
def test_mp_offset(self):
@ -88,7 +89,7 @@ class TestFileMpo(PillowTestCase):
# in APP2 data, in contrast to normal 8
im = Image.open("Tests/images/sugarshack_ifd_offset.mpo")
mpinfo = im._getmp()
self.assertEqual(mpinfo[45056], b'0100')
self.assertEqual(mpinfo[45056], b"0100")
self.assertEqual(mpinfo[45057], 2)
def test_mp_attribute(self):
@ -97,17 +98,16 @@ class TestFileMpo(PillowTestCase):
mpinfo = im._getmp()
frameNumber = 0
for mpentry in mpinfo[45058]:
mpattr = mpentry['Attribute']
mpattr = mpentry["Attribute"]
if frameNumber:
self.assertFalse(mpattr['RepresentativeImageFlag'])
self.assertFalse(mpattr["RepresentativeImageFlag"])
else:
self.assertTrue(mpattr['RepresentativeImageFlag'])
self.assertFalse(mpattr['DependentParentImageFlag'])
self.assertFalse(mpattr['DependentChildImageFlag'])
self.assertEqual(mpattr['ImageDataFormat'], 'JPEG')
self.assertEqual(mpattr['MPType'],
'Multi-Frame Image: (Disparity)')
self.assertEqual(mpattr['Reserved'], 0)
self.assertTrue(mpattr["RepresentativeImageFlag"])
self.assertFalse(mpattr["DependentParentImageFlag"])
self.assertFalse(mpattr["DependentChildImageFlag"])
self.assertEqual(mpattr["ImageDataFormat"], "JPEG")
self.assertEqual(mpattr["MPType"], "Multi-Frame Image: (Disparity)")
self.assertEqual(mpattr["Reserved"], 0)
frameNumber += 1
def test_seek(self):
@ -144,7 +144,7 @@ class TestFileMpo(PillowTestCase):
self.assertLess(im.tell(), n_frames)
# 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):
for test_file in test_files:

View File

@ -10,7 +10,6 @@ YA_EXTRA_DIR = "Tests/images/msp"
class TestFileMsp(PillowTestCase):
def test_sanity(self):
test_file = self.tempfile("temp.msp")
@ -25,8 +24,7 @@ class TestFileMsp(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
MspImagePlugin.MspImageFile, invalid_file)
self.assertRaises(SyntaxError, MspImagePlugin.MspImageFile, invalid_file)
def test_bad_checksum(self):
# Arrange
@ -34,8 +32,7 @@ class TestFileMsp(PillowTestCase):
bad_checksum = "Tests/images/hopper_bad_checksum.msp"
# Act / Assert
self.assertRaises(SyntaxError,
MspImagePlugin.MspImageFile, bad_checksum)
self.assertRaises(SyntaxError, MspImagePlugin.MspImageFile, bad_checksum)
def test_open_windows_v1(self):
# Arrange
@ -51,25 +48,26 @@ class TestFileMsp(PillowTestCase):
target = Image.open(target_path)
self.assert_image_equal(im, target)
@unittest.skipIf(not os.path.exists(EXTRA_DIR),
"Extra image files not installed")
@unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed")
def test_open_windows_v2(self):
files = (os.path.join(EXTRA_DIR, f) for f in os.listdir(EXTRA_DIR)
if os.path.splitext(f)[1] == '.msp')
files = (
os.path.join(EXTRA_DIR, f)
for f in os.listdir(EXTRA_DIR)
if os.path.splitext(f)[1] == ".msp"
)
for path in files:
self._assert_file_image_equal(path,
path.replace('.msp', '.png'))
self._assert_file_image_equal(path, path.replace(".msp", ".png"))
@unittest.skipIf(not os.path.exists(YA_EXTRA_DIR),
"Even More Extra image files not installed")
@unittest.skipIf(
not os.path.exists(YA_EXTRA_DIR), "Even More Extra image files not installed"
)
def test_msp_v2(self):
for f in os.listdir(YA_EXTRA_DIR):
if '.MSP' not in f:
if ".MSP" not in f:
continue
path = os.path.join(YA_EXTRA_DIR, f)
self._assert_file_image_equal(path,
path.replace('.MSP', '.png'))
self._assert_file_image_equal(path, path.replace(".MSP", ".png"))
def test_cannot_save_wrong_mode(self):
# Arrange

View File

@ -46,6 +46,13 @@ class TestFilePalm(PillowTestCase):
self.skipKnownBadTest("Palm P image is wrong")
self.roundtrip(mode)
def test_l_ioerror(self):
# Arrange
mode = "L"
# Act / Assert
self.assertRaises(IOError, self.helper_save_as_palm, mode)
def test_rgb_ioerror(self):
# Arrange
mode = "RGB"

View File

@ -3,9 +3,8 @@ from PIL import Image
class TestFilePcd(PillowTestCase):
def test_load_raw(self):
im = Image.open('Tests/images/hopper.pcd')
im = Image.open("Tests/images/hopper.pcd")
im.load() # should not segfault.
# 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):
def _roundtrip(self, im):
f = self.tempfile("temp.pcx")
im.save(f)
@ -17,7 +16,7 @@ class TestFilePcx(PillowTestCase):
self.assert_image_equal(im2, im)
def test_sanity(self):
for mode in ('1', 'L', 'P', 'RGB'):
for mode in ("1", "L", "P", "RGB"):
self._roundtrip(hopper(mode))
# Test an unsupported mode
@ -28,14 +27,13 @@ class TestFilePcx(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
PcxImagePlugin.PcxImageFile, invalid_file)
self.assertRaises(SyntaxError, PcxImagePlugin.PcxImageFile, invalid_file)
def test_odd(self):
# see issue #523, odd sized images should have a stride that's even.
# not that imagemagick or gimp write pcx that way.
# 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
# we handle interrupted scan lines properly.
self._roundtrip(hopper(mode).resize((511, 511)))
@ -50,17 +48,17 @@ class TestFilePcx(PillowTestCase):
self.assertEqual(im.tile[0][1], (0, 0, 447, 144))
# 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):
im = Image.new('L', (1, 256))
im = Image.new("L", (1, 256))
px = im.load()
for y in range(256):
px[0, y] = y
self._roundtrip(im)
def test_large_count(self):
im = Image.new('L', (256, 1))
im = Image.new("L", (256, 1))
px = im.load()
for x in range(256):
px[x, 0] = x // 67 * 67
@ -75,7 +73,7 @@ class TestFilePcx(PillowTestCase):
ImageFile.MAXBLOCK = _last
def test_break_in_count_overflow(self):
im = Image.new('L', (256, 5))
im = Image.new("L", (256, 5))
px = im.load()
for y in range(4):
for x in range(256):
@ -83,7 +81,7 @@ class TestFilePcx(PillowTestCase):
self._test_buffer_overflow(im)
def test_break_one_in_loop(self):
im = Image.new('L', (256, 5))
im = Image.new("L", (256, 5))
px = im.load()
for y in range(5):
for x in range(256):
@ -91,7 +89,7 @@ class TestFilePcx(PillowTestCase):
self._test_buffer_overflow(im)
def test_break_many_in_loop(self):
im = Image.new('L', (256, 5))
im = Image.new("L", (256, 5))
px = im.load()
for y in range(4):
for x in range(256):
@ -101,7 +99,7 @@ class TestFilePcx(PillowTestCase):
self._test_buffer_overflow(im)
def test_break_one_at_end(self):
im = Image.new('L', (256, 5))
im = Image.new("L", (256, 5))
px = im.load()
for y in range(5):
for x in range(256):
@ -110,7 +108,7 @@ class TestFilePcx(PillowTestCase):
self._test_buffer_overflow(im)
def test_break_many_at_end(self):
im = Image.new('L', (256, 5))
im = Image.new("L", (256, 5))
px = im.load()
for y in range(5):
for x in range(256):
@ -121,7 +119,7 @@ class TestFilePcx(PillowTestCase):
self._test_buffer_overflow(im)
def test_break_padding(self):
im = Image.new('L', (257, 5))
im = Image.new("L", (257, 5))
px = im.load()
for y in range(5):
for x in range(257):

View File

@ -8,7 +8,6 @@ import time
class TestFilePdf(PillowTestCase):
def helper_save_as_pdf(self, mode, **kwargs):
# Arrange
im = hopper(mode)
@ -21,11 +20,17 @@ class TestFilePdf(PillowTestCase):
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
with PdfParser.PdfParser(outfile) as pdf:
if kwargs.get("append_images", False) or \
kwargs.get("append", False):
if kwargs.get("append_images", False) or kwargs.get("append", False):
self.assertGreater(len(pdf.pages), 1)
else:
self.assertGreater(len(pdf.pages), 0)
with open(outfile, "rb") as fp:
contents = fp.read()
size = tuple(
int(d)
for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
)
self.assertEqual(im.size, size)
return outfile
@ -77,7 +82,7 @@ class TestFilePdf(PillowTestCase):
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
outfile = self.tempfile('temp.pdf')
outfile = self.tempfile("temp.pdf")
im.save(outfile, save_all=True)
self.assertTrue(os.path.isfile(outfile))
@ -94,6 +99,7 @@ class TestFilePdf(PillowTestCase):
def imGenerator(ims):
for im in ims:
yield im
im.save(outfile, save_all=True, append_images=imGenerator(ims))
self.assertTrue(os.path.isfile(outfile))
@ -110,7 +116,7 @@ class TestFilePdf(PillowTestCase):
# Test saving a multiframe image without save_all
im = Image.open("Tests/images/dispose_bgnd.gif")
outfile = self.tempfile('temp.pdf')
outfile = self.tempfile("temp.pdf")
im.save(outfile)
self.assertTrue(os.path.isfile(outfile))
@ -119,8 +125,8 @@ class TestFilePdf(PillowTestCase):
def test_pdf_open(self):
# fail on a buffer full of null bytes
self.assertRaises(
PdfParser.PdfFormatError,
PdfParser.PdfParser, buf=bytearray(65536))
PdfParser.PdfFormatError, PdfParser.PdfParser, buf=bytearray(65536)
)
# make an empty PDF object
with PdfParser.PdfParser() as empty_pdf:
@ -157,10 +163,9 @@ class TestFilePdf(PillowTestCase):
im = hopper("RGB")
temp_dir = tempfile.mkdtemp()
try:
self.assertRaises(IOError,
im.save,
os.path.join(temp_dir, "nonexistent.pdf"),
append=True)
self.assertRaises(
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
)
finally:
os.rmdir(temp_dir)
@ -189,9 +194,9 @@ class TestFilePdf(PillowTestCase):
with PdfParser.PdfParser(pdf_filename, mode="r+b") as pdf:
self.assertEqual(len(pdf.pages), 1)
self.assertEqual(len(pdf.info), 4)
self.assertEqual(pdf.info.Title, os.path.splitext(
os.path.basename(pdf_filename)
)[0])
self.assertEqual(
pdf.info.Title, os.path.splitext(os.path.basename(pdf_filename))[0]
)
self.assertEqual(pdf.info.Producer, "PdfParser")
self.assertIn(b"CreationDate", pdf.info)
self.assertIn(b"ModDate", pdf.info)
@ -218,8 +223,7 @@ class TestFilePdf(PillowTestCase):
# append two images
mode_CMYK = hopper("CMYK")
mode_P = hopper("P")
mode_CMYK.save(pdf_filename,
append=True, save_all=True, append_images=[mode_P])
mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P])
# open the PDF again, check pages and info again
with PdfParser.PdfParser(pdf_filename) as pdf:
@ -237,10 +241,16 @@ class TestFilePdf(PillowTestCase):
def test_pdf_info(self):
# make a PDF file
pdf_filename = self.helper_save_as_pdf(
"RGB", title="title", author="author", subject="subject",
keywords="keywords", creator="creator", producer="producer",
"RGB",
title="title",
author="author",
subject="subject",
keywords="keywords",
creator="creator",
producer="producer",
creationDate=time.strptime("2000", "%Y"),
modDate=time.strptime("2001", "%Y"))
modDate=time.strptime("2001", "%Y"),
)
# open it, check pages and info
with PdfParser.PdfParser(pdf_filename) as pdf:
@ -251,8 +261,7 @@ class TestFilePdf(PillowTestCase):
self.assertEqual(pdf.info.Keywords, "keywords")
self.assertEqual(pdf.info.Creator, "creator")
self.assertEqual(pdf.info.Producer, "producer")
self.assertEqual(pdf.info.CreationDate,
time.strptime("2000", "%Y"))
self.assertEqual(pdf.info.CreationDate, time.strptime("2000", "%Y"))
self.assertEqual(pdf.info.ModDate, time.strptime("2001", "%Y"))
self.check_pdf_pages_consistency(pdf)

View File

@ -6,7 +6,6 @@ TEST_FILE = "Tests/images/hopper.pxr"
class TestFilePixar(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
@ -21,6 +20,4 @@ class TestFilePixar(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(
SyntaxError,
PixarImagePlugin.PixarImageFile, invalid_file)
self.assertRaises(SyntaxError, PixarImagePlugin.PixarImageFile, invalid_file)

View File

@ -8,6 +8,7 @@ import sys
try:
from PIL import _webp
HAVE_WEBP = True
except ImportError:
HAVE_WEBP = False
@ -32,7 +33,7 @@ def chunk(cid, *data):
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")
IEND = chunk(b"IEND")
@ -52,7 +53,6 @@ def roundtrip(im, **options):
class TestFilePng(PillowTestCase):
def setUp(self):
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
self.skipTest("zip/deflate support not available")
@ -86,7 +86,7 @@ class TestFilePng(PillowTestCase):
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
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"]:
im = hopper(mode)
@ -99,8 +99,7 @@ class TestFilePng(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
PngImagePlugin.PngImageFile, invalid_file)
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, invalid_file)
def test_broken(self):
# Check reading of totally broken files. In this case, the test
@ -112,76 +111,83 @@ class TestFilePng(PillowTestCase):
def test_bad_text(self):
# 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, {})
im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL)
self.assertEqual(im.info, {'spam': ''})
im = load(HEAD + chunk(b"tEXt", b"spam") + TAIL)
self.assertEqual(im.info, {"spam": ""})
im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL)
self.assertEqual(im.info, {'spam': ''})
im = load(HEAD + chunk(b"tEXt", b"spam\0") + TAIL)
self.assertEqual(im.info, {"spam": ""})
im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL)
self.assertEqual(im.info, {'spam': 'egg'})
im = load(HEAD + chunk(b"tEXt", b"spam\0egg") + TAIL)
self.assertEqual(im.info, {"spam": "egg"})
im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL)
self.assertEqual(im.info, {'spam': 'egg\x00'})
im = load(HEAD + chunk(b"tEXt", b"spam\0egg\0") + TAIL)
self.assertEqual(im.info, {"spam": "egg\x00"})
def test_bad_ztxt(self):
# 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, {})
im = load(HEAD + chunk(b'zTXt', b'spam') + TAIL)
self.assertEqual(im.info, {'spam': ''})
im = load(HEAD + chunk(b"zTXt", b"spam") + TAIL)
self.assertEqual(im.info, {"spam": ""})
im = load(HEAD + chunk(b'zTXt', b'spam\0') + TAIL)
self.assertEqual(im.info, {'spam': ''})
im = load(HEAD + chunk(b"zTXt", b"spam\0") + TAIL)
self.assertEqual(im.info, {"spam": ""})
im = load(HEAD + chunk(b'zTXt', b'spam\0\0') + TAIL)
self.assertEqual(im.info, {'spam': ''})
im = load(HEAD + chunk(b"zTXt", b"spam\0\0") + TAIL)
self.assertEqual(im.info, {"spam": ""})
im = load(HEAD + chunk(
b'zTXt', b'spam\0\0' + zlib.compress(b'egg')[:1]) + TAIL)
self.assertEqual(im.info, {'spam': ''})
im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")[:1]) + TAIL)
self.assertEqual(im.info, {"spam": ""})
im = load(
HEAD + chunk(b'zTXt', b'spam\0\0' + zlib.compress(b'egg')) + TAIL)
self.assertEqual(im.info, {'spam': 'egg'})
im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")) + TAIL)
self.assertEqual(im.info, {"spam": "egg"})
def test_bad_itxt(self):
im = load(HEAD + chunk(b'iTXt') + TAIL)
im = load(HEAD + chunk(b"iTXt") + TAIL)
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, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0') + TAIL)
im = load(HEAD + chunk(b"iTXt", b"spam\0") + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\x02') + TAIL)
im = load(HEAD + chunk(b"iTXt", b"spam\0\x02") + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\0\0foo\0') + TAIL)
im = load(HEAD + chunk(b"iTXt", b"spam\0\0\0foo\0") + TAIL)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\0\0en\0Spam\0egg') + TAIL)
im = load(HEAD + chunk(b"iTXt", b"spam\0\0\0en\0Spam\0egg") + TAIL)
self.assertEqual(im.info, {"spam": "egg"})
self.assertEqual(im.info["spam"].lang, "en")
self.assertEqual(im.info["spam"].tkey, "Spam")
im = load(HEAD + 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\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' +
zlib.compress(b"egg")) + TAIL)
im = load(
HEAD
+ chunk(b"iTXt", b"spam\0\1\1en\0Spam\0" + zlib.compress(b"egg"))
+ TAIL
)
self.assertEqual(im.info, {})
im = load(HEAD + chunk(b'iTXt', b'spam\0\1\0en\0Spam\0' +
zlib.compress(b"egg")) + TAIL)
im = load(
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"].lang, "en")
self.assertEqual(im.info["spam"].tkey, "Spam")
@ -213,7 +219,7 @@ class TestFilePng(PillowTestCase):
self.assert_image(im, "RGBA", (162, 150))
# 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):
test_file = "Tests/images/rgb_trns.png"
@ -225,7 +231,7 @@ class TestFilePng(PillowTestCase):
self.assert_image(im, "RGBA", (64, 64))
# 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):
in_file = "Tests/images/pil123p.png"
@ -247,7 +253,7 @@ class TestFilePng(PillowTestCase):
self.assert_image(im, "RGBA", (162, 150))
# 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):
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))
# 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):
# check if solid black image with full transparency
@ -292,19 +298,14 @@ class TestFilePng(PillowTestCase):
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
def test_save_greyscale_transparency(self):
for mode, num_transparent in {
"1": 1994,
"L": 559,
"I": 559,
}.items():
in_file = "Tests/images/"+mode.lower()+"_trns.png"
for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
in_file = "Tests/images/" + mode.lower() + "_trns.png"
im = Image.open(in_file)
self.assertEqual(im.mode, mode)
self.assertEqual(im.info["transparency"], 255)
im_rgba = im.convert('RGBA')
self.assertEqual(
im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
im_rgba = im.convert("RGBA")
self.assertEqual(im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
test_file = self.tempfile("temp.png")
im.save(test_file)
@ -314,9 +315,10 @@ class TestFilePng(PillowTestCase):
self.assertEqual(test_im.info["transparency"], 255)
self.assert_image_equal(im, test_im)
test_im_rgba = test_im.convert('RGBA')
test_im_rgba = test_im.convert("RGBA")
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):
in_file = "Tests/images/caption_6_33_22.png"
@ -345,7 +347,7 @@ class TestFilePng(PillowTestCase):
# -14: malformed chunk
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]
im = Image.open(BytesIO(test_file))
@ -355,12 +357,11 @@ class TestFilePng(PillowTestCase):
def test_verify_ignores_crc_error(self):
# check ignores crc errors in ancillary chunks
chunk_data = chunk(b'tEXt', b'spam')
broken_crc_chunk_data = chunk_data[:-1] + b'q' # break CRC
chunk_data = chunk(b"tEXt", b"spam")
broken_crc_chunk_data = chunk_data[:-1] + b"q" # break CRC
image_data = HEAD + broken_crc_chunk_data + TAIL
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
BytesIO(image_data))
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data))
ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
@ -372,12 +373,13 @@ class TestFilePng(PillowTestCase):
def test_verify_not_ignores_crc_error_in_required_chunk(self):
# check does not ignore crc errors in required chunks
image_data = MAGIC + IHDR[:-1] + b'q' + TAIL
image_data = MAGIC + IHDR[:-1] + b"q" + TAIL
ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
BytesIO(image_data))
self.assertRaises(
SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data)
)
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False
@ -417,8 +419,8 @@ class TestFilePng(PillowTestCase):
info.add_text("ZIP", "VALUE", zip=True)
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
self.assertEqual(im.info, {"TXT": "VALUE", "ZIP": "VALUE"})
self.assertEqual(im.text, {"TXT": "VALUE", "ZIP": "VALUE"})
def test_roundtrip_itxt(self):
# Check iTXt roundtripping
@ -426,8 +428,7 @@ class TestFilePng(PillowTestCase):
im = Image.new("RGB", (32, 32))
info = PngImagePlugin.PngInfo()
info.add_itxt("spam", "Eggs", "en", "Spam")
info.add_text("eggs", PngImagePlugin.iTXt("Spam", "en", "Eggs"),
zip=True)
info.add_text("eggs", PngImagePlugin.iTXt("Spam", "en", "Eggs"), zip=True)
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"spam": "Eggs", "eggs": "Spam"})
@ -459,11 +460,11 @@ class TestFilePng(PillowTestCase):
self.assertEqual(im.info, {"Text": value})
if py3:
rt_text(" Aa" + chr(0xa0) + chr(0xc4) + chr(0xff)) # Latin1
rt_text(chr(0x400) + chr(0x472) + chr(0x4ff)) # Cyrillic
rt_text(chr(0x4e00) + chr(0x66f0) + # CJK
chr(0x9fba) + chr(0x3042) + chr(0xac00))
rt_text("A" + chr(0xc4) + chr(0x472) + chr(0x3042)) # Combined
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
# CJK:
rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
def test_scary(self):
# 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
# to avoid classification as malware.
with open("Tests/images/pngtest_bad.png.bin", 'rb') as fd:
data = b'\x89' + fd.read()
with open("Tests/images/pngtest_bad.png.bin", "rb") as fd:
data = b"\x89" + fd.read()
pngfile = BytesIO(data)
self.assertRaises(IOError, Image.open, pngfile)
@ -494,17 +495,16 @@ class TestFilePng(PillowTestCase):
def test_trns_p(self):
# Check writing a transparency of 0, issue #528
im = hopper('P')
im.info['transparency'] = 0
im = hopper("P")
im.info["transparency"] = 0
f = self.tempfile("temp.png")
im.save(f)
im2 = Image.open(f)
self.assertIn('transparency', im2.info)
self.assertIn("transparency", im2.info)
self.assert_image_equal(im2.convert('RGBA'),
im.convert('RGBA'))
self.assert_image_equal(im2.convert("RGBA"), im.convert("RGBA"))
def test_trns_null(self):
# Check reading images with null tRNS value, issue #1239
@ -515,39 +515,39 @@ class TestFilePng(PillowTestCase):
def test_save_icc_profile(self):
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")
expected_icc = with_icc.info['icc_profile']
expected_icc = with_icc.info["icc_profile"]
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):
im = Image.open('Tests/images/icc_profile.png')
im = Image.open("Tests/images/icc_profile.png")
im = roundtrip(im, icc_profile=None)
self.assertNotIn('icc_profile', im.info)
self.assertNotIn("icc_profile", im.info)
def test_roundtrip_icc_profile(self):
im = Image.open('Tests/images/icc_profile.png')
expected_icc = im.info['icc_profile']
im = Image.open("Tests/images/icc_profile.png")
expected_icc = im.info["icc_profile"]
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):
im = Image.open("Tests/images/icc_profile_none.png")
self.assertIsNone(im.info['icc_profile'])
self.assertIsNone(im.info["icc_profile"])
im = roundtrip(im)
self.assertNotIn('icc_profile', im.info)
self.assertNotIn("icc_profile", im.info)
def test_repr_png(self):
im = hopper()
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)
def test_chunk_order(self):
@ -579,10 +579,10 @@ class TestFilePng(PillowTestCase):
def test_textual_chunks_after_idat(self):
im = Image.open("Tests/images/hopper.png")
self.assertIn('comment', im.text.keys())
self.assertIn("comment", im.text.keys())
for k, v in {
'date:create': '2014-09-04T09:37:08+03:00',
'date:modify': '2014-09-04T09:37:08+03:00',
"date:create": "2014-09-04T09:37:08+03:00",
"date:modify": "2014-09-04T09:37:08+03:00",
}.items():
self.assertEqual(im.text[k], v)
@ -601,7 +601,7 @@ class TestFilePng(PillowTestCase):
# Raises an EOFError in load_end
im = Image.open("Tests/images/hopper_idat_after_image_end.png")
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
self.assertEqual(im.text, {"TXT": "VALUE", "ZIP": "VALUE"})
def test_exif(self):
im = Image.open("Tests/images/exif.png")
@ -637,20 +637,21 @@ class TestFilePng(PillowTestCase):
reloaded = Image.open(test_file)
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
@unittest.skipUnless(HAVE_WEBP and _webp.HAVE_WEBPANIM,
"WebP support not installed with animation")
@unittest.skipUnless(
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP support not installed with animation"
)
def test_apng(self):
im = Image.open("Tests/images/iss634.apng")
self.assertEqual(im.get_format_mimetype(), 'image/apng')
self.assertEqual(im.get_format_mimetype(), "image/apng")
# This also tests reading unknown PNG chunks (fcTL and fdAT) in load_end
expected = Image.open("Tests/images/iss634.webp")
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):
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
def setUp(self):
@ -658,7 +659,7 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase):
self.skipTest("zip/deflate support not available")
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))
ImageFile.LOAD_TRUNCATED_IMAGES = True

View File

@ -7,7 +7,6 @@ test_file = "Tests/images/hopper.ppm"
class TestFilePpm(PillowTestCase):
def test_sanity(self):
im = Image.open(test_file)
im.load()
@ -17,39 +16,39 @@ class TestFilePpm(PillowTestCase):
self.assertEqual(im.get_format_mimetype(), "image/x-portable-pixmap")
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()
self.assertEqual(im.mode, 'I')
self.assertEqual(im.mode, "I")
self.assertEqual(im.size, (20, 100))
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)
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()
f = self.tempfile('temp.pgm')
im.save(f, 'PPM')
f = self.tempfile("temp.pgm")
im.save(f, "PPM")
reloaded = Image.open(f)
self.assert_image_equal(im, reloaded)
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)
f = self.tempfile('temp.pnm')
f = self.tempfile("temp.pnm")
im.save(f)
reloaded = Image.open(f)
self.assert_image_equal(im, reloaded)
def test_truncated_file(self):
path = self.tempfile('temp.pgm')
with open(path, 'w') as f:
f.write('P6')
path = self.tempfile("temp.pgm")
with open(path, "w") as f:
f.write("P6")
self.assertRaises(ValueError, Image.open, path)
@ -60,17 +59,17 @@ class TestFilePpm(PillowTestCase):
# sizes.
with self.assertRaises(IOError):
Image.open('Tests/images/negative_size.ppm')
Image.open("Tests/images/negative_size.ppm")
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")
im = Image.open(path)
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")
im = Image.open(path)
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):
def test_sanity(self):
im = Image.open(test_file)
im.load()
@ -17,11 +16,17 @@ class TestImagePsd(PillowTestCase):
im2 = hopper()
self.assert_image_similar(im, im2, 4.8)
def test_unclosed_file(self):
def open():
im = Image.open(test_file)
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError,
PsdImagePlugin.PsdImageFile, invalid_file)
self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file)
def test_n_frames(self):
im = Image.open("Tests/images/hopper_merged.psd")
@ -35,14 +40,14 @@ class TestImagePsd(PillowTestCase):
def test_eoferror(self):
im = Image.open(test_file)
# 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
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# 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):
im = Image.open(test_file)
@ -65,6 +70,12 @@ class TestImagePsd(PillowTestCase):
self.assertRaises(EOFError, im.seek, -1)
def test_open_after_exclusive_load(self):
im = Image.open(test_file)
im.load()
im.seek(im.tell() + 1)
im.load()
def test_icc_profile(self):
im = Image.open(test_file)
self.assertIn("icc_profile", im.info)

View File

@ -4,7 +4,6 @@ from PIL import Image, SgiImagePlugin
class TestFileSgi(PillowTestCase):
def test_rgb(self):
# Created with ImageMagick then renamed:
# convert hopper.ppm -compress None sgi:hopper.rgb
@ -12,7 +11,7 @@ class TestFileSgi(PillowTestCase):
im = Image.open(test_file)
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):
test_file = "Tests/images/hopper16.rgb"
@ -26,8 +25,8 @@ class TestFileSgi(PillowTestCase):
test_file = "Tests/images/hopper.bw"
im = Image.open(test_file)
self.assert_image_similar(im, hopper('L'), 2)
self.assertEqual(im.get_format_mimetype(), 'image/sgi')
self.assert_image_similar(im, hopper("L"), 2)
self.assertEqual(im.get_format_mimetype(), "image/sgi")
def test_rgba(self):
# Created with ImageMagick:
@ -35,9 +34,9 @@ class TestFileSgi(PillowTestCase):
test_file = "Tests/images/transparent.sgi"
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.assertEqual(im.get_format_mimetype(), 'image/sgi')
self.assertEqual(im.get_format_mimetype(), "image/sgi")
def test_rle(self):
# Created with ImageMagick:
@ -45,47 +44,46 @@ class TestFileSgi(PillowTestCase):
test_file = "Tests/images/hopper.sgi"
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)
def test_rle16(self):
test_file = "Tests/images/tv16.sgi"
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)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(ValueError,
SgiImagePlugin.SgiImageFile, invalid_file)
self.assertRaises(ValueError, SgiImagePlugin.SgiImageFile, invalid_file)
def test_write(self):
def roundtrip(img):
out = self.tempfile('temp.sgi')
img.save(out, format='sgi')
out = self.tempfile("temp.sgi")
img.save(out, format="sgi")
reloaded = Image.open(out)
self.assert_image_equal(img, reloaded)
for mode in ('L', 'RGB', 'RGBA'):
for mode in ("L", "RGB", "RGBA"):
roundtrip(hopper(mode))
# Test 1 dimension for an L mode image
roundtrip(Image.new('L', (10, 1)))
roundtrip(Image.new("L", (10, 1)))
def test_write16(self):
test_file = "Tests/images/hopper16.rgb"
im = Image.open(test_file)
out = self.tempfile('temp.sgi')
im.save(out, format='sgi', bpc=2)
out = self.tempfile("temp.sgi")
im.save(out, format="sgi", bpc=2)
reloaded = Image.open(out)
self.assert_image_equal(im, reloaded)
def test_unsupported_mode(self):
im = hopper('LA')
out = self.tempfile('temp.sgi')
im = hopper("LA")
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):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
@ -22,11 +21,12 @@ class TestImageSpider(PillowTestCase):
def open():
im = Image.open(TEST_FILE)
im.load()
self.assert_warning(None, open)
def test_save(self):
# Arrange
temp = self.tempfile('temp.spider')
temp = self.tempfile("temp.spider")
im = hopper()
# Act

Some files were not shown because too many files have changed in this diff Show More