mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	Merge branch 'master' into apng
This commit is contained in:
		
						commit
						9f61be4c72
					
				
							
								
								
									
										15
									
								
								CHANGES.rst
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								CHANGES.rst
									
									
									
									
									
								
							| 
						 | 
					@ -5,6 +5,21 @@ Changelog (Pillow)
 | 
				
			||||||
7.1.0 (unreleased)
 | 
					7.1.0 (unreleased)
 | 
				
			||||||
------------------
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add JPEG comment to info dictionary #4455
 | 
				
			||||||
 | 
					  [radarhere]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fix size calculation of Image.thumbnail() #4404
 | 
				
			||||||
 | 
					  [orlnub123]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixed stroke on FreeType < 2.9 #4401
 | 
				
			||||||
 | 
					  [radarhere]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- If present, only use alpha channel for bounding box #4454
 | 
				
			||||||
 | 
					  [radarhere]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Warn if an unknown feature is passed to features.check() #4438
 | 
				
			||||||
 | 
					  [jdufresne]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fix Name field length when saving IM images #4424
 | 
					- Fix Name field length when saving IM images #4424
 | 
				
			||||||
  [hugovk, radarhere]
 | 
					  [hugovk, radarhere]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,6 @@ Helper functions.
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
| 
						 | 
					@ -192,21 +191,9 @@ class PillowTestCase(unittest.TestCase):
 | 
				
			||||||
        self.addCleanup(self.delete_tempfile, path)
 | 
					        self.addCleanup(self.delete_tempfile, path)
 | 
				
			||||||
        return path
 | 
					        return path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def open_withImagemagick(self, f):
 | 
					 | 
				
			||||||
        if not imagemagick_available():
 | 
					 | 
				
			||||||
            raise OSError()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        outfile = self.tempfile("temp.png")
 | 
					@pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS")
 | 
				
			||||||
        rc = subprocess.call(
 | 
					class PillowLeakTestCase:
 | 
				
			||||||
            [IMCONVERT, f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        if rc:
 | 
					 | 
				
			||||||
            raise OSError
 | 
					 | 
				
			||||||
        return Image.open(outfile)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
 | 
					 | 
				
			||||||
class PillowLeakTestCase(PillowTestCase):
 | 
					 | 
				
			||||||
    # requires unix/macOS
 | 
					    # requires unix/macOS
 | 
				
			||||||
    iterations = 100  # count
 | 
					    iterations = 100  # count
 | 
				
			||||||
    mem_limit = 512  # k
 | 
					    mem_limit = 512  # k
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								Tests/images/imagedraw_stroke_descender.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Tests/images/imagedraw_stroke_descender.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.1 KiB  | 
| 
						 | 
					@ -3,23 +3,21 @@ import os
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_similar
 | 
					from .helper import assert_image_similar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
base = os.path.join("Tests", "images", "bmp")
 | 
					base = os.path.join("Tests", "images", "bmp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestBmpReference(PillowTestCase):
 | 
					def get_files(d, ext=".bmp"):
 | 
				
			||||||
    def get_files(self, d, ext=".bmp"):
 | 
					 | 
				
			||||||
    return [
 | 
					    return [
 | 
				
			||||||
            os.path.join(base, d, f)
 | 
					        os.path.join(base, d, f) for f in os.listdir(os.path.join(base, d)) if ext in f
 | 
				
			||||||
            for f in os.listdir(os.path.join(base, d))
 | 
					 | 
				
			||||||
            if ext in f
 | 
					 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_bad(self):
 | 
					
 | 
				
			||||||
 | 
					def test_bad():
 | 
				
			||||||
    """ These shouldn't crash/dos, but they shouldn't return anything
 | 
					    """ These shouldn't crash/dos, but they shouldn't return anything
 | 
				
			||||||
    either """
 | 
					    either """
 | 
				
			||||||
        for f in self.get_files("b"):
 | 
					    for f in get_files("b"):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def open(f):
 | 
					        def open(f):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
| 
						 | 
					@ -31,7 +29,8 @@ class TestBmpReference(PillowTestCase):
 | 
				
			||||||
        # Assert that there is no unclosed file warning
 | 
					        # Assert that there is no unclosed file warning
 | 
				
			||||||
        pytest.warns(None, open, f)
 | 
					        pytest.warns(None, open, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_questionable(self):
 | 
					
 | 
				
			||||||
 | 
					def test_questionable():
 | 
				
			||||||
    """ These shouldn't crash/dos, but it's not well defined that these
 | 
					    """ These shouldn't crash/dos, but it's not well defined that these
 | 
				
			||||||
    are in spec """
 | 
					    are in spec """
 | 
				
			||||||
    supported = [
 | 
					    supported = [
 | 
				
			||||||
| 
						 | 
					@ -45,7 +44,7 @@ class TestBmpReference(PillowTestCase):
 | 
				
			||||||
        "pal8os2sp.bmp",
 | 
					        "pal8os2sp.bmp",
 | 
				
			||||||
        "rgb32bf-xbgr.bmp",
 | 
					        "rgb32bf-xbgr.bmp",
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
        for f in self.get_files("q"):
 | 
					    for f in get_files("q"):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            with Image.open(f) as im:
 | 
					            with Image.open(f) as im:
 | 
				
			||||||
                im.load()
 | 
					                im.load()
 | 
				
			||||||
| 
						 | 
					@ -55,7 +54,8 @@ class TestBmpReference(PillowTestCase):
 | 
				
			||||||
            if os.path.basename(f) in supported:
 | 
					            if os.path.basename(f) in supported:
 | 
				
			||||||
                raise
 | 
					                raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_good(self):
 | 
					
 | 
				
			||||||
 | 
					def test_good():
 | 
				
			||||||
    """ These should all work. There's a set of target files in the
 | 
					    """ These should all work. There's a set of target files in the
 | 
				
			||||||
    html directory that we can compare against. """
 | 
					    html directory that we can compare against. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,7 +86,7 @@ class TestBmpReference(PillowTestCase):
 | 
				
			||||||
        name = os.path.splitext(name)[0]
 | 
					        name = os.path.splitext(name)[0]
 | 
				
			||||||
        return os.path.join(base, "html", "%s.png" % name)
 | 
					        return os.path.join(base, "html", "%s.png" % name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for f in self.get_files("g"):
 | 
					    for f in get_files("g"):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            with Image.open(f) as im:
 | 
					            with Image.open(f) as im:
 | 
				
			||||||
                im.load()
 | 
					                im.load()
 | 
				
			||||||
| 
						 | 
					@ -107,5 +107,4 @@ class TestBmpReference(PillowTestCase):
 | 
				
			||||||
                os.path.join(base, "g", "pal8rle.bmp"),
 | 
					                os.path.join(base, "g", "pal8rle.bmp"),
 | 
				
			||||||
                os.path.join(base, "g", "pal4rle.bmp"),
 | 
					                os.path.join(base, "g", "pal4rle.bmp"),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
                if f not in unsupported:
 | 
					            assert f in unsupported, "Unsupported Image {}: {}".format(f, msg)
 | 
				
			||||||
                    self.fail("Unsupported Image {}: {}".format(f, msg))
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,9 @@
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, is_pypy
 | 
					from .helper import is_pypy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_get_stats():
 | 
					def test_get_stats():
 | 
				
			||||||
| 
						 | 
					@ -32,8 +31,8 @@ def test_reset_stats():
 | 
				
			||||||
    assert stats["blocks_cached"] == 0
 | 
					    assert stats["blocks_cached"] == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestCoreMemory(PillowTestCase):
 | 
					class TestCoreMemory:
 | 
				
			||||||
    def tearDown(self):
 | 
					    def teardown_method(self):
 | 
				
			||||||
        # Restore default values
 | 
					        # Restore default values
 | 
				
			||||||
        Image.core.set_alignment(1)
 | 
					        Image.core.set_alignment(1)
 | 
				
			||||||
        Image.core.set_block_size(1024 * 1024)
 | 
					        Image.core.set_block_size(1024 * 1024)
 | 
				
			||||||
| 
						 | 
					@ -114,7 +113,7 @@ class TestCoreMemory(PillowTestCase):
 | 
				
			||||||
            with pytest.raises(ValueError):
 | 
					            with pytest.raises(ValueError):
 | 
				
			||||||
                Image.core.set_blocks_max(2 ** 29)
 | 
					                Image.core.set_blocks_max(2 ** 29)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_pypy(), "images are not collected")
 | 
					    @pytest.mark.skipif(is_pypy(), reason="Images not collected")
 | 
				
			||||||
    def test_set_blocks_max_stats(self):
 | 
					    def test_set_blocks_max_stats(self):
 | 
				
			||||||
        Image.core.reset_stats()
 | 
					        Image.core.reset_stats()
 | 
				
			||||||
        Image.core.set_blocks_max(128)
 | 
					        Image.core.set_blocks_max(128)
 | 
				
			||||||
| 
						 | 
					@ -129,7 +128,7 @@ class TestCoreMemory(PillowTestCase):
 | 
				
			||||||
        assert stats["freed_blocks"] == 0
 | 
					        assert stats["freed_blocks"] == 0
 | 
				
			||||||
        assert stats["blocks_cached"] == 64
 | 
					        assert stats["blocks_cached"] == 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_pypy(), "images are not collected")
 | 
					    @pytest.mark.skipif(is_pypy(), reason="Images not collected")
 | 
				
			||||||
    def test_clear_cache_stats(self):
 | 
					    def test_clear_cache_stats(self):
 | 
				
			||||||
        Image.core.reset_stats()
 | 
					        Image.core.reset_stats()
 | 
				
			||||||
        Image.core.clear_cache()
 | 
					        Image.core.clear_cache()
 | 
				
			||||||
| 
						 | 
					@ -163,8 +162,8 @@ class TestCoreMemory(PillowTestCase):
 | 
				
			||||||
            assert stats["freed_blocks"] >= 16
 | 
					            assert stats["freed_blocks"] >= 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestEnvVars(PillowTestCase):
 | 
					class TestEnvVars:
 | 
				
			||||||
    def tearDown(self):
 | 
					    def teardown_method(self):
 | 
				
			||||||
        # Restore default values
 | 
					        # Restore default values
 | 
				
			||||||
        Image.core.set_alignment(1)
 | 
					        Image.core.set_alignment(1)
 | 
				
			||||||
        Image.core.set_block_size(1024 * 1024)
 | 
					        Image.core.set_block_size(1024 * 1024)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,6 +44,13 @@ def test_check_modules():
 | 
				
			||||||
        assert features.check_codec(feature) in [True, False]
 | 
					        assert features.check_codec(feature) in [True, False]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_check_warns_on_nonexistent():
 | 
				
			||||||
 | 
					    with pytest.warns(UserWarning) as cm:
 | 
				
			||||||
 | 
					        has_feature = features.check("typo")
 | 
				
			||||||
 | 
					    assert has_feature is False
 | 
				
			||||||
 | 
					    assert str(cm[-1].message) == "Unknown feature 'typo'."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_supported_modules():
 | 
					def test_supported_modules():
 | 
				
			||||||
    assert isinstance(features.get_supported_modules(), list)
 | 
					    assert isinstance(features.get_supported_modules(), list)
 | 
				
			||||||
    assert isinstance(features.get_supported_codecs(), list)
 | 
					    assert isinstance(features.get_supported_codecs(), list)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,21 @@
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal
 | 
					from .helper import assert_image_equal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFileBlp(PillowTestCase):
 | 
					def test_load_blp2_raw():
 | 
				
			||||||
    def test_load_blp2_raw(self):
 | 
					 | 
				
			||||||
    with Image.open("Tests/images/blp/blp2_raw.blp") as im:
 | 
					    with Image.open("Tests/images/blp/blp2_raw.blp") as im:
 | 
				
			||||||
        with Image.open("Tests/images/blp/blp2_raw.png") as target:
 | 
					        with Image.open("Tests/images/blp/blp2_raw.png") as target:
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_load_blp2_dxt1(self):
 | 
					
 | 
				
			||||||
 | 
					def test_load_blp2_dxt1():
 | 
				
			||||||
    with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
 | 
					    with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
 | 
				
			||||||
        with Image.open("Tests/images/blp/blp2_dxt1.png") as target:
 | 
					        with Image.open("Tests/images/blp/blp2_dxt1.png") as target:
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_load_blp2_dxt1a(self):
 | 
					
 | 
				
			||||||
 | 
					def test_load_blp2_dxt1a():
 | 
				
			||||||
    with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im:
 | 
					    with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im:
 | 
				
			||||||
        with Image.open("Tests/images/blp/blp2_dxt1a.png") as target:
 | 
					        with Image.open("Tests/images/blp/blp2_dxt1a.png") as target:
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,15 @@
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar
 | 
					from .helper import assert_image_equal, assert_image_similar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFileFtex(PillowTestCase):
 | 
					def test_load_raw():
 | 
				
			||||||
    def test_load_raw(self):
 | 
					 | 
				
			||||||
    with Image.open("Tests/images/ftex_uncompressed.ftu") as im:
 | 
					    with Image.open("Tests/images/ftex_uncompressed.ftu") as im:
 | 
				
			||||||
        with Image.open("Tests/images/ftex_uncompressed.png") as target:
 | 
					        with Image.open("Tests/images/ftex_uncompressed.png") as target:
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_load_dxt1(self):
 | 
					
 | 
				
			||||||
 | 
					def test_load_dxt1():
 | 
				
			||||||
    with Image.open("Tests/images/ftex_dxt1.ftc") as im:
 | 
					    with Image.open("Tests/images/ftex_dxt1.ftc") as im:
 | 
				
			||||||
        with Image.open("Tests/images/ftex_dxt1.png") as target:
 | 
					        with Image.open("Tests/images/ftex_dxt1.png") as target:
 | 
				
			||||||
            assert_image_similar(im, target.convert("RGBA"), 15)
 | 
					            assert_image_similar(im, target.convert("RGBA"), 15)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,6 @@ import pytest
 | 
				
			||||||
from PIL import ExifTags, Image, ImageFile, JpegImagePlugin
 | 
					from PIL import ExifTags, Image, ImageFile, JpegImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import (
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    assert_image,
 | 
					    assert_image,
 | 
				
			||||||
    assert_image_equal,
 | 
					    assert_image_equal,
 | 
				
			||||||
    assert_image_similar,
 | 
					    assert_image_similar,
 | 
				
			||||||
| 
						 | 
					@ -15,14 +14,13 @@ from .helper import (
 | 
				
			||||||
    hopper,
 | 
					    hopper,
 | 
				
			||||||
    is_win32,
 | 
					    is_win32,
 | 
				
			||||||
    skip_unless_feature,
 | 
					    skip_unless_feature,
 | 
				
			||||||
    unittest,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_FILE = "Tests/images/hopper.jpg"
 | 
					TEST_FILE = "Tests/images/hopper.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@skip_unless_feature("jpg")
 | 
					@skip_unless_feature("jpg")
 | 
				
			||||||
class TestFileJpeg(PillowTestCase):
 | 
					class TestFileJpeg:
 | 
				
			||||||
    def roundtrip(self, im, **options):
 | 
					    def roundtrip(self, im, **options):
 | 
				
			||||||
        out = BytesIO()
 | 
					        out = BytesIO()
 | 
				
			||||||
        im.save(out, "JPEG", **options)
 | 
					        im.save(out, "JPEG", **options)
 | 
				
			||||||
| 
						 | 
					@ -62,6 +60,8 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            assert len(im.applist) == 2
 | 
					            assert len(im.applist) == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cmyk(self):
 | 
					    def test_cmyk(self):
 | 
				
			||||||
        # Test CMYK handling.  Thanks to Tim and Charlie for test data,
 | 
					        # Test CMYK handling.  Thanks to Tim and Charlie for test data,
 | 
				
			||||||
        # Michael for getting me to look one more time.
 | 
					        # Michael for getting me to look one more time.
 | 
				
			||||||
| 
						 | 
					@ -101,13 +101,13 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        assert test(100, 200) == (100, 200)
 | 
					        assert test(100, 200) == (100, 200)
 | 
				
			||||||
        assert test(0) is None  # square pixels
 | 
					        assert test(0) is None  # square pixels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_icc(self):
 | 
					    def test_icc(self, tmp_path):
 | 
				
			||||||
        # Test ICC support
 | 
					        # Test ICC support
 | 
				
			||||||
        with Image.open("Tests/images/rgb.jpg") as im1:
 | 
					        with Image.open("Tests/images/rgb.jpg") as im1:
 | 
				
			||||||
            icc_profile = im1.info["icc_profile"]
 | 
					            icc_profile = im1.info["icc_profile"]
 | 
				
			||||||
            assert len(icc_profile) == 3144
 | 
					            assert len(icc_profile) == 3144
 | 
				
			||||||
            # Roundtrip via physical file.
 | 
					            # Roundtrip via physical file.
 | 
				
			||||||
            f = self.tempfile("temp.jpg")
 | 
					            f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
            im1.save(f, icc_profile=icc_profile)
 | 
					            im1.save(f, icc_profile=icc_profile)
 | 
				
			||||||
        with Image.open(f) as im2:
 | 
					        with Image.open(f) as im2:
 | 
				
			||||||
            assert im2.info.get("icc_profile") == icc_profile
 | 
					            assert im2.info.get("icc_profile") == icc_profile
 | 
				
			||||||
| 
						 | 
					@ -140,12 +140,12 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        test(ImageFile.MAXBLOCK + 1)  # full buffer block plus one byte
 | 
					        test(ImageFile.MAXBLOCK + 1)  # full buffer block plus one byte
 | 
				
			||||||
        test(ImageFile.MAXBLOCK * 4 + 3)  # large block
 | 
					        test(ImageFile.MAXBLOCK * 4 + 3)  # large block
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_large_icc_meta(self):
 | 
					    def test_large_icc_meta(self, tmp_path):
 | 
				
			||||||
        # https://github.com/python-pillow/Pillow/issues/148
 | 
					        # https://github.com/python-pillow/Pillow/issues/148
 | 
				
			||||||
        # Sometimes the meta data on the icc_profile block is bigger than
 | 
					        # Sometimes the meta data on the icc_profile block is bigger than
 | 
				
			||||||
        # Image.MAXBLOCK or the image size.
 | 
					        # Image.MAXBLOCK or the image size.
 | 
				
			||||||
        with Image.open("Tests/images/icc_profile_big.jpg") as im:
 | 
					        with Image.open("Tests/images/icc_profile_big.jpg") as im:
 | 
				
			||||||
            f = self.tempfile("temp.jpg")
 | 
					            f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
            icc_profile = im.info["icc_profile"]
 | 
					            icc_profile = im.info["icc_profile"]
 | 
				
			||||||
            # Should not raise IOError for image with icc larger than image size.
 | 
					            # Should not raise IOError for image with icc larger than image size.
 | 
				
			||||||
            im.save(
 | 
					            im.save(
 | 
				
			||||||
| 
						 | 
					@ -166,9 +166,9 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        assert im1.bytes >= im2.bytes
 | 
					        assert im1.bytes >= im2.bytes
 | 
				
			||||||
        assert im1.bytes >= im3.bytes
 | 
					        assert im1.bytes >= im3.bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_optimize_large_buffer(self):
 | 
					    def test_optimize_large_buffer(self, tmp_path):
 | 
				
			||||||
        # https://github.com/python-pillow/Pillow/issues/148
 | 
					        # https://github.com/python-pillow/Pillow/issues/148
 | 
				
			||||||
        f = self.tempfile("temp.jpg")
 | 
					        f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
        # this requires ~ 1.5x Image.MAXBLOCK
 | 
					        # this requires ~ 1.5x Image.MAXBLOCK
 | 
				
			||||||
        im = Image.new("RGB", (4096, 4096), 0xFF3333)
 | 
					        im = Image.new("RGB", (4096, 4096), 0xFF3333)
 | 
				
			||||||
        im.save(f, format="JPEG", optimize=True)
 | 
					        im.save(f, format="JPEG", optimize=True)
 | 
				
			||||||
| 
						 | 
					@ -184,14 +184,14 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        assert_image_equal(im1, im3)
 | 
					        assert_image_equal(im1, im3)
 | 
				
			||||||
        assert im1.bytes >= im3.bytes
 | 
					        assert im1.bytes >= im3.bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_progressive_large_buffer(self):
 | 
					    def test_progressive_large_buffer(self, tmp_path):
 | 
				
			||||||
        f = self.tempfile("temp.jpg")
 | 
					        f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
        # this requires ~ 1.5x Image.MAXBLOCK
 | 
					        # this requires ~ 1.5x Image.MAXBLOCK
 | 
				
			||||||
        im = Image.new("RGB", (4096, 4096), 0xFF3333)
 | 
					        im = Image.new("RGB", (4096, 4096), 0xFF3333)
 | 
				
			||||||
        im.save(f, format="JPEG", progressive=True)
 | 
					        im.save(f, format="JPEG", progressive=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_progressive_large_buffer_highest_quality(self):
 | 
					    def test_progressive_large_buffer_highest_quality(self, tmp_path):
 | 
				
			||||||
        f = self.tempfile("temp.jpg")
 | 
					        f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
        im = self.gen_random_image((255, 255))
 | 
					        im = self.gen_random_image((255, 255))
 | 
				
			||||||
        # this requires more bytes than pixels in the image
 | 
					        # this requires more bytes than pixels in the image
 | 
				
			||||||
        im.save(f, format="JPEG", progressive=True, quality=100)
 | 
					        im.save(f, format="JPEG", progressive=True, quality=100)
 | 
				
			||||||
| 
						 | 
					@ -202,9 +202,9 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        im = self.gen_random_image((256, 256), "CMYK")
 | 
					        im = self.gen_random_image((256, 256), "CMYK")
 | 
				
			||||||
        im.save(f, format="JPEG", progressive=True, quality=94)
 | 
					        im.save(f, format="JPEG", progressive=True, quality=94)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_large_exif(self):
 | 
					    def test_large_exif(self, tmp_path):
 | 
				
			||||||
        # https://github.com/python-pillow/Pillow/issues/148
 | 
					        # https://github.com/python-pillow/Pillow/issues/148
 | 
				
			||||||
        f = self.tempfile("temp.jpg")
 | 
					        f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
        im = hopper()
 | 
					        im = hopper()
 | 
				
			||||||
        im.save(f, "JPEG", quality=90, exif=b"1" * 65532)
 | 
					        im.save(f, "JPEG", quality=90, exif=b"1" * 65532)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -301,7 +301,7 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im3 = self.roundtrip(hopper(), quality=0)
 | 
					        im3 = self.roundtrip(hopper(), quality=0)
 | 
				
			||||||
        assert_image(im1, im3.mode, im3.size)
 | 
					        assert_image(im1, im3.mode, im3.size)
 | 
				
			||||||
        self.assertGreater(im2.bytes, im3.bytes)
 | 
					        assert im2.bytes > im3.bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_smooth(self):
 | 
					    def test_smooth(self):
 | 
				
			||||||
        im1 = self.roundtrip(hopper())
 | 
					        im1 = self.roundtrip(hopper())
 | 
				
			||||||
| 
						 | 
					@ -346,18 +346,18 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
 | 
					        with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
 | 
				
			||||||
            assert im._getmp() is None
 | 
					            assert im._getmp() is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_quality_keep(self):
 | 
					    def test_quality_keep(self, tmp_path):
 | 
				
			||||||
        # RGB
 | 
					        # RGB
 | 
				
			||||||
        with Image.open("Tests/images/hopper.jpg") as im:
 | 
					        with Image.open("Tests/images/hopper.jpg") as im:
 | 
				
			||||||
            f = self.tempfile("temp.jpg")
 | 
					            f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
            im.save(f, quality="keep")
 | 
					            im.save(f, quality="keep")
 | 
				
			||||||
        # Grayscale
 | 
					        # Grayscale
 | 
				
			||||||
        with Image.open("Tests/images/hopper_gray.jpg") as im:
 | 
					        with Image.open("Tests/images/hopper_gray.jpg") as im:
 | 
				
			||||||
            f = self.tempfile("temp.jpg")
 | 
					            f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
            im.save(f, quality="keep")
 | 
					            im.save(f, quality="keep")
 | 
				
			||||||
        # CMYK
 | 
					        # CMYK
 | 
				
			||||||
        with Image.open("Tests/images/pil_sample_cmyk.jpg") as im:
 | 
					        with Image.open("Tests/images/pil_sample_cmyk.jpg") as im:
 | 
				
			||||||
            f = self.tempfile("temp.jpg")
 | 
					            f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
            im.save(f, quality="keep")
 | 
					            im.save(f, quality="keep")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_junk_jpeg_header(self):
 | 
					    def test_junk_jpeg_header(self):
 | 
				
			||||||
| 
						 | 
					@ -389,16 +389,16 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
            with pytest.raises(IOError):
 | 
					            with pytest.raises(IOError):
 | 
				
			||||||
                im.load()
 | 
					                im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _n_qtables_helper(self, n, test_file):
 | 
					    def test_qtables(self, tmp_path):
 | 
				
			||||||
 | 
					        def _n_qtables_helper(n, test_file):
 | 
				
			||||||
            with Image.open(test_file) as im:
 | 
					            with Image.open(test_file) as im:
 | 
				
			||||||
            f = self.tempfile("temp.jpg")
 | 
					                f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
                im.save(f, qtables=[[n] * 64] * n)
 | 
					                im.save(f, qtables=[[n] * 64] * n)
 | 
				
			||||||
            with Image.open(f) as im:
 | 
					            with Image.open(f) as im:
 | 
				
			||||||
                assert len(im.quantization) == n
 | 
					                assert len(im.quantization) == n
 | 
				
			||||||
                reloaded = self.roundtrip(im, qtables="keep")
 | 
					                reloaded = self.roundtrip(im, qtables="keep")
 | 
				
			||||||
                assert im.quantization == reloaded.quantization
 | 
					                assert im.quantization == reloaded.quantization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_qtables(self):
 | 
					 | 
				
			||||||
        with Image.open("Tests/images/hopper.jpg") as im:
 | 
					        with Image.open("Tests/images/hopper.jpg") as im:
 | 
				
			||||||
            qtables = im.quantization
 | 
					            qtables = im.quantization
 | 
				
			||||||
            reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
 | 
					            reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
 | 
				
			||||||
| 
						 | 
					@ -470,14 +470,14 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
                30,
 | 
					                30,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._n_qtables_helper(1, "Tests/images/hopper_gray.jpg")
 | 
					            _n_qtables_helper(1, "Tests/images/hopper_gray.jpg")
 | 
				
			||||||
            self._n_qtables_helper(1, "Tests/images/pil_sample_rgb.jpg")
 | 
					            _n_qtables_helper(1, "Tests/images/pil_sample_rgb.jpg")
 | 
				
			||||||
            self._n_qtables_helper(2, "Tests/images/pil_sample_rgb.jpg")
 | 
					            _n_qtables_helper(2, "Tests/images/pil_sample_rgb.jpg")
 | 
				
			||||||
            self._n_qtables_helper(3, "Tests/images/pil_sample_rgb.jpg")
 | 
					            _n_qtables_helper(3, "Tests/images/pil_sample_rgb.jpg")
 | 
				
			||||||
            self._n_qtables_helper(1, "Tests/images/pil_sample_cmyk.jpg")
 | 
					            _n_qtables_helper(1, "Tests/images/pil_sample_cmyk.jpg")
 | 
				
			||||||
            self._n_qtables_helper(2, "Tests/images/pil_sample_cmyk.jpg")
 | 
					            _n_qtables_helper(2, "Tests/images/pil_sample_cmyk.jpg")
 | 
				
			||||||
            self._n_qtables_helper(3, "Tests/images/pil_sample_cmyk.jpg")
 | 
					            _n_qtables_helper(3, "Tests/images/pil_sample_cmyk.jpg")
 | 
				
			||||||
            self._n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
 | 
					            _n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # not a sequence
 | 
					            # not a sequence
 | 
				
			||||||
            with pytest.raises(ValueError):
 | 
					            with pytest.raises(ValueError):
 | 
				
			||||||
| 
						 | 
					@ -496,16 +496,16 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
            with pytest.raises(ValueError):
 | 
					            with pytest.raises(ValueError):
 | 
				
			||||||
                self.roundtrip(im, qtables=[[1, 2, 3, 4]])
 | 
					                self.roundtrip(im, qtables=[[1, 2, 3, 4]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(djpeg_available(), "djpeg not available")
 | 
					    @pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
 | 
				
			||||||
    def test_load_djpeg(self):
 | 
					    def test_load_djpeg(self):
 | 
				
			||||||
        with Image.open(TEST_FILE) as img:
 | 
					        with Image.open(TEST_FILE) as img:
 | 
				
			||||||
            img.load_djpeg()
 | 
					            img.load_djpeg()
 | 
				
			||||||
            assert_image_similar(img, Image.open(TEST_FILE), 0)
 | 
					            assert_image_similar(img, Image.open(TEST_FILE), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(cjpeg_available(), "cjpeg not available")
 | 
					    @pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
 | 
				
			||||||
    def test_save_cjpeg(self):
 | 
					    def test_save_cjpeg(self, tmp_path):
 | 
				
			||||||
        with Image.open(TEST_FILE) as img:
 | 
					        with Image.open(TEST_FILE) as img:
 | 
				
			||||||
            tempfile = self.tempfile("temp.jpg")
 | 
					            tempfile = str(tmp_path / "temp.jpg")
 | 
				
			||||||
            JpegImagePlugin._save_cjpeg(img, 0, tempfile)
 | 
					            JpegImagePlugin._save_cjpeg(img, 0, tempfile)
 | 
				
			||||||
            # Default save quality is 75%, so a tiny bit of difference is alright
 | 
					            # Default save quality is 75%, so a tiny bit of difference is alright
 | 
				
			||||||
            assert_image_similar(img, Image.open(tempfile), 17)
 | 
					            assert_image_similar(img, Image.open(tempfile), 17)
 | 
				
			||||||
| 
						 | 
					@ -518,9 +518,9 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        assert tag_ids["RelatedImageWidth"] == 0x1001
 | 
					        assert tag_ids["RelatedImageWidth"] == 0x1001
 | 
				
			||||||
        assert tag_ids["RelatedImageLength"] == 0x1002
 | 
					        assert tag_ids["RelatedImageLength"] == 0x1002
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_MAXBLOCK_scaling(self):
 | 
					    def test_MAXBLOCK_scaling(self, tmp_path):
 | 
				
			||||||
        im = self.gen_random_image((512, 512))
 | 
					        im = self.gen_random_image((512, 512))
 | 
				
			||||||
        f = self.tempfile("temp.jpeg")
 | 
					        f = str(tmp_path / "temp.jpeg")
 | 
				
			||||||
        im.save(f, quality=100, optimize=True)
 | 
					        im.save(f, quality=100, optimize=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(f) as reloaded:
 | 
					        with Image.open(f) as reloaded:
 | 
				
			||||||
| 
						 | 
					@ -555,9 +555,9 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
            with pytest.raises(IOError):
 | 
					            with pytest.raises(IOError):
 | 
				
			||||||
                img.save(out, "JPEG")
 | 
					                img.save(out, "JPEG")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_tiff_with_dpi(self):
 | 
					    def test_save_tiff_with_dpi(self, tmp_path):
 | 
				
			||||||
        # Arrange
 | 
					        # Arrange
 | 
				
			||||||
        outfile = self.tempfile("temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        with Image.open("Tests/images/hopper.tif") as im:
 | 
					        with Image.open("Tests/images/hopper.tif") as im:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Act
 | 
					            # Act
 | 
				
			||||||
| 
						 | 
					@ -577,8 +577,8 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        with Image.open("Tests/images/iptc_roundDown.jpg") as im:
 | 
					        with Image.open("Tests/images/iptc_roundDown.jpg") as im:
 | 
				
			||||||
            assert im.info["dpi"] == (2, 2)
 | 
					            assert im.info["dpi"] == (2, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_dpi_rounding(self):
 | 
					    def test_save_dpi_rounding(self, tmp_path):
 | 
				
			||||||
        outfile = self.tempfile("temp.jpg")
 | 
					        outfile = str(tmp_path / "temp.jpg")
 | 
				
			||||||
        with Image.open("Tests/images/hopper.jpg") as im:
 | 
					        with Image.open("Tests/images/hopper.jpg") as im:
 | 
				
			||||||
            im.save(outfile, dpi=(72.2, 72.2))
 | 
					            im.save(outfile, dpi=(72.2, 72.2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -690,11 +690,11 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
            assert [65504, 24] == apps_13_lengths
 | 
					            assert [65504, 24] == apps_13_lengths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipUnless(is_win32(), "Windows only")
 | 
					@pytest.mark.skipif(not is_win32(), reason="Windows only")
 | 
				
			||||||
@skip_unless_feature("jpg")
 | 
					@skip_unless_feature("jpg")
 | 
				
			||||||
class TestFileCloseW32(PillowTestCase):
 | 
					class TestFileCloseW32:
 | 
				
			||||||
    def test_fd_leak(self):
 | 
					    def test_fd_leak(self, tmp_path):
 | 
				
			||||||
        tmpfile = self.tempfile("temp.jpg")
 | 
					        tmpfile = str(tmp_path / "temp.jpg")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open("Tests/images/hopper.jpg") as im:
 | 
					        with Image.open("Tests/images/hopper.jpg") as im:
 | 
				
			||||||
            im.save(tmpfile)
 | 
					            im.save(tmpfile)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,6 @@ import pytest
 | 
				
			||||||
from PIL import Image, ImageFile, Jpeg2KImagePlugin
 | 
					from PIL import Image, ImageFile, Jpeg2KImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import (
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    assert_image_equal,
 | 
					    assert_image_equal,
 | 
				
			||||||
    assert_image_similar,
 | 
					    assert_image_similar,
 | 
				
			||||||
    is_big_endian,
 | 
					    is_big_endian,
 | 
				
			||||||
| 
						 | 
					@ -13,6 +12,8 @@ from .helper import (
 | 
				
			||||||
    skip_unless_feature,
 | 
					    skip_unless_feature,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pytestmark = skip_unless_feature("jpg_2000")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_card = Image.open("Tests/images/test-card.png")
 | 
					test_card = Image.open("Tests/images/test-card.png")
 | 
				
			||||||
test_card.load()
 | 
					test_card.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,9 +22,7 @@ test_card.load()
 | 
				
			||||||
# 'Not enough memory to handle tile data'
 | 
					# 'Not enough memory to handle tile data'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@skip_unless_feature("jpg_2000")
 | 
					def roundtrip(im, **options):
 | 
				
			||||||
class TestFileJpeg2k(PillowTestCase):
 | 
					 | 
				
			||||||
    def roundtrip(self, im, **options):
 | 
					 | 
				
			||||||
    out = BytesIO()
 | 
					    out = BytesIO()
 | 
				
			||||||
    im.save(out, "JPEG2000", **options)
 | 
					    im.save(out, "JPEG2000", **options)
 | 
				
			||||||
    test_bytes = out.tell()
 | 
					    test_bytes = out.tell()
 | 
				
			||||||
| 
						 | 
					@ -33,7 +32,8 @@ class TestFileJpeg2k(PillowTestCase):
 | 
				
			||||||
    im.load()
 | 
					    im.load()
 | 
				
			||||||
    return im
 | 
					    return im
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sanity(self):
 | 
					
 | 
				
			||||||
 | 
					def test_sanity():
 | 
				
			||||||
    # Internal version number
 | 
					    # Internal version number
 | 
				
			||||||
    assert re.search(r"\d+\.\d+\.\d+$", Image.core.jp2klib_version)
 | 
					    assert re.search(r"\d+\.\d+\.\d+$", Image.core.jp2klib_version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,83 +45,95 @@ class TestFileJpeg2k(PillowTestCase):
 | 
				
			||||||
        assert im.format == "JPEG2000"
 | 
					        assert im.format == "JPEG2000"
 | 
				
			||||||
        assert im.get_format_mimetype() == "image/jp2"
 | 
					        assert im.get_format_mimetype() == "image/jp2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_jpf(self):
 | 
					
 | 
				
			||||||
 | 
					def test_jpf():
 | 
				
			||||||
    with Image.open("Tests/images/balloon.jpf") as im:
 | 
					    with Image.open("Tests/images/balloon.jpf") as im:
 | 
				
			||||||
        assert im.format == "JPEG2000"
 | 
					        assert im.format == "JPEG2000"
 | 
				
			||||||
        assert im.get_format_mimetype() == "image/jpx"
 | 
					        assert im.get_format_mimetype() == "image/jpx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_file(self):
 | 
					
 | 
				
			||||||
 | 
					def test_invalid_file():
 | 
				
			||||||
    invalid_file = "Tests/images/flower.jpg"
 | 
					    invalid_file = "Tests/images/flower.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with pytest.raises(SyntaxError):
 | 
					    with pytest.raises(SyntaxError):
 | 
				
			||||||
        Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file)
 | 
					        Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_bytesio(self):
 | 
					
 | 
				
			||||||
 | 
					def test_bytesio():
 | 
				
			||||||
    with open("Tests/images/test-card-lossless.jp2", "rb") as f:
 | 
					    with open("Tests/images/test-card-lossless.jp2", "rb") as f:
 | 
				
			||||||
        data = BytesIO(f.read())
 | 
					        data = BytesIO(f.read())
 | 
				
			||||||
    with Image.open(data) as im:
 | 
					    with Image.open(data) as im:
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert_image_similar(im, test_card, 1.0e-3)
 | 
					        assert_image_similar(im, test_card, 1.0e-3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # These two test pre-written JPEG 2000 files that were not written with
 | 
					 | 
				
			||||||
    # PIL (they were made using Adobe Photoshop)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_lossless(self):
 | 
					# These two test pre-written JPEG 2000 files that were not written with
 | 
				
			||||||
 | 
					# PIL (they were made using Adobe Photoshop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_lossless(tmp_path):
 | 
				
			||||||
    with Image.open("Tests/images/test-card-lossless.jp2") as im:
 | 
					    with Image.open("Tests/images/test-card-lossless.jp2") as im:
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
            outfile = self.tempfile("temp_test-card.png")
 | 
					        outfile = str(tmp_path / "temp_test-card.png")
 | 
				
			||||||
        im.save(outfile)
 | 
					        im.save(outfile)
 | 
				
			||||||
    assert_image_similar(im, test_card, 1.0e-3)
 | 
					    assert_image_similar(im, test_card, 1.0e-3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_lossy_tiled(self):
 | 
					
 | 
				
			||||||
 | 
					def test_lossy_tiled():
 | 
				
			||||||
    with Image.open("Tests/images/test-card-lossy-tiled.jp2") as im:
 | 
					    with Image.open("Tests/images/test-card-lossy-tiled.jp2") as im:
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert_image_similar(im, test_card, 2.0)
 | 
					        assert_image_similar(im, test_card, 2.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_lossless_rt(self):
 | 
					
 | 
				
			||||||
        im = self.roundtrip(test_card)
 | 
					def test_lossless_rt():
 | 
				
			||||||
 | 
					    im = roundtrip(test_card)
 | 
				
			||||||
    assert_image_equal(im, test_card)
 | 
					    assert_image_equal(im, test_card)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_lossy_rt(self):
 | 
					
 | 
				
			||||||
        im = self.roundtrip(test_card, quality_layers=[20])
 | 
					def test_lossy_rt():
 | 
				
			||||||
 | 
					    im = roundtrip(test_card, quality_layers=[20])
 | 
				
			||||||
    assert_image_similar(im, test_card, 2.0)
 | 
					    assert_image_similar(im, test_card, 2.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_tiled_rt(self):
 | 
					
 | 
				
			||||||
        im = self.roundtrip(test_card, tile_size=(128, 128))
 | 
					def test_tiled_rt():
 | 
				
			||||||
 | 
					    im = roundtrip(test_card, tile_size=(128, 128))
 | 
				
			||||||
    assert_image_equal(im, test_card)
 | 
					    assert_image_equal(im, test_card)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_tiled_offset_rt(self):
 | 
					
 | 
				
			||||||
        im = self.roundtrip(
 | 
					def test_tiled_offset_rt():
 | 
				
			||||||
            test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32)
 | 
					    im = roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32))
 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    assert_image_equal(im, test_card)
 | 
					    assert_image_equal(im, test_card)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_tiled_offset_too_small(self):
 | 
					
 | 
				
			||||||
 | 
					def test_tiled_offset_too_small():
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
            self.roundtrip(
 | 
					        roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(128, 32))
 | 
				
			||||||
                test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(128, 32)
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_irreversible_rt(self):
 | 
					
 | 
				
			||||||
        im = self.roundtrip(test_card, irreversible=True, quality_layers=[20])
 | 
					def test_irreversible_rt():
 | 
				
			||||||
 | 
					    im = roundtrip(test_card, irreversible=True, quality_layers=[20])
 | 
				
			||||||
    assert_image_similar(im, test_card, 2.0)
 | 
					    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")
 | 
					def test_prog_qual_rt():
 | 
				
			||||||
 | 
					    im = roundtrip(test_card, quality_layers=[60, 40, 20], progression="LRCP")
 | 
				
			||||||
    assert_image_similar(im, test_card, 2.0)
 | 
					    assert_image_similar(im, test_card, 2.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_prog_res_rt(self):
 | 
					
 | 
				
			||||||
        im = self.roundtrip(test_card, num_resolutions=8, progression="RLCP")
 | 
					def test_prog_res_rt():
 | 
				
			||||||
 | 
					    im = roundtrip(test_card, num_resolutions=8, progression="RLCP")
 | 
				
			||||||
    assert_image_equal(im, test_card)
 | 
					    assert_image_equal(im, test_card)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_reduce(self):
 | 
					
 | 
				
			||||||
 | 
					def test_reduce():
 | 
				
			||||||
    with Image.open("Tests/images/test-card-lossless.jp2") as im:
 | 
					    with Image.open("Tests/images/test-card-lossless.jp2") as im:
 | 
				
			||||||
        im.reduce = 2
 | 
					        im.reduce = 2
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert im.size == (160, 120)
 | 
					        assert im.size == (160, 120)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_layers_type(self):
 | 
					
 | 
				
			||||||
        outfile = self.tempfile("temp_layers.jp2")
 | 
					def test_layers_type(tmp_path):
 | 
				
			||||||
 | 
					    outfile = str(tmp_path / "temp_layers.jp2")
 | 
				
			||||||
    for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
 | 
					    for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
 | 
				
			||||||
        test_card.save(outfile, quality_layers=quality_layers)
 | 
					        test_card.save(outfile, quality_layers=quality_layers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,11 +141,10 @@ class TestFileJpeg2k(PillowTestCase):
 | 
				
			||||||
        with pytest.raises(ValueError):
 | 
					        with pytest.raises(ValueError):
 | 
				
			||||||
            test_card.save(outfile, quality_layers=quality_layers)
 | 
					            test_card.save(outfile, quality_layers=quality_layers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_layers(self):
 | 
					
 | 
				
			||||||
 | 
					def test_layers():
 | 
				
			||||||
    out = BytesIO()
 | 
					    out = BytesIO()
 | 
				
			||||||
        test_card.save(
 | 
					    test_card.save(out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP")
 | 
				
			||||||
            out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP"
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    out.seek(0)
 | 
					    out.seek(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as im:
 | 
					    with Image.open(out) as im:
 | 
				
			||||||
| 
						 | 
					@ -147,7 +158,8 @@ class TestFileJpeg2k(PillowTestCase):
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert_image_similar(im, test_card, 0.4)
 | 
					        assert_image_similar(im, test_card, 0.4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rgba(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rgba():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
 | 
					    with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
 | 
				
			||||||
        with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
 | 
					        with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
 | 
				
			||||||
| 
						 | 
					@ -160,7 +172,8 @@ class TestFileJpeg2k(PillowTestCase):
 | 
				
			||||||
            assert j2k.mode == "RGBA"
 | 
					            assert j2k.mode == "RGBA"
 | 
				
			||||||
            assert jp2.mode == "RGBA"
 | 
					            assert jp2.mode == "RGBA"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit_monochrome_has_correct_mode(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit_monochrome_has_correct_mode():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
 | 
					    with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
 | 
				
			||||||
        j2k.load()
 | 
					        j2k.load()
 | 
				
			||||||
        assert j2k.mode == "I;16"
 | 
					        assert j2k.mode == "I;16"
 | 
				
			||||||
| 
						 | 
					@ -169,35 +182,40 @@ class TestFileJpeg2k(PillowTestCase):
 | 
				
			||||||
        jp2.load()
 | 
					        jp2.load()
 | 
				
			||||||
        assert jp2.mode == "I;16"
 | 
					        assert jp2.mode == "I;16"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
 | 
					
 | 
				
			||||||
    def test_16bit_monochrome_jp2_like_tiff(self):
 | 
					@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
 | 
				
			||||||
 | 
					def test_16bit_monochrome_jp2_like_tiff():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
 | 
					    with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
 | 
				
			||||||
        with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
 | 
					        with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
 | 
				
			||||||
            assert_image_similar(jp2, tiff_16bit, 1e-3)
 | 
					            assert_image_similar(jp2, tiff_16bit, 1e-3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
 | 
					
 | 
				
			||||||
    def test_16bit_monochrome_j2k_like_tiff(self):
 | 
					@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
 | 
				
			||||||
 | 
					def test_16bit_monochrome_j2k_like_tiff():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
 | 
					    with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
 | 
				
			||||||
        with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
 | 
					        with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
 | 
				
			||||||
            assert_image_similar(j2k, tiff_16bit, 1e-3)
 | 
					            assert_image_similar(j2k, tiff_16bit, 1e-3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit_j2k_roundtrips(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit_j2k_roundtrips():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
 | 
					    with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
 | 
				
			||||||
            im = self.roundtrip(j2k)
 | 
					        im = roundtrip(j2k)
 | 
				
			||||||
        assert_image_equal(im, j2k)
 | 
					        assert_image_equal(im, j2k)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit_jp2_roundtrips(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit_jp2_roundtrips():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
 | 
					    with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
 | 
				
			||||||
            im = self.roundtrip(jp2)
 | 
					        im = roundtrip(jp2)
 | 
				
			||||||
        assert_image_equal(im, jp2)
 | 
					        assert_image_equal(im, jp2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_unbound_local(self):
 | 
					
 | 
				
			||||||
        # prepatch, a malformed jp2 file could cause an UnboundLocalError
 | 
					def test_unbound_local():
 | 
				
			||||||
        # exception.
 | 
					    # prepatch, a malformed jp2 file could cause an UnboundLocalError exception.
 | 
				
			||||||
    with pytest.raises(IOError):
 | 
					    with pytest.raises(IOError):
 | 
				
			||||||
        Image.open("Tests/images/unbound_variable.jp2")
 | 
					        Image.open("Tests/images/unbound_variable.jp2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_parser_feed(self):
 | 
					
 | 
				
			||||||
 | 
					def test_parser_feed():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    with open("Tests/images/test-card-lossless.jp2", "rb") as f:
 | 
					    with open("Tests/images/test-card-lossless.jp2", "rb") as f:
 | 
				
			||||||
        data = f.read()
 | 
					        data = f.read()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@ import pytest
 | 
				
			||||||
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags
 | 
					from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import (
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    assert_image_equal,
 | 
					    assert_image_equal,
 | 
				
			||||||
    assert_image_equal_tofile,
 | 
					    assert_image_equal_tofile,
 | 
				
			||||||
    assert_image_similar,
 | 
					    assert_image_similar,
 | 
				
			||||||
| 
						 | 
					@ -23,8 +22,8 @@ logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@skip_unless_feature("libtiff")
 | 
					@skip_unless_feature("libtiff")
 | 
				
			||||||
class LibTiffTestCase(PillowTestCase):
 | 
					class LibTiffTestCase:
 | 
				
			||||||
    def _assert_noerr(self, im):
 | 
					    def _assert_noerr(self, tmp_path, im):
 | 
				
			||||||
        """Helper tests that assert basic sanity about the g4 tiff reading"""
 | 
					        """Helper tests that assert basic sanity about the g4 tiff reading"""
 | 
				
			||||||
        # 1 bit
 | 
					        # 1 bit
 | 
				
			||||||
        assert im.mode == "1"
 | 
					        assert im.mode == "1"
 | 
				
			||||||
| 
						 | 
					@ -40,7 +39,7 @@ class LibTiffTestCase(PillowTestCase):
 | 
				
			||||||
            print(dir(im))
 | 
					            print(dir(im))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # can we write it back out, in a different form.
 | 
					        # can we write it back out, in a different form.
 | 
				
			||||||
        out = self.tempfile("temp.png")
 | 
					        out = str(tmp_path / "temp.png")
 | 
				
			||||||
        im.save(out)
 | 
					        im.save(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out_bytes = io.BytesIO()
 | 
					        out_bytes = io.BytesIO()
 | 
				
			||||||
| 
						 | 
					@ -48,29 +47,29 @@ class LibTiffTestCase(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFileLibTiff(LibTiffTestCase):
 | 
					class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
    def test_g4_tiff(self):
 | 
					    def test_g4_tiff(self, tmp_path):
 | 
				
			||||||
        """Test the ordinary file path load path"""
 | 
					        """Test the ordinary file path load path"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4_500.tif"
 | 
					        test_file = "Tests/images/hopper_g4_500.tif"
 | 
				
			||||||
        with Image.open(test_file) as im:
 | 
					        with Image.open(test_file) as im:
 | 
				
			||||||
            assert im.size == (500, 500)
 | 
					            assert im.size == (500, 500)
 | 
				
			||||||
            self._assert_noerr(im)
 | 
					            self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_large(self):
 | 
					    def test_g4_large(self, tmp_path):
 | 
				
			||||||
        test_file = "Tests/images/pport_g4.tif"
 | 
					        test_file = "Tests/images/pport_g4.tif"
 | 
				
			||||||
        with Image.open(test_file) as im:
 | 
					        with Image.open(test_file) as im:
 | 
				
			||||||
            self._assert_noerr(im)
 | 
					            self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_tiff_file(self):
 | 
					    def test_g4_tiff_file(self, tmp_path):
 | 
				
			||||||
        """Testing the string load path"""
 | 
					        """Testing the string load path"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4_500.tif"
 | 
					        test_file = "Tests/images/hopper_g4_500.tif"
 | 
				
			||||||
        with open(test_file, "rb") as f:
 | 
					        with open(test_file, "rb") as f:
 | 
				
			||||||
            with Image.open(f) as im:
 | 
					            with Image.open(f) as im:
 | 
				
			||||||
                assert im.size == (500, 500)
 | 
					                assert im.size == (500, 500)
 | 
				
			||||||
                self._assert_noerr(im)
 | 
					                self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_tiff_bytesio(self):
 | 
					    def test_g4_tiff_bytesio(self, tmp_path):
 | 
				
			||||||
        """Testing the stringio loading code path"""
 | 
					        """Testing the stringio loading code path"""
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4_500.tif"
 | 
					        test_file = "Tests/images/hopper_g4_500.tif"
 | 
				
			||||||
        s = io.BytesIO()
 | 
					        s = io.BytesIO()
 | 
				
			||||||
| 
						 | 
					@ -79,9 +78,9 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            s.seek(0)
 | 
					            s.seek(0)
 | 
				
			||||||
        with Image.open(s) as im:
 | 
					        with Image.open(s) as im:
 | 
				
			||||||
            assert im.size == (500, 500)
 | 
					            assert im.size == (500, 500)
 | 
				
			||||||
            self._assert_noerr(im)
 | 
					            self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_non_disk_file_object(self):
 | 
					    def test_g4_non_disk_file_object(self, tmp_path):
 | 
				
			||||||
        """Testing loading from non-disk non-BytesIO file object"""
 | 
					        """Testing loading from non-disk non-BytesIO file object"""
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4_500.tif"
 | 
					        test_file = "Tests/images/hopper_g4_500.tif"
 | 
				
			||||||
        s = io.BytesIO()
 | 
					        s = io.BytesIO()
 | 
				
			||||||
| 
						 | 
					@ -91,7 +90,7 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
        r = io.BufferedReader(s)
 | 
					        r = io.BufferedReader(s)
 | 
				
			||||||
        with Image.open(r) as im:
 | 
					        with Image.open(r) as im:
 | 
				
			||||||
            assert im.size == (500, 500)
 | 
					            assert im.size == (500, 500)
 | 
				
			||||||
            self._assert_noerr(im)
 | 
					            self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_eq_png(self):
 | 
					    def test_g4_eq_png(self):
 | 
				
			||||||
        """ Checking that we're actually getting the data that we expect"""
 | 
					        """ Checking that we're actually getting the data that we expect"""
 | 
				
			||||||
| 
						 | 
					@ -106,18 +105,18 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            with Image.open("Tests/images/g4-fillorder-test.tif") as g4:
 | 
					            with Image.open("Tests/images/g4-fillorder-test.tif") as g4:
 | 
				
			||||||
                assert_image_equal(g4, png)
 | 
					                assert_image_equal(g4, png)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_write(self):
 | 
					    def test_g4_write(self, tmp_path):
 | 
				
			||||||
        """Checking to see that the saved image is the same as what we wrote"""
 | 
					        """Checking to see that the saved image is the same as what we wrote"""
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4_500.tif"
 | 
					        test_file = "Tests/images/hopper_g4_500.tif"
 | 
				
			||||||
        with Image.open(test_file) as orig:
 | 
					        with Image.open(test_file) as orig:
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
            rot = orig.transpose(Image.ROTATE_90)
 | 
					            rot = orig.transpose(Image.ROTATE_90)
 | 
				
			||||||
            assert rot.size == (500, 500)
 | 
					            assert rot.size == (500, 500)
 | 
				
			||||||
            rot.save(out)
 | 
					            rot.save(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with Image.open(out) as reread:
 | 
					            with Image.open(out) as reread:
 | 
				
			||||||
                assert reread.size == (500, 500)
 | 
					                assert reread.size == (500, 500)
 | 
				
			||||||
                self._assert_noerr(reread)
 | 
					                self._assert_noerr(tmp_path, reread)
 | 
				
			||||||
                assert_image_equal(reread, rot)
 | 
					                assert_image_equal(reread, rot)
 | 
				
			||||||
                assert reread.info["compression"] == "group4"
 | 
					                assert reread.info["compression"] == "group4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,10 +134,10 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
 | 
					            assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_write_metadata(self):
 | 
					    def test_write_metadata(self, tmp_path):
 | 
				
			||||||
        """ Test metadata writing through libtiff """
 | 
					        """ Test metadata writing through libtiff """
 | 
				
			||||||
        for legacy_api in [False, True]:
 | 
					        for legacy_api in [False, True]:
 | 
				
			||||||
            f = self.tempfile("temp.tiff")
 | 
					            f = str(tmp_path / "temp.tiff")
 | 
				
			||||||
            with Image.open("Tests/images/hopper_g4.tif") as img:
 | 
					            with Image.open("Tests/images/hopper_g4.tif") as img:
 | 
				
			||||||
                img.save(f, tiffinfo=img.tag)
 | 
					                img.save(f, tiffinfo=img.tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,7 +182,7 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            for field in requested_fields:
 | 
					            for field in requested_fields:
 | 
				
			||||||
                assert field in reloaded, "%s not in metadata" % field
 | 
					                assert field in reloaded, "%s not in metadata" % field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_additional_metadata(self):
 | 
					    def test_additional_metadata(self, tmp_path):
 | 
				
			||||||
        # these should not crash. Seriously dummy data, most of it doesn't make
 | 
					        # these should not crash. Seriously dummy data, most of it doesn't make
 | 
				
			||||||
        # any sense, so we're running up against limits where we're asking
 | 
					        # any sense, so we're running up against limits where we're asking
 | 
				
			||||||
        # libtiff to do stupid things.
 | 
					        # libtiff to do stupid things.
 | 
				
			||||||
| 
						 | 
					@ -232,14 +231,14 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            # Extra samples really doesn't make sense in this application.
 | 
					            # Extra samples really doesn't make sense in this application.
 | 
				
			||||||
            del new_ifd[338]
 | 
					            del new_ifd[338]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
            TiffImagePlugin.WRITE_LIBTIFF = True
 | 
					            TiffImagePlugin.WRITE_LIBTIFF = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            im.save(out, tiffinfo=new_ifd)
 | 
					            im.save(out, tiffinfo=new_ifd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_custom_metadata(self):
 | 
					    def test_custom_metadata(self, tmp_path):
 | 
				
			||||||
        tc = namedtuple("test_case", "value,type,supported_by_default")
 | 
					        tc = namedtuple("test_case", "value,type,supported_by_default")
 | 
				
			||||||
        custom = {
 | 
					        custom = {
 | 
				
			||||||
            37000 + k: v
 | 
					            37000 + k: v
 | 
				
			||||||
| 
						 | 
					@ -284,7 +283,7 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            def check_tags(tiffinfo):
 | 
					            def check_tags(tiffinfo):
 | 
				
			||||||
                im = hopper()
 | 
					                im = hopper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                out = self.tempfile("temp.tif")
 | 
					                out = str(tmp_path / "temp.tif")
 | 
				
			||||||
                im.save(out, tiffinfo=tiffinfo)
 | 
					                im.save(out, tiffinfo=tiffinfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                with Image.open(out) as reloaded:
 | 
					                with Image.open(out) as reloaded:
 | 
				
			||||||
| 
						 | 
					@ -323,26 +322,26 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_int_dpi(self):
 | 
					    def test_int_dpi(self, tmp_path):
 | 
				
			||||||
        # issue #1765
 | 
					        # issue #1765
 | 
				
			||||||
        im = hopper("RGB")
 | 
					        im = hopper("RGB")
 | 
				
			||||||
        out = self.tempfile("temp.tif")
 | 
					        out = str(tmp_path / "temp.tif")
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = True
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = True
 | 
				
			||||||
        im.save(out, dpi=(72, 72))
 | 
					        im.save(out, dpi=(72, 72))
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
				
			||||||
        with Image.open(out) as reloaded:
 | 
					        with Image.open(out) as reloaded:
 | 
				
			||||||
            assert reloaded.info["dpi"] == (72.0, 72.0)
 | 
					            assert reloaded.info["dpi"] == (72.0, 72.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g3_compression(self):
 | 
					    def test_g3_compression(self, tmp_path):
 | 
				
			||||||
        with Image.open("Tests/images/hopper_g4_500.tif") as i:
 | 
					        with Image.open("Tests/images/hopper_g4_500.tif") as i:
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
            i.save(out, compression="group3")
 | 
					            i.save(out, compression="group3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with Image.open(out) as reread:
 | 
					            with Image.open(out) as reread:
 | 
				
			||||||
                assert reread.info["compression"] == "group3"
 | 
					                assert reread.info["compression"] == "group3"
 | 
				
			||||||
                assert_image_equal(reread, i)
 | 
					                assert_image_equal(reread, i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_little_endian(self):
 | 
					    def test_little_endian(self, tmp_path):
 | 
				
			||||||
        with Image.open("Tests/images/16bit.deflate.tif") as im:
 | 
					        with Image.open("Tests/images/16bit.deflate.tif") as im:
 | 
				
			||||||
            assert im.getpixel((0, 0)) == 480
 | 
					            assert im.getpixel((0, 0)) == 480
 | 
				
			||||||
            assert im.mode == "I;16"
 | 
					            assert im.mode == "I;16"
 | 
				
			||||||
| 
						 | 
					@ -352,7 +351,7 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            assert b[0] == ord(b"\xe0")
 | 
					            assert b[0] == ord(b"\xe0")
 | 
				
			||||||
            assert b[1] == ord(b"\x01")
 | 
					            assert b[1] == ord(b"\x01")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
            # out = "temp.le.tif"
 | 
					            # out = "temp.le.tif"
 | 
				
			||||||
            im.save(out)
 | 
					            im.save(out)
 | 
				
			||||||
        with Image.open(out) as reread:
 | 
					        with Image.open(out) as reread:
 | 
				
			||||||
| 
						 | 
					@ -361,7 +360,7 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
        # UNDONE - libtiff defaults to writing in native endian, so
 | 
					        # UNDONE - libtiff defaults to writing in native endian, so
 | 
				
			||||||
        # on big endian, we'll get back mode = 'I;16B' here.
 | 
					        # on big endian, we'll get back mode = 'I;16B' here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_big_endian(self):
 | 
					    def test_big_endian(self, tmp_path):
 | 
				
			||||||
        with Image.open("Tests/images/16bit.MM.deflate.tif") as im:
 | 
					        with Image.open("Tests/images/16bit.MM.deflate.tif") as im:
 | 
				
			||||||
            assert im.getpixel((0, 0)) == 480
 | 
					            assert im.getpixel((0, 0)) == 480
 | 
				
			||||||
            assert im.mode == "I;16B"
 | 
					            assert im.mode == "I;16B"
 | 
				
			||||||
| 
						 | 
					@ -372,17 +371,17 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            assert b[0] == ord(b"\x01")
 | 
					            assert b[0] == ord(b"\x01")
 | 
				
			||||||
            assert b[1] == ord(b"\xe0")
 | 
					            assert b[1] == ord(b"\xe0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
            im.save(out)
 | 
					            im.save(out)
 | 
				
			||||||
            with Image.open(out) as reread:
 | 
					            with Image.open(out) as reread:
 | 
				
			||||||
                assert reread.info["compression"] == im.info["compression"]
 | 
					                assert reread.info["compression"] == im.info["compression"]
 | 
				
			||||||
                assert reread.getpixel((0, 0)) == 480
 | 
					                assert reread.getpixel((0, 0)) == 480
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_string_info(self):
 | 
					    def test_g4_string_info(self, tmp_path):
 | 
				
			||||||
        """Tests String data in info directory"""
 | 
					        """Tests String data in info directory"""
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4_500.tif"
 | 
					        test_file = "Tests/images/hopper_g4_500.tif"
 | 
				
			||||||
        with Image.open(test_file) as orig:
 | 
					        with Image.open(test_file) as orig:
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            orig.tag[269] = "temp.tif"
 | 
					            orig.tag[269] = "temp.tif"
 | 
				
			||||||
            orig.save(out)
 | 
					            orig.save(out)
 | 
				
			||||||
| 
						 | 
					@ -406,10 +405,10 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
 | 
					            assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_blur(self):
 | 
					    def test_blur(self, tmp_path):
 | 
				
			||||||
        # test case from irc, how to do blur on b/w image
 | 
					        # test case from irc, how to do blur on b/w image
 | 
				
			||||||
        # and save to compressed tif.
 | 
					        # and save to compressed tif.
 | 
				
			||||||
        out = self.tempfile("temp.tif")
 | 
					        out = str(tmp_path / "temp.tif")
 | 
				
			||||||
        with Image.open("Tests/images/pport_g4.tif") as im:
 | 
					        with Image.open("Tests/images/pport_g4.tif") as im:
 | 
				
			||||||
            im = im.convert("L")
 | 
					            im = im.convert("L")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -421,11 +420,11 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            assert_image_equal(im, im2)
 | 
					            assert_image_equal(im, im2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_compressions(self):
 | 
					    def test_compressions(self, tmp_path):
 | 
				
			||||||
        # Test various tiff compressions and assert similar image content but reduced
 | 
					        # Test various tiff compressions and assert similar image content but reduced
 | 
				
			||||||
        # file sizes.
 | 
					        # file sizes.
 | 
				
			||||||
        im = hopper("RGB")
 | 
					        im = hopper("RGB")
 | 
				
			||||||
        out = self.tempfile("temp.tif")
 | 
					        out = str(tmp_path / "temp.tif")
 | 
				
			||||||
        im.save(out)
 | 
					        im.save(out)
 | 
				
			||||||
        size_raw = os.path.getsize(out)
 | 
					        size_raw = os.path.getsize(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -449,9 +448,9 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
        assert size_compressed > size_jpeg
 | 
					        assert size_compressed > size_jpeg
 | 
				
			||||||
        assert size_jpeg > size_jpeg_30
 | 
					        assert size_jpeg > size_jpeg_30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_quality(self):
 | 
					    def test_quality(self, tmp_path):
 | 
				
			||||||
        im = hopper("RGB")
 | 
					        im = hopper("RGB")
 | 
				
			||||||
        out = self.tempfile("temp.tif")
 | 
					        out = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with pytest.raises(ValueError):
 | 
					        with pytest.raises(ValueError):
 | 
				
			||||||
            im.save(out, compression="tiff_lzw", quality=50)
 | 
					            im.save(out, compression="tiff_lzw", quality=50)
 | 
				
			||||||
| 
						 | 
					@ -464,21 +463,21 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
        im.save(out, compression="jpeg", quality=0)
 | 
					        im.save(out, compression="jpeg", quality=0)
 | 
				
			||||||
        im.save(out, compression="jpeg", quality=100)
 | 
					        im.save(out, compression="jpeg", quality=100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cmyk_save(self):
 | 
					    def test_cmyk_save(self, tmp_path):
 | 
				
			||||||
        im = hopper("CMYK")
 | 
					        im = hopper("CMYK")
 | 
				
			||||||
        out = self.tempfile("temp.tif")
 | 
					        out = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im.save(out, compression="tiff_adobe_deflate")
 | 
					        im.save(out, compression="tiff_adobe_deflate")
 | 
				
			||||||
        with Image.open(out) as im2:
 | 
					        with Image.open(out) as im2:
 | 
				
			||||||
            assert_image_equal(im, im2)
 | 
					            assert_image_equal(im, im2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def xtest_bw_compression_w_rgb(self):
 | 
					    def xtest_bw_compression_w_rgb(self, tmp_path):
 | 
				
			||||||
        """ This test passes, but when running all tests causes a failure due
 | 
					        """ This test passes, but when running all tests causes a failure due
 | 
				
			||||||
            to output on stderr from the error thrown by libtiff. We need to
 | 
					            to output on stderr from the error thrown by libtiff. We need to
 | 
				
			||||||
            capture that but not now"""
 | 
					            capture that but not now"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = hopper("RGB")
 | 
					        im = hopper("RGB")
 | 
				
			||||||
        out = self.tempfile("temp.tif")
 | 
					        out = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with pytest.raises(IOError):
 | 
					        with pytest.raises(IOError):
 | 
				
			||||||
            im.save(out, compression="tiff_ccitt")
 | 
					            im.save(out, compression="tiff_ccitt")
 | 
				
			||||||
| 
						 | 
					@ -619,22 +618,22 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
				
			||||||
        TiffImagePlugin.READ_LIBTIFF = False
 | 
					        TiffImagePlugin.READ_LIBTIFF = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_crashing_metadata(self):
 | 
					    def test_crashing_metadata(self, tmp_path):
 | 
				
			||||||
        # issue 1597
 | 
					        # issue 1597
 | 
				
			||||||
        with Image.open("Tests/images/rdf.tif") as im:
 | 
					        with Image.open("Tests/images/rdf.tif") as im:
 | 
				
			||||||
            out = self.tempfile("temp.tif")
 | 
					            out = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            TiffImagePlugin.WRITE_LIBTIFF = True
 | 
					            TiffImagePlugin.WRITE_LIBTIFF = True
 | 
				
			||||||
            # this shouldn't crash
 | 
					            # this shouldn't crash
 | 
				
			||||||
            im.save(out, format="TIFF")
 | 
					            im.save(out, format="TIFF")
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_page_number_x_0(self):
 | 
					    def test_page_number_x_0(self, tmp_path):
 | 
				
			||||||
        # Issue 973
 | 
					        # Issue 973
 | 
				
			||||||
        # Test TIFF with tag 297 (Page Number) having value of 0 0.
 | 
					        # Test TIFF with tag 297 (Page Number) having value of 0 0.
 | 
				
			||||||
        # The first number is the current page number.
 | 
					        # The first number is the current page number.
 | 
				
			||||||
        # The second is the total number of pages, zero means not available.
 | 
					        # The second is the total number of pages, zero means not available.
 | 
				
			||||||
        outfile = self.tempfile("temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        # Created by printing a page in Chrome to PDF, then:
 | 
					        # Created by printing a page in Chrome to PDF, then:
 | 
				
			||||||
        # /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
 | 
					        # /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
 | 
				
			||||||
        # -dNOPAUSE /tmp/test.pdf -c quit
 | 
					        # -dNOPAUSE /tmp/test.pdf -c quit
 | 
				
			||||||
| 
						 | 
					@ -643,10 +642,10 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            # Should not divide by zero
 | 
					            # Should not divide by zero
 | 
				
			||||||
            im.save(outfile)
 | 
					            im.save(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_fd_duplication(self):
 | 
					    def test_fd_duplication(self, tmp_path):
 | 
				
			||||||
        # https://github.com/python-pillow/Pillow/issues/1651
 | 
					        # https://github.com/python-pillow/Pillow/issues/1651
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tmpfile = self.tempfile("temp.tif")
 | 
					        tmpfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        with open(tmpfile, "wb") as f:
 | 
					        with open(tmpfile, "wb") as f:
 | 
				
			||||||
            with open("Tests/images/g4-multi.tiff", "rb") as src:
 | 
					            with open("Tests/images/g4-multi.tiff", "rb") as src:
 | 
				
			||||||
                f.write(src.read())
 | 
					                f.write(src.read())
 | 
				
			||||||
| 
						 | 
					@ -685,9 +684,9 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            assert im.size == (10, 10)
 | 
					            assert im.size == (10, 10)
 | 
				
			||||||
            im.load()
 | 
					            im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_tiff_with_jpegtables(self):
 | 
					    def test_save_tiff_with_jpegtables(self, tmp_path):
 | 
				
			||||||
        # Arrange
 | 
					        # Arrange
 | 
				
			||||||
        outfile = self.tempfile("temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Created with ImageMagick: convert hopper.jpg hopper_jpg.tif
 | 
					        # Created with ImageMagick: convert hopper.jpg hopper_jpg.tif
 | 
				
			||||||
        # Contains JPEGTables (347) tag
 | 
					        # Contains JPEGTables (347) tag
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,16 +15,16 @@ class TestFileLibTiffSmall(LibTiffTestCase):
 | 
				
			||||||
        file just before reading in libtiff. These tests remain
 | 
					        file just before reading in libtiff. These tests remain
 | 
				
			||||||
        to ensure that it stays fixed. """
 | 
					        to ensure that it stays fixed. """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_hopper_file(self):
 | 
					    def test_g4_hopper_file(self, tmp_path):
 | 
				
			||||||
        """Testing the open file load path"""
 | 
					        """Testing the open file load path"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4.tif"
 | 
					        test_file = "Tests/images/hopper_g4.tif"
 | 
				
			||||||
        with open(test_file, "rb") as f:
 | 
					        with open(test_file, "rb") as f:
 | 
				
			||||||
            with Image.open(f) as im:
 | 
					            with Image.open(f) as im:
 | 
				
			||||||
                assert im.size == (128, 128)
 | 
					                assert im.size == (128, 128)
 | 
				
			||||||
                self._assert_noerr(im)
 | 
					                self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_hopper_bytesio(self):
 | 
					    def test_g4_hopper_bytesio(self, tmp_path):
 | 
				
			||||||
        """Testing the bytesio loading code path"""
 | 
					        """Testing the bytesio loading code path"""
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4.tif"
 | 
					        test_file = "Tests/images/hopper_g4.tif"
 | 
				
			||||||
        s = BytesIO()
 | 
					        s = BytesIO()
 | 
				
			||||||
| 
						 | 
					@ -33,12 +33,12 @@ class TestFileLibTiffSmall(LibTiffTestCase):
 | 
				
			||||||
            s.seek(0)
 | 
					            s.seek(0)
 | 
				
			||||||
        with Image.open(s) as im:
 | 
					        with Image.open(s) as im:
 | 
				
			||||||
            assert im.size == (128, 128)
 | 
					            assert im.size == (128, 128)
 | 
				
			||||||
            self._assert_noerr(im)
 | 
					            self._assert_noerr(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_g4_hopper(self):
 | 
					    def test_g4_hopper(self, tmp_path):
 | 
				
			||||||
        """The 128x128 lena image failed for some reason."""
 | 
					        """The 128x128 lena image failed for some reason."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_file = "Tests/images/hopper_g4.tif"
 | 
					        test_file = "Tests/images/hopper_g4.tif"
 | 
				
			||||||
        with Image.open(test_file) as im:
 | 
					        with Image.open(test_file) as im:
 | 
				
			||||||
            assert im.size == (128, 128)
 | 
					            assert im.size == (128, 128)
 | 
				
			||||||
            self._assert_noerr(im)
 | 
					            self._assert_noerr(tmp_path, im)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +1,24 @@
 | 
				
			||||||
import os.path
 | 
					import os.path
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import (
 | 
				
			||||||
    PillowTestCase,
 | 
					    IMCONVERT,
 | 
				
			||||||
    assert_image_equal,
 | 
					    assert_image_equal,
 | 
				
			||||||
    hopper,
 | 
					    hopper,
 | 
				
			||||||
    imagemagick_available,
 | 
					    imagemagick_available,
 | 
				
			||||||
    skip_known_bad_test,
 | 
					    skip_known_bad_test,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_roundtrip = imagemagick_available()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFilePalm(PillowTestCase):
 | 
					 | 
				
			||||||
    _roundtrip = imagemagick_available()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def helper_save_as_palm(self, mode):
 | 
					def helper_save_as_palm(tmp_path, mode):
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    im = hopper(mode)
 | 
					    im = hopper(mode)
 | 
				
			||||||
        outfile = self.tempfile("temp_" + mode + ".palm")
 | 
					    outfile = str(tmp_path / ("temp_" + mode + ".palm"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Act
 | 
					    # Act
 | 
				
			||||||
    im.save(outfile)
 | 
					    im.save(outfile)
 | 
				
			||||||
| 
						 | 
					@ -26,46 +27,64 @@ class TestFilePalm(PillowTestCase):
 | 
				
			||||||
    assert os.path.isfile(outfile)
 | 
					    assert os.path.isfile(outfile)
 | 
				
			||||||
    assert os.path.getsize(outfile) > 0
 | 
					    assert os.path.getsize(outfile) > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def roundtrip(self, mode):
 | 
					
 | 
				
			||||||
        if not self._roundtrip:
 | 
					def open_with_imagemagick(tmp_path, f):
 | 
				
			||||||
 | 
					    if not imagemagick_available():
 | 
				
			||||||
 | 
					        raise OSError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    outfile = str(tmp_path / "temp.png")
 | 
				
			||||||
 | 
					    rc = subprocess.call(
 | 
				
			||||||
 | 
					        [IMCONVERT, f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    if rc:
 | 
				
			||||||
 | 
					        raise OSError
 | 
				
			||||||
 | 
					    return Image.open(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def roundtrip(tmp_path, mode):
 | 
				
			||||||
 | 
					    if not _roundtrip:
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = hopper(mode)
 | 
					    im = hopper(mode)
 | 
				
			||||||
        outfile = self.tempfile("temp.palm")
 | 
					    outfile = str(tmp_path / "temp.palm")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im.save(outfile)
 | 
					    im.save(outfile)
 | 
				
			||||||
        converted = self.open_withImagemagick(outfile)
 | 
					    converted = open_with_imagemagick(tmp_path, outfile)
 | 
				
			||||||
    assert_image_equal(converted, im)
 | 
					    assert_image_equal(converted, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_monochrome(self):
 | 
					
 | 
				
			||||||
 | 
					def test_monochrome(tmp_path):
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    mode = "1"
 | 
					    mode = "1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Act / Assert
 | 
					    # Act / Assert
 | 
				
			||||||
        self.helper_save_as_palm(mode)
 | 
					    helper_save_as_palm(tmp_path, mode)
 | 
				
			||||||
        self.roundtrip(mode)
 | 
					    roundtrip(tmp_path, mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_p_mode(self):
 | 
					
 | 
				
			||||||
 | 
					def test_p_mode(tmp_path):
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    mode = "P"
 | 
					    mode = "P"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Act / Assert
 | 
					    # Act / Assert
 | 
				
			||||||
        self.helper_save_as_palm(mode)
 | 
					    helper_save_as_palm(tmp_path, mode)
 | 
				
			||||||
    skip_known_bad_test("Palm P image is wrong")
 | 
					    skip_known_bad_test("Palm P image is wrong")
 | 
				
			||||||
        self.roundtrip(mode)
 | 
					    roundtrip(tmp_path, mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_l_ioerror(self):
 | 
					
 | 
				
			||||||
 | 
					def test_l_ioerror(tmp_path):
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    mode = "L"
 | 
					    mode = "L"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Act / Assert
 | 
					    # Act / Assert
 | 
				
			||||||
    with pytest.raises(IOError):
 | 
					    with pytest.raises(IOError):
 | 
				
			||||||
            self.helper_save_as_palm(mode)
 | 
					        helper_save_as_palm(tmp_path, mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rgb_ioerror(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rgb_ioerror(tmp_path):
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    mode = "RGB"
 | 
					    mode = "RGB"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Act / Assert
 | 
					    # Act / Assert
 | 
				
			||||||
    with pytest.raises(IOError):
 | 
					    with pytest.raises(IOError):
 | 
				
			||||||
            self.helper_save_as_palm(mode)
 | 
					        helper_save_as_palm(tmp_path, mode)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,7 @@
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_load_raw():
 | 
				
			||||||
class TestFilePcd(PillowTestCase):
 | 
					 | 
				
			||||||
    def test_load_raw(self):
 | 
					 | 
				
			||||||
    with Image.open("Tests/images/hopper.pcd") as im:
 | 
					    with Image.open("Tests/images/hopper.pcd") as im:
 | 
				
			||||||
        im.load()  # should not segfault.
 | 
					        im.load()  # should not segfault.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,11 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image, ImageFile, PcxImagePlugin
 | 
					from PIL import Image, ImageFile, PcxImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, hopper
 | 
					from .helper import assert_image_equal, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFilePcx(PillowTestCase):
 | 
					def _roundtrip(tmp_path, im):
 | 
				
			||||||
    def _roundtrip(self, im):
 | 
					    f = str(tmp_path / "temp.pcx")
 | 
				
			||||||
        f = self.tempfile("temp.pcx")
 | 
					 | 
				
			||||||
    im.save(f)
 | 
					    im.save(f)
 | 
				
			||||||
    with Image.open(f) as im2:
 | 
					    with Image.open(f) as im2:
 | 
				
			||||||
        assert im2.mode == im.mode
 | 
					        assert im2.mode == im.mode
 | 
				
			||||||
| 
						 | 
					@ -15,32 +14,36 @@ class TestFilePcx(PillowTestCase):
 | 
				
			||||||
        assert im2.get_format_mimetype() == "image/x-pcx"
 | 
					        assert im2.get_format_mimetype() == "image/x-pcx"
 | 
				
			||||||
        assert_image_equal(im2, im)
 | 
					        assert_image_equal(im2, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sanity(self):
 | 
					
 | 
				
			||||||
 | 
					def test_sanity(tmp_path):
 | 
				
			||||||
    for mode in ("1", "L", "P", "RGB"):
 | 
					    for mode in ("1", "L", "P", "RGB"):
 | 
				
			||||||
            self._roundtrip(hopper(mode))
 | 
					        _roundtrip(tmp_path, hopper(mode))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Test an unsupported mode
 | 
					    # Test an unsupported mode
 | 
				
			||||||
        f = self.tempfile("temp.pcx")
 | 
					    f = str(tmp_path / "temp.pcx")
 | 
				
			||||||
    im = hopper("RGBA")
 | 
					    im = hopper("RGBA")
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        im.save(f)
 | 
					        im.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_file(self):
 | 
					
 | 
				
			||||||
 | 
					def test_invalid_file():
 | 
				
			||||||
    invalid_file = "Tests/images/flower.jpg"
 | 
					    invalid_file = "Tests/images/flower.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with pytest.raises(SyntaxError):
 | 
					    with pytest.raises(SyntaxError):
 | 
				
			||||||
        PcxImagePlugin.PcxImageFile(invalid_file)
 | 
					        PcxImagePlugin.PcxImageFile(invalid_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_odd(self):
 | 
					
 | 
				
			||||||
        # see issue #523, odd sized images should have a stride that's even.
 | 
					def test_odd(tmp_path):
 | 
				
			||||||
        # not that imagemagick or gimp write pcx that way.
 | 
					    # See issue #523, odd sized images should have a stride that's even.
 | 
				
			||||||
        # we were not handling properly.
 | 
					    # 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
 | 
					        # larger, odd sized images are better here to ensure that
 | 
				
			||||||
        # we handle interrupted scan lines properly.
 | 
					        # we handle interrupted scan lines properly.
 | 
				
			||||||
            self._roundtrip(hopper(mode).resize((511, 511)))
 | 
					        _roundtrip(tmp_path, hopper(mode).resize((511, 511)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pil184(self):
 | 
					
 | 
				
			||||||
 | 
					def test_pil184():
 | 
				
			||||||
    # Check reading of files where xmin/xmax is not zero.
 | 
					    # Check reading of files where xmin/xmax is not zero.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test_file = "Tests/images/pil184.pcx"
 | 
					    test_file = "Tests/images/pil184.pcx"
 | 
				
			||||||
| 
						 | 
					@ -51,45 +54,51 @@ class TestFilePcx(PillowTestCase):
 | 
				
			||||||
        # Make sure all pixels are either 0 or 255.
 | 
					        # Make sure all pixels are either 0 or 255.
 | 
				
			||||||
        assert im.histogram()[0] + im.histogram()[255] == 447 * 144
 | 
					        assert im.histogram()[0] + im.histogram()[255] == 447 * 144
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_1px_width(self):
 | 
					
 | 
				
			||||||
 | 
					def test_1px_width(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (1, 256))
 | 
					    im = Image.new("L", (1, 256))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(256):
 | 
					    for y in range(256):
 | 
				
			||||||
        px[0, y] = y
 | 
					        px[0, y] = y
 | 
				
			||||||
        self._roundtrip(im)
 | 
					    _roundtrip(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_large_count(self):
 | 
					
 | 
				
			||||||
 | 
					def test_large_count(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (256, 1))
 | 
					    im = Image.new("L", (256, 1))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for x in range(256):
 | 
					    for x in range(256):
 | 
				
			||||||
        px[x, 0] = x // 67 * 67
 | 
					        px[x, 0] = x // 67 * 67
 | 
				
			||||||
        self._roundtrip(im)
 | 
					    _roundtrip(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _test_buffer_overflow(self, im, size=1024):
 | 
					
 | 
				
			||||||
 | 
					def _test_buffer_overflow(tmp_path, im, size=1024):
 | 
				
			||||||
    _last = ImageFile.MAXBLOCK
 | 
					    _last = ImageFile.MAXBLOCK
 | 
				
			||||||
    ImageFile.MAXBLOCK = size
 | 
					    ImageFile.MAXBLOCK = size
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
            self._roundtrip(im)
 | 
					        _roundtrip(tmp_path, im)
 | 
				
			||||||
    finally:
 | 
					    finally:
 | 
				
			||||||
        ImageFile.MAXBLOCK = _last
 | 
					        ImageFile.MAXBLOCK = _last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_break_in_count_overflow(self):
 | 
					
 | 
				
			||||||
 | 
					def test_break_in_count_overflow(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (256, 5))
 | 
					    im = Image.new("L", (256, 5))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(4):
 | 
					    for y in range(4):
 | 
				
			||||||
        for x in range(256):
 | 
					        for x in range(256):
 | 
				
			||||||
            px[x, y] = x % 128
 | 
					            px[x, y] = x % 128
 | 
				
			||||||
        self._test_buffer_overflow(im)
 | 
					    _test_buffer_overflow(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_break_one_in_loop(self):
 | 
					
 | 
				
			||||||
 | 
					def test_break_one_in_loop(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (256, 5))
 | 
					    im = Image.new("L", (256, 5))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(5):
 | 
					    for y in range(5):
 | 
				
			||||||
        for x in range(256):
 | 
					        for x in range(256):
 | 
				
			||||||
            px[x, y] = x % 128
 | 
					            px[x, y] = x % 128
 | 
				
			||||||
        self._test_buffer_overflow(im)
 | 
					    _test_buffer_overflow(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_break_many_in_loop(self):
 | 
					
 | 
				
			||||||
 | 
					def test_break_many_in_loop(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (256, 5))
 | 
					    im = Image.new("L", (256, 5))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(4):
 | 
					    for y in range(4):
 | 
				
			||||||
| 
						 | 
					@ -97,18 +106,20 @@ class TestFilePcx(PillowTestCase):
 | 
				
			||||||
            px[x, y] = x % 128
 | 
					            px[x, y] = x % 128
 | 
				
			||||||
    for x in range(8):
 | 
					    for x in range(8):
 | 
				
			||||||
        px[x, 4] = 16
 | 
					        px[x, 4] = 16
 | 
				
			||||||
        self._test_buffer_overflow(im)
 | 
					    _test_buffer_overflow(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_break_one_at_end(self):
 | 
					
 | 
				
			||||||
 | 
					def test_break_one_at_end(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (256, 5))
 | 
					    im = Image.new("L", (256, 5))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(5):
 | 
					    for y in range(5):
 | 
				
			||||||
        for x in range(256):
 | 
					        for x in range(256):
 | 
				
			||||||
            px[x, y] = x % 128
 | 
					            px[x, y] = x % 128
 | 
				
			||||||
    px[0, 3] = 128 + 64
 | 
					    px[0, 3] = 128 + 64
 | 
				
			||||||
        self._test_buffer_overflow(im)
 | 
					    _test_buffer_overflow(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_break_many_at_end(self):
 | 
					
 | 
				
			||||||
 | 
					def test_break_many_at_end(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (256, 5))
 | 
					    im = Image.new("L", (256, 5))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(5):
 | 
					    for y in range(5):
 | 
				
			||||||
| 
						 | 
					@ -117,9 +128,10 @@ class TestFilePcx(PillowTestCase):
 | 
				
			||||||
    for x in range(4):
 | 
					    for x in range(4):
 | 
				
			||||||
        px[x * 2, 3] = 128 + 64
 | 
					        px[x * 2, 3] = 128 + 64
 | 
				
			||||||
        px[x + 256 - 4, 3] = 0
 | 
					        px[x + 256 - 4, 3] = 0
 | 
				
			||||||
        self._test_buffer_overflow(im)
 | 
					    _test_buffer_overflow(tmp_path, im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_break_padding(self):
 | 
					
 | 
				
			||||||
 | 
					def test_break_padding(tmp_path):
 | 
				
			||||||
    im = Image.new("L", (257, 5))
 | 
					    im = Image.new("L", (257, 5))
 | 
				
			||||||
    px = im.load()
 | 
					    px = im.load()
 | 
				
			||||||
    for y in range(5):
 | 
					    for y in range(5):
 | 
				
			||||||
| 
						 | 
					@ -127,4 +139,4 @@ class TestFilePcx(PillowTestCase):
 | 
				
			||||||
            px[x, y] = x % 128
 | 
					            px[x, y] = x % 128
 | 
				
			||||||
    for x in range(5):
 | 
					    for x in range(5):
 | 
				
			||||||
        px[x, 3] = 0
 | 
					        px[x, 3] = 0
 | 
				
			||||||
        self._test_buffer_overflow(im)
 | 
					    _test_buffer_overflow(tmp_path, im)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
import zlib
 | 
					import zlib
 | 
				
			||||||
from io import BytesIO
 | 
					from io import BytesIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +7,6 @@ from PIL import Image, ImageFile, PngImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import (
 | 
				
			||||||
    PillowLeakTestCase,
 | 
					    PillowLeakTestCase,
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    assert_image,
 | 
					    assert_image,
 | 
				
			||||||
    assert_image_equal,
 | 
					    assert_image_equal,
 | 
				
			||||||
    hopper,
 | 
					    hopper,
 | 
				
			||||||
| 
						 | 
					@ -55,7 +53,7 @@ def roundtrip(im, **options):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@skip_unless_feature("zlib")
 | 
					@skip_unless_feature("zlib")
 | 
				
			||||||
class TestFilePng(PillowTestCase):
 | 
					class TestFilePng:
 | 
				
			||||||
    def get_chunks(self, filename):
 | 
					    def get_chunks(self, filename):
 | 
				
			||||||
        chunks = []
 | 
					        chunks = []
 | 
				
			||||||
        with open(filename, "rb") as fp:
 | 
					        with open(filename, "rb") as fp:
 | 
				
			||||||
| 
						 | 
					@ -72,12 +70,12 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        return chunks
 | 
					        return chunks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
 | 
					    @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
 | 
				
			||||||
    def test_sanity(self):
 | 
					    def test_sanity(self, tmp_path):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # internal version number
 | 
					        # internal version number
 | 
				
			||||||
        assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", Image.core.zlib_version)
 | 
					        assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", Image.core.zlib_version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_file = self.tempfile("temp.png")
 | 
					        test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        hopper("RGB").save(test_file)
 | 
					        hopper("RGB").save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -232,14 +230,14 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        # image has 876 transparent pixels
 | 
					        # image has 876 transparent pixels
 | 
				
			||||||
        assert im.getchannel("A").getcolors()[0][0] == 876
 | 
					        assert im.getchannel("A").getcolors()[0][0] == 876
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_p_transparent_palette(self):
 | 
					    def test_save_p_transparent_palette(self, tmp_path):
 | 
				
			||||||
        in_file = "Tests/images/pil123p.png"
 | 
					        in_file = "Tests/images/pil123p.png"
 | 
				
			||||||
        with Image.open(in_file) as im:
 | 
					        with Image.open(in_file) as im:
 | 
				
			||||||
            # 'transparency' contains a byte string with the opacity for
 | 
					            # 'transparency' contains a byte string with the opacity for
 | 
				
			||||||
            # each palette entry
 | 
					            # each palette entry
 | 
				
			||||||
            assert len(im.info["transparency"]) == 256
 | 
					            assert len(im.info["transparency"]) == 256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file)
 | 
					            im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # check if saved image contains same transparency
 | 
					        # check if saved image contains same transparency
 | 
				
			||||||
| 
						 | 
					@ -253,14 +251,14 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        # image has 124 unique alpha values
 | 
					        # image has 124 unique alpha values
 | 
				
			||||||
        assert len(im.getchannel("A").getcolors()) == 124
 | 
					        assert len(im.getchannel("A").getcolors()) == 124
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_p_single_transparency(self):
 | 
					    def test_save_p_single_transparency(self, tmp_path):
 | 
				
			||||||
        in_file = "Tests/images/p_trns_single.png"
 | 
					        in_file = "Tests/images/p_trns_single.png"
 | 
				
			||||||
        with Image.open(in_file) as im:
 | 
					        with Image.open(in_file) as im:
 | 
				
			||||||
            # pixel value 164 is full transparent
 | 
					            # pixel value 164 is full transparent
 | 
				
			||||||
            assert im.info["transparency"] == 164
 | 
					            assert im.info["transparency"] == 164
 | 
				
			||||||
            assert im.getpixel((31, 31)) == 164
 | 
					            assert im.getpixel((31, 31)) == 164
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file)
 | 
					            im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # check if saved image contains same transparency
 | 
					        # check if saved image contains same transparency
 | 
				
			||||||
| 
						 | 
					@ -276,14 +274,14 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        # image has 876 transparent pixels
 | 
					        # image has 876 transparent pixels
 | 
				
			||||||
        assert im.getchannel("A").getcolors()[0][0] == 876
 | 
					        assert im.getchannel("A").getcolors()[0][0] == 876
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_p_transparent_black(self):
 | 
					    def test_save_p_transparent_black(self, tmp_path):
 | 
				
			||||||
        # check if solid black image with full transparency
 | 
					        # check if solid black image with full transparency
 | 
				
			||||||
        # is supported (check for #1838)
 | 
					        # is supported (check for #1838)
 | 
				
			||||||
        im = Image.new("RGBA", (10, 10), (0, 0, 0, 0))
 | 
					        im = Image.new("RGBA", (10, 10), (0, 0, 0, 0))
 | 
				
			||||||
        assert im.getcolors() == [(100, (0, 0, 0, 0))]
 | 
					        assert im.getcolors() == [(100, (0, 0, 0, 0))]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = im.convert("P")
 | 
					        im = im.convert("P")
 | 
				
			||||||
        test_file = self.tempfile("temp.png")
 | 
					        test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
        im.save(test_file)
 | 
					        im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # check if saved image contains same transparency
 | 
					        # check if saved image contains same transparency
 | 
				
			||||||
| 
						 | 
					@ -294,7 +292,7 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        assert_image(im, "RGBA", (10, 10))
 | 
					        assert_image(im, "RGBA", (10, 10))
 | 
				
			||||||
        assert im.getcolors() == [(100, (0, 0, 0, 0))]
 | 
					        assert im.getcolors() == [(100, (0, 0, 0, 0))]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_greyscale_transparency(self):
 | 
					    def test_save_greyscale_transparency(self, tmp_path):
 | 
				
			||||||
        for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
 | 
					        for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
 | 
				
			||||||
            in_file = "Tests/images/" + mode.lower() + "_trns.png"
 | 
					            in_file = "Tests/images/" + mode.lower() + "_trns.png"
 | 
				
			||||||
            with Image.open(in_file) as im:
 | 
					            with Image.open(in_file) as im:
 | 
				
			||||||
| 
						 | 
					@ -304,7 +302,7 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
                im_rgba = im.convert("RGBA")
 | 
					                im_rgba = im.convert("RGBA")
 | 
				
			||||||
            assert im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
 | 
					            assert im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file)
 | 
					            im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with Image.open(test_file) as test_im:
 | 
					            with Image.open(test_file) as test_im:
 | 
				
			||||||
| 
						 | 
					@ -315,10 +313,10 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
            test_im_rgba = test_im.convert("RGBA")
 | 
					            test_im_rgba = test_im.convert("RGBA")
 | 
				
			||||||
            assert test_im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
 | 
					            assert test_im_rgba.getchannel("A").getcolors()[0][0] == num_transparent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_rgb_single_transparency(self):
 | 
					    def test_save_rgb_single_transparency(self, tmp_path):
 | 
				
			||||||
        in_file = "Tests/images/caption_6_33_22.png"
 | 
					        in_file = "Tests/images/caption_6_33_22.png"
 | 
				
			||||||
        with Image.open(in_file) as im:
 | 
					        with Image.open(in_file) as im:
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file)
 | 
					            im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_load_verify(self):
 | 
					    def test_load_verify(self):
 | 
				
			||||||
| 
						 | 
					@ -483,12 +481,12 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        im = roundtrip(im, transparency=(0, 1, 2))
 | 
					        im = roundtrip(im, transparency=(0, 1, 2))
 | 
				
			||||||
        assert im.info["transparency"] == (0, 1, 2)
 | 
					        assert im.info["transparency"] == (0, 1, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_trns_p(self):
 | 
					    def test_trns_p(self, tmp_path):
 | 
				
			||||||
        # Check writing a transparency of 0, issue #528
 | 
					        # Check writing a transparency of 0, issue #528
 | 
				
			||||||
        im = hopper("P")
 | 
					        im = hopper("P")
 | 
				
			||||||
        im.info["transparency"] = 0
 | 
					        im.info["transparency"] = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f = self.tempfile("temp.png")
 | 
					        f = str(tmp_path / "temp.png")
 | 
				
			||||||
        im.save(f)
 | 
					        im.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(f) as im2:
 | 
					        with Image.open(f) as im2:
 | 
				
			||||||
| 
						 | 
					@ -539,9 +537,9 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
            assert repr_png.format == "PNG"
 | 
					            assert repr_png.format == "PNG"
 | 
				
			||||||
            assert_image_equal(im, repr_png)
 | 
					            assert_image_equal(im, repr_png)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_chunk_order(self):
 | 
					    def test_chunk_order(self, tmp_path):
 | 
				
			||||||
        with Image.open("Tests/images/icc_profile.png") as im:
 | 
					        with Image.open("Tests/images/icc_profile.png") as im:
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.convert("P").save(test_file, dpi=(100, 100))
 | 
					            im.convert("P").save(test_file, dpi=(100, 100))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        chunks = self.get_chunks(test_file)
 | 
					        chunks = self.get_chunks(test_file)
 | 
				
			||||||
| 
						 | 
					@ -598,34 +596,34 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
            exif = im._getexif()
 | 
					            exif = im._getexif()
 | 
				
			||||||
        assert exif[274] == 1
 | 
					        assert exif[274] == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_exif_save(self):
 | 
					    def test_exif_save(self, tmp_path):
 | 
				
			||||||
        with Image.open("Tests/images/exif.png") as im:
 | 
					        with Image.open("Tests/images/exif.png") as im:
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file)
 | 
					            im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(test_file) as reloaded:
 | 
					        with Image.open(test_file) as reloaded:
 | 
				
			||||||
            exif = reloaded._getexif()
 | 
					            exif = reloaded._getexif()
 | 
				
			||||||
        assert exif[274] == 1
 | 
					        assert exif[274] == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_exif_from_jpg(self):
 | 
					    def test_exif_from_jpg(self, tmp_path):
 | 
				
			||||||
        with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
 | 
					        with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file)
 | 
					            im.save(test_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(test_file) as reloaded:
 | 
					        with Image.open(test_file) as reloaded:
 | 
				
			||||||
            exif = reloaded._getexif()
 | 
					            exif = reloaded._getexif()
 | 
				
			||||||
        assert exif[305] == "Adobe Photoshop CS Macintosh"
 | 
					        assert exif[305] == "Adobe Photoshop CS Macintosh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_exif_argument(self):
 | 
					    def test_exif_argument(self, tmp_path):
 | 
				
			||||||
        with Image.open(TEST_PNG_FILE) as im:
 | 
					        with Image.open(TEST_PNG_FILE) as im:
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					            test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
            im.save(test_file, exif=b"exifstring")
 | 
					            im.save(test_file, exif=b"exifstring")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(test_file) as reloaded:
 | 
					        with Image.open(test_file) as reloaded:
 | 
				
			||||||
            assert reloaded.info["exif"] == b"Exif\x00\x00exifstring"
 | 
					            assert reloaded.info["exif"] == b"Exif\x00\x00exifstring"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipIf(is_win32(), "requires Unix or macOS")
 | 
					@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
 | 
				
			||||||
@skip_unless_feature("zlib")
 | 
					@skip_unless_feature("zlib")
 | 
				
			||||||
class TestTruncatedPngPLeaks(PillowLeakTestCase):
 | 
					class TestTruncatedPngPLeaks(PillowLeakTestCase):
 | 
				
			||||||
    mem_limit = 2 * 1024  # max increase in K
 | 
					    mem_limit = 2 * 1024  # max increase in K
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,22 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper
 | 
					from .helper import assert_image_equal, assert_image_similar, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# sample ppm stream
 | 
					# sample ppm stream
 | 
				
			||||||
test_file = "Tests/images/hopper.ppm"
 | 
					TEST_FILE = "Tests/images/hopper.ppm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFilePpm(PillowTestCase):
 | 
					def test_sanity():
 | 
				
			||||||
    def test_sanity(self):
 | 
					    with Image.open(TEST_FILE) as im:
 | 
				
			||||||
        with Image.open(test_file) as im:
 | 
					 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert im.mode == "RGB"
 | 
					        assert im.mode == "RGB"
 | 
				
			||||||
        assert im.size == (128, 128)
 | 
					        assert im.size == (128, 128)
 | 
				
			||||||
        assert im.format, "PPM"
 | 
					        assert im.format, "PPM"
 | 
				
			||||||
        assert im.get_format_mimetype() == "image/x-portable-pixmap"
 | 
					        assert im.get_format_mimetype() == "image/x-portable-pixmap"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit_pgm(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit_pgm():
 | 
				
			||||||
    with Image.open("Tests/images/16_bit_binary.pgm") as im:
 | 
					    with Image.open("Tests/images/16_bit_binary.pgm") as im:
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert im.mode == "I"
 | 
					        assert im.mode == "I"
 | 
				
			||||||
| 
						 | 
					@ -26,35 +26,39 @@ class TestFilePpm(PillowTestCase):
 | 
				
			||||||
        with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt:
 | 
					        with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt:
 | 
				
			||||||
            assert_image_equal(im, tgt)
 | 
					            assert_image_equal(im, tgt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit_pgm_write(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit_pgm_write(tmp_path):
 | 
				
			||||||
    with Image.open("Tests/images/16_bit_binary.pgm") as im:
 | 
					    with Image.open("Tests/images/16_bit_binary.pgm") as im:
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            f = self.tempfile("temp.pgm")
 | 
					        f = str(tmp_path / "temp.pgm")
 | 
				
			||||||
        im.save(f, "PPM")
 | 
					        im.save(f, "PPM")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(f) as reloaded:
 | 
					        with Image.open(f) as reloaded:
 | 
				
			||||||
            assert_image_equal(im, reloaded)
 | 
					            assert_image_equal(im, reloaded)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pnm(self):
 | 
					
 | 
				
			||||||
 | 
					def test_pnm(tmp_path):
 | 
				
			||||||
    with Image.open("Tests/images/hopper.pnm") as im:
 | 
					    with Image.open("Tests/images/hopper.pnm") as im:
 | 
				
			||||||
        assert_image_similar(im, hopper(), 0.0001)
 | 
					        assert_image_similar(im, hopper(), 0.0001)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            f = self.tempfile("temp.pnm")
 | 
					        f = str(tmp_path / "temp.pnm")
 | 
				
			||||||
        im.save(f)
 | 
					        im.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(f) as reloaded:
 | 
					        with Image.open(f) as reloaded:
 | 
				
			||||||
            assert_image_equal(im, reloaded)
 | 
					            assert_image_equal(im, reloaded)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_truncated_file(self):
 | 
					
 | 
				
			||||||
        path = self.tempfile("temp.pgm")
 | 
					def test_truncated_file(tmp_path):
 | 
				
			||||||
 | 
					    path = str(tmp_path / "temp.pgm")
 | 
				
			||||||
    with open(path, "w") as f:
 | 
					    with open(path, "w") as f:
 | 
				
			||||||
        f.write("P6")
 | 
					        f.write("P6")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        Image.open(path)
 | 
					        Image.open(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_neg_ppm(self):
 | 
					
 | 
				
			||||||
 | 
					def test_neg_ppm():
 | 
				
			||||||
    # Storage.c accepted negative values for xsize, ysize.  the
 | 
					    # Storage.c accepted negative values for xsize, ysize.  the
 | 
				
			||||||
    # internal open_ppm function didn't check for sanity but it
 | 
					    # internal open_ppm function didn't check for sanity but it
 | 
				
			||||||
    # has been removed. The default opener doesn't accept negative
 | 
					    # has been removed. The default opener doesn't accept negative
 | 
				
			||||||
| 
						 | 
					@ -63,8 +67,9 @@ class TestFilePpm(PillowTestCase):
 | 
				
			||||||
    with pytest.raises(IOError):
 | 
					    with pytest.raises(IOError):
 | 
				
			||||||
        Image.open("Tests/images/negative_size.ppm")
 | 
					        Image.open("Tests/images/negative_size.ppm")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_mimetypes(self):
 | 
					
 | 
				
			||||||
        path = self.tempfile("temp.pgm")
 | 
					def test_mimetypes(tmp_path):
 | 
				
			||||||
 | 
					    path = str(tmp_path / "temp.pgm")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with open(path, "w") as f:
 | 
					    with open(path, "w") as f:
 | 
				
			||||||
        f.write("P4\n128 128\n255")
 | 
					        f.write("P4\n128 128\n255")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,10 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image, SgiImagePlugin
 | 
					from PIL import Image, SgiImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper
 | 
					from .helper import assert_image_equal, assert_image_similar, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFileSgi(PillowTestCase):
 | 
					def test_rgb():
 | 
				
			||||||
    def test_rgb(self):
 | 
					 | 
				
			||||||
    # Created with ImageMagick then renamed:
 | 
					    # Created with ImageMagick then renamed:
 | 
				
			||||||
    # convert hopper.ppm -compress None sgi:hopper.rgb
 | 
					    # convert hopper.ppm -compress None sgi:hopper.rgb
 | 
				
			||||||
    test_file = "Tests/images/hopper.rgb"
 | 
					    test_file = "Tests/images/hopper.rgb"
 | 
				
			||||||
| 
						 | 
					@ -14,13 +13,15 @@ class TestFileSgi(PillowTestCase):
 | 
				
			||||||
        assert_image_equal(im, hopper())
 | 
					        assert_image_equal(im, hopper())
 | 
				
			||||||
        assert im.get_format_mimetype() == "image/rgb"
 | 
					        assert im.get_format_mimetype() == "image/rgb"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rgb16(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rgb16():
 | 
				
			||||||
    test_file = "Tests/images/hopper16.rgb"
 | 
					    test_file = "Tests/images/hopper16.rgb"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(test_file) as im:
 | 
					    with Image.open(test_file) as im:
 | 
				
			||||||
        assert_image_equal(im, hopper())
 | 
					        assert_image_equal(im, hopper())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_l(self):
 | 
					
 | 
				
			||||||
 | 
					def test_l():
 | 
				
			||||||
    # Created with ImageMagick
 | 
					    # Created with ImageMagick
 | 
				
			||||||
    # convert hopper.ppm -monochrome -compress None sgi:hopper.bw
 | 
					    # convert hopper.ppm -monochrome -compress None sgi:hopper.bw
 | 
				
			||||||
    test_file = "Tests/images/hopper.bw"
 | 
					    test_file = "Tests/images/hopper.bw"
 | 
				
			||||||
| 
						 | 
					@ -29,7 +30,8 @@ class TestFileSgi(PillowTestCase):
 | 
				
			||||||
        assert_image_similar(im, hopper("L"), 2)
 | 
					        assert_image_similar(im, hopper("L"), 2)
 | 
				
			||||||
        assert im.get_format_mimetype() == "image/sgi"
 | 
					        assert im.get_format_mimetype() == "image/sgi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rgba(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rgba():
 | 
				
			||||||
    # Created with ImageMagick:
 | 
					    # Created with ImageMagick:
 | 
				
			||||||
    # convert transparent.png -compress None transparent.sgi
 | 
					    # convert transparent.png -compress None transparent.sgi
 | 
				
			||||||
    test_file = "Tests/images/transparent.sgi"
 | 
					    test_file = "Tests/images/transparent.sgi"
 | 
				
			||||||
| 
						 | 
					@ -39,7 +41,8 @@ class TestFileSgi(PillowTestCase):
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
        assert im.get_format_mimetype() == "image/sgi"
 | 
					        assert im.get_format_mimetype() == "image/sgi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rle(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rle():
 | 
				
			||||||
    # Created with ImageMagick:
 | 
					    # Created with ImageMagick:
 | 
				
			||||||
    # convert hopper.ppm  hopper.sgi
 | 
					    # convert hopper.ppm  hopper.sgi
 | 
				
			||||||
    test_file = "Tests/images/hopper.sgi"
 | 
					    test_file = "Tests/images/hopper.sgi"
 | 
				
			||||||
| 
						 | 
					@ -48,22 +51,25 @@ class TestFileSgi(PillowTestCase):
 | 
				
			||||||
        with Image.open("Tests/images/hopper.rgb") as target:
 | 
					        with Image.open("Tests/images/hopper.rgb") as target:
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rle16(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rle16():
 | 
				
			||||||
    test_file = "Tests/images/tv16.sgi"
 | 
					    test_file = "Tests/images/tv16.sgi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(test_file) as im:
 | 
					    with Image.open(test_file) as im:
 | 
				
			||||||
        with Image.open("Tests/images/tv.rgb") as target:
 | 
					        with Image.open("Tests/images/tv.rgb") as target:
 | 
				
			||||||
            assert_image_equal(im, target)
 | 
					            assert_image_equal(im, target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_file(self):
 | 
					
 | 
				
			||||||
 | 
					def test_invalid_file():
 | 
				
			||||||
    invalid_file = "Tests/images/flower.jpg"
 | 
					    invalid_file = "Tests/images/flower.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        SgiImagePlugin.SgiImageFile(invalid_file)
 | 
					        SgiImagePlugin.SgiImageFile(invalid_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_write(self):
 | 
					
 | 
				
			||||||
 | 
					def test_write(tmp_path):
 | 
				
			||||||
    def roundtrip(img):
 | 
					    def roundtrip(img):
 | 
				
			||||||
            out = self.tempfile("temp.sgi")
 | 
					        out = str(tmp_path / "temp.sgi")
 | 
				
			||||||
        img.save(out, format="sgi")
 | 
					        img.save(out, format="sgi")
 | 
				
			||||||
        with Image.open(out) as reloaded:
 | 
					        with Image.open(out) as reloaded:
 | 
				
			||||||
            assert_image_equal(img, reloaded)
 | 
					            assert_image_equal(img, reloaded)
 | 
				
			||||||
| 
						 | 
					@ -74,19 +80,21 @@ class TestFileSgi(PillowTestCase):
 | 
				
			||||||
    # Test 1 dimension for an L mode image
 | 
					    # Test 1 dimension for an L mode image
 | 
				
			||||||
    roundtrip(Image.new("L", (10, 1)))
 | 
					    roundtrip(Image.new("L", (10, 1)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_write16(self):
 | 
					
 | 
				
			||||||
 | 
					def test_write16(tmp_path):
 | 
				
			||||||
    test_file = "Tests/images/hopper16.rgb"
 | 
					    test_file = "Tests/images/hopper16.rgb"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(test_file) as im:
 | 
					    with Image.open(test_file) as im:
 | 
				
			||||||
            out = self.tempfile("temp.sgi")
 | 
					        out = str(tmp_path / "temp.sgi")
 | 
				
			||||||
        im.save(out, format="sgi", bpc=2)
 | 
					        im.save(out, format="sgi", bpc=2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open(out) as reloaded:
 | 
					        with Image.open(out) as reloaded:
 | 
				
			||||||
            assert_image_equal(im, reloaded)
 | 
					            assert_image_equal(im, reloaded)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_unsupported_mode(self):
 | 
					
 | 
				
			||||||
 | 
					def test_unsupported_mode(tmp_path):
 | 
				
			||||||
    im = hopper("LA")
 | 
					    im = hopper("LA")
 | 
				
			||||||
        out = self.tempfile("temp.sgi")
 | 
					    out = str(tmp_path / "temp.sgi")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        im.save(out, format="sgi")
 | 
					        im.save(out, format="sgi")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
from io import BytesIO
 | 
					from io import BytesIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
| 
						 | 
					@ -8,7 +7,6 @@ from PIL import Image, TiffImagePlugin
 | 
				
			||||||
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
 | 
					from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import (
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    assert_image_equal,
 | 
					    assert_image_equal,
 | 
				
			||||||
    assert_image_equal_tofile,
 | 
					    assert_image_equal_tofile,
 | 
				
			||||||
    assert_image_similar,
 | 
					    assert_image_similar,
 | 
				
			||||||
| 
						 | 
					@ -21,10 +19,10 @@ from .helper import (
 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFileTiff(PillowTestCase):
 | 
					class TestFileTiff:
 | 
				
			||||||
    def test_sanity(self):
 | 
					    def test_sanity(self, tmp_path):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        filename = self.tempfile("temp.tif")
 | 
					        filename = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        hopper("RGB").save(filename)
 | 
					        hopper("RGB").save(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +52,7 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
        with Image.open(filename):
 | 
					        with Image.open(filename):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_pypy(), "Requires CPython")
 | 
					    @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
 | 
				
			||||||
    def test_unclosed_file(self):
 | 
					    def test_unclosed_file(self):
 | 
				
			||||||
        def open():
 | 
					        def open():
 | 
				
			||||||
            im = Image.open("Tests/images/multipage.tiff")
 | 
					            im = Image.open("Tests/images/multipage.tiff")
 | 
				
			||||||
| 
						 | 
					@ -155,8 +153,8 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
                assert im.tag_v2.get(RESOLUTION_UNIT) == resolutionUnit
 | 
					                assert im.tag_v2.get(RESOLUTION_UNIT) == resolutionUnit
 | 
				
			||||||
                assert im.info["dpi"] == (dpi[1], dpi[1])
 | 
					                assert im.info["dpi"] == (dpi[1], dpi[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_dpi_rounding(self):
 | 
					    def test_save_dpi_rounding(self, tmp_path):
 | 
				
			||||||
        outfile = self.tempfile("temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        with Image.open("Tests/images/hopper.tif") as im:
 | 
					        with Image.open("Tests/images/hopper.tif") as im:
 | 
				
			||||||
            for dpi in (72.2, 72.8):
 | 
					            for dpi in (72.2, 72.8):
 | 
				
			||||||
                im.save(outfile, dpi=(dpi, dpi))
 | 
					                im.save(outfile, dpi=(dpi, dpi))
 | 
				
			||||||
| 
						 | 
					@ -190,14 +188,14 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
            # Should not raise struct.error.
 | 
					            # Should not raise struct.error.
 | 
				
			||||||
            pytest.warns(UserWarning, i._getexif)
 | 
					            pytest.warns(UserWarning, i._getexif)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_rgba(self):
 | 
					    def test_save_rgba(self, tmp_path):
 | 
				
			||||||
        im = hopper("RGBA")
 | 
					        im = hopper("RGBA")
 | 
				
			||||||
        outfile = self.tempfile("temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        im.save(outfile)
 | 
					        im.save(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_save_unsupported_mode(self):
 | 
					    def test_save_unsupported_mode(self, tmp_path):
 | 
				
			||||||
        im = hopper("HSV")
 | 
					        im = hopper("HSV")
 | 
				
			||||||
        outfile = self.tempfile("temp.tif")
 | 
					        outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        with pytest.raises(IOError):
 | 
					        with pytest.raises(IOError):
 | 
				
			||||||
            im.save(outfile)
 | 
					            im.save(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -459,9 +457,9 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
                        assert im2.mode == "L"
 | 
					                        assert im2.mode == "L"
 | 
				
			||||||
                        assert_image_equal(im, im2)
 | 
					                        assert_image_equal(im, im2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_with_underscores(self):
 | 
					    def test_with_underscores(self, tmp_path):
 | 
				
			||||||
        kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
 | 
					        kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
 | 
				
			||||||
        filename = self.tempfile("temp.tif")
 | 
					        filename = str(tmp_path / "temp.tif")
 | 
				
			||||||
        hopper("RGB").save(filename, **kwargs)
 | 
					        hopper("RGB").save(filename, **kwargs)
 | 
				
			||||||
        with Image.open(filename) as im:
 | 
					        with Image.open(filename) as im:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -473,14 +471,14 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
            assert im.tag_v2[X_RESOLUTION] == 72
 | 
					            assert im.tag_v2[X_RESOLUTION] == 72
 | 
				
			||||||
            assert im.tag_v2[Y_RESOLUTION] == 36
 | 
					            assert im.tag_v2[Y_RESOLUTION] == 36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_roundtrip_tiff_uint16(self):
 | 
					    def test_roundtrip_tiff_uint16(self, tmp_path):
 | 
				
			||||||
        # Test an image of all '0' values
 | 
					        # Test an image of all '0' values
 | 
				
			||||||
        pixel_value = 0x1234
 | 
					        pixel_value = 0x1234
 | 
				
			||||||
        infile = "Tests/images/uint16_1_4660.tif"
 | 
					        infile = "Tests/images/uint16_1_4660.tif"
 | 
				
			||||||
        with Image.open(infile) as im:
 | 
					        with Image.open(infile) as im:
 | 
				
			||||||
            assert im.getpixel((0, 0)) == pixel_value
 | 
					            assert im.getpixel((0, 0)) == pixel_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            tmpfile = self.tempfile("temp.tif")
 | 
					            tmpfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
            im.save(tmpfile)
 | 
					            im.save(tmpfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with Image.open(tmpfile) as reloaded:
 | 
					            with Image.open(tmpfile) as reloaded:
 | 
				
			||||||
| 
						 | 
					@ -512,9 +510,9 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
        with Image.open(infile) as im:
 | 
					        with Image.open(infile) as im:
 | 
				
			||||||
            assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
 | 
					            assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_palette(self):
 | 
					    def test_palette(self, tmp_path):
 | 
				
			||||||
        for mode in ["P", "PA"]:
 | 
					        def roundtrip(mode):
 | 
				
			||||||
            outfile = self.tempfile("temp.tif")
 | 
					            outfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            im = hopper(mode)
 | 
					            im = hopper(mode)
 | 
				
			||||||
            im.save(outfile)
 | 
					            im.save(outfile)
 | 
				
			||||||
| 
						 | 
					@ -522,6 +520,9 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
            with Image.open(outfile) as reloaded:
 | 
					            with Image.open(outfile) as reloaded:
 | 
				
			||||||
                assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
 | 
					                assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for mode in ["P", "PA"]:
 | 
				
			||||||
 | 
					            roundtrip(mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_tiff_save_all(self):
 | 
					    def test_tiff_save_all(self):
 | 
				
			||||||
        mp = BytesIO()
 | 
					        mp = BytesIO()
 | 
				
			||||||
        with Image.open("Tests/images/multipage.tiff") as im:
 | 
					        with Image.open("Tests/images/multipage.tiff") as im:
 | 
				
			||||||
| 
						 | 
					@ -552,7 +553,7 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
        with Image.open(mp) as reread:
 | 
					        with Image.open(mp) as reread:
 | 
				
			||||||
            assert reread.n_frames == 3
 | 
					            assert reread.n_frames == 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_saving_icc_profile(self):
 | 
					    def test_saving_icc_profile(self, tmp_path):
 | 
				
			||||||
        # Tests saving TIFF with icc_profile set.
 | 
					        # Tests saving TIFF with icc_profile set.
 | 
				
			||||||
        # At the time of writing this will only work for non-compressed tiffs
 | 
					        # At the time of writing this will only work for non-compressed tiffs
 | 
				
			||||||
        # as libtiff does not support embedded ICC profiles,
 | 
					        # as libtiff does not support embedded ICC profiles,
 | 
				
			||||||
| 
						 | 
					@ -561,14 +562,14 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
        im.info["icc_profile"] = "Dummy value"
 | 
					        im.info["icc_profile"] = "Dummy value"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Try save-load round trip to make sure both handle icc_profile.
 | 
					        # Try save-load round trip to make sure both handle icc_profile.
 | 
				
			||||||
        tmpfile = self.tempfile("temp.tif")
 | 
					        tmpfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
        im.save(tmpfile, "TIFF", compression="raw")
 | 
					        im.save(tmpfile, "TIFF", compression="raw")
 | 
				
			||||||
        with Image.open(tmpfile) as reloaded:
 | 
					        with Image.open(tmpfile) as reloaded:
 | 
				
			||||||
            assert b"Dummy value" == reloaded.info["icc_profile"]
 | 
					            assert b"Dummy value" == reloaded.info["icc_profile"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_close_on_load_exclusive(self):
 | 
					    def test_close_on_load_exclusive(self, tmp_path):
 | 
				
			||||||
        # similar to test_fd_leak, but runs on unixlike os
 | 
					        # similar to test_fd_leak, but runs on unixlike os
 | 
				
			||||||
        tmpfile = self.tempfile("temp.tif")
 | 
					        tmpfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open("Tests/images/uint16_1_4660.tif") as im:
 | 
					        with Image.open("Tests/images/uint16_1_4660.tif") as im:
 | 
				
			||||||
            im.save(tmpfile)
 | 
					            im.save(tmpfile)
 | 
				
			||||||
| 
						 | 
					@ -579,8 +580,8 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert fp.closed
 | 
					        assert fp.closed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_close_on_load_nonexclusive(self):
 | 
					    def test_close_on_load_nonexclusive(self, tmp_path):
 | 
				
			||||||
        tmpfile = self.tempfile("temp.tif")
 | 
					        tmpfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with Image.open("Tests/images/uint16_1_4660.tif") as im:
 | 
					        with Image.open("Tests/images/uint16_1_4660.tif") as im:
 | 
				
			||||||
            im.save(tmpfile)
 | 
					            im.save(tmpfile)
 | 
				
			||||||
| 
						 | 
					@ -601,10 +602,10 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
            Image.open("Tests/images/string_dimension.tiff")
 | 
					            Image.open("Tests/images/string_dimension.tiff")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipUnless(is_win32(), "Windows only")
 | 
					@pytest.mark.skipif(not is_win32(), reason="Windows only")
 | 
				
			||||||
class TestFileTiffW32(PillowTestCase):
 | 
					class TestFileTiffW32:
 | 
				
			||||||
    def test_fd_leak(self):
 | 
					    def test_fd_leak(self, tmp_path):
 | 
				
			||||||
        tmpfile = self.tempfile("temp.tif")
 | 
					        tmpfile = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # this is an mmaped file.
 | 
					        # this is an mmaped file.
 | 
				
			||||||
        with Image.open("Tests/images/uint16_1_4660.tif") as im:
 | 
					        with Image.open("Tests/images/uint16_1_4660.tif") as im:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,13 +5,12 @@ import pytest
 | 
				
			||||||
from PIL import Image, TiffImagePlugin, TiffTags
 | 
					from PIL import Image, TiffImagePlugin, TiffTags
 | 
				
			||||||
from PIL.TiffImagePlugin import IFDRational
 | 
					from PIL.TiffImagePlugin import IFDRational
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_deep_equal, hopper
 | 
					from .helper import assert_deep_equal, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tag_ids = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
 | 
					TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFileTiffMetadata(PillowTestCase):
 | 
					def test_rt_metadata(tmp_path):
 | 
				
			||||||
    def test_rt_metadata(self):
 | 
					 | 
				
			||||||
    """ Test writing arbitrary metadata into the tiff image directory
 | 
					    """ Test writing arbitrary metadata into the tiff image directory
 | 
				
			||||||
        Use case is ImageJ private tags, one numeric, one arbitrary
 | 
					        Use case is ImageJ private tags, one numeric, one arbitrary
 | 
				
			||||||
        data.  https://github.com/python-pillow/Pillow/issues/291
 | 
					        data.  https://github.com/python-pillow/Pillow/issues/291
 | 
				
			||||||
| 
						 | 
					@ -36,20 +35,20 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
    doubledata = 67.89
 | 
					    doubledata = 67.89
 | 
				
			||||||
    info = TiffImagePlugin.ImageFileDirectory()
 | 
					    info = TiffImagePlugin.ImageFileDirectory()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ImageJMetaData = tag_ids["ImageJMetaData"]
 | 
					    ImageJMetaData = TAG_IDS["ImageJMetaData"]
 | 
				
			||||||
        ImageJMetaDataByteCounts = tag_ids["ImageJMetaDataByteCounts"]
 | 
					    ImageJMetaDataByteCounts = TAG_IDS["ImageJMetaDataByteCounts"]
 | 
				
			||||||
        ImageDescription = tag_ids["ImageDescription"]
 | 
					    ImageDescription = TAG_IDS["ImageDescription"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[ImageJMetaDataByteCounts] = len(bindata)
 | 
					    info[ImageJMetaDataByteCounts] = len(bindata)
 | 
				
			||||||
    info[ImageJMetaData] = bindata
 | 
					    info[ImageJMetaData] = bindata
 | 
				
			||||||
        info[tag_ids["RollAngle"]] = floatdata
 | 
					    info[TAG_IDS["RollAngle"]] = floatdata
 | 
				
			||||||
        info.tagtype[tag_ids["RollAngle"]] = 11
 | 
					    info.tagtype[TAG_IDS["RollAngle"]] = 11
 | 
				
			||||||
        info[tag_ids["YawAngle"]] = doubledata
 | 
					    info[TAG_IDS["YawAngle"]] = doubledata
 | 
				
			||||||
        info.tagtype[tag_ids["YawAngle"]] = 12
 | 
					    info.tagtype[TAG_IDS["YawAngle"]] = 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[ImageDescription] = textdata
 | 
					    info[ImageDescription] = textdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f = self.tempfile("temp.tif")
 | 
					    f = str(tmp_path / "temp.tif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    img.save(f, tiffinfo=info)
 | 
					    img.save(f, tiffinfo=info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,9 +63,9 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
        assert loaded.tag[ImageDescription] == (reloaded_textdata,)
 | 
					        assert loaded.tag[ImageDescription] == (reloaded_textdata,)
 | 
				
			||||||
        assert loaded.tag_v2[ImageDescription] == reloaded_textdata
 | 
					        assert loaded.tag_v2[ImageDescription] == reloaded_textdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            loaded_float = loaded.tag[tag_ids["RollAngle"]][0]
 | 
					        loaded_float = loaded.tag[TAG_IDS["RollAngle"]][0]
 | 
				
			||||||
        assert round(abs(loaded_float - floatdata), 5) == 0
 | 
					        assert round(abs(loaded_float - floatdata), 5) == 0
 | 
				
			||||||
            loaded_double = loaded.tag[tag_ids["YawAngle"]][0]
 | 
					        loaded_double = loaded.tag[TAG_IDS["YawAngle"]][0]
 | 
				
			||||||
        assert round(abs(loaded_double - doubledata), 7) == 0
 | 
					        assert round(abs(loaded_double - doubledata), 7) == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # check with 2 element ImageJMetaDataByteCounts, issue #2006
 | 
					    # check with 2 element ImageJMetaDataByteCounts, issue #2006
 | 
				
			||||||
| 
						 | 
					@ -78,7 +77,8 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
        assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
 | 
					        assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
 | 
				
			||||||
        assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
 | 
					        assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_read_metadata(self):
 | 
					
 | 
				
			||||||
 | 
					def test_read_metadata():
 | 
				
			||||||
    with Image.open("Tests/images/hopper_g4.tif") as img:
 | 
					    with Image.open("Tests/images/hopper_g4.tif") as img:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert {
 | 
					        assert {
 | 
				
			||||||
| 
						 | 
					@ -119,10 +119,11 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
            "StripOffsets": (8,),
 | 
					            "StripOffsets": (8,),
 | 
				
			||||||
        } == img.tag.named()
 | 
					        } == img.tag.named()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_write_metadata(self):
 | 
					
 | 
				
			||||||
 | 
					def test_write_metadata(tmp_path):
 | 
				
			||||||
    """ Test metadata writing through the python code """
 | 
					    """ Test metadata writing through the python code """
 | 
				
			||||||
    with Image.open("Tests/images/hopper.tif") as img:
 | 
					    with Image.open("Tests/images/hopper.tif") as img:
 | 
				
			||||||
            f = self.tempfile("temp.tiff")
 | 
					        f = str(tmp_path / "temp.tiff")
 | 
				
			||||||
        img.save(f, tiffinfo=img.tag)
 | 
					        img.save(f, tiffinfo=img.tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        original = img.tag_v2.named()
 | 
					        original = img.tag_v2.named()
 | 
				
			||||||
| 
						 | 
					@ -154,20 +155,23 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
        if tag not in ignored:
 | 
					        if tag not in ignored:
 | 
				
			||||||
            assert value == reloaded[tag], "%s didn't roundtrip" % tag
 | 
					            assert value == reloaded[tag], "%s didn't roundtrip" % tag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_no_duplicate_50741_tag(self):
 | 
					 | 
				
			||||||
        assert tag_ids["MakerNoteSafety"] == 50741
 | 
					 | 
				
			||||||
        assert tag_ids["BestQualityScale"] == 50780
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_empty_metadata(self):
 | 
					def test_no_duplicate_50741_tag():
 | 
				
			||||||
 | 
					    assert TAG_IDS["MakerNoteSafety"] == 50741
 | 
				
			||||||
 | 
					    assert TAG_IDS["BestQualityScale"] == 50780
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_empty_metadata():
 | 
				
			||||||
    f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
 | 
					    f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
 | 
				
			||||||
    head = f.read(8)
 | 
					    head = f.read(8)
 | 
				
			||||||
    info = TiffImagePlugin.ImageFileDirectory(head)
 | 
					    info = TiffImagePlugin.ImageFileDirectory(head)
 | 
				
			||||||
    # Should not raise struct.error.
 | 
					    # Should not raise struct.error.
 | 
				
			||||||
    pytest.warns(UserWarning, info.load, f)
 | 
					    pytest.warns(UserWarning, info.load, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_iccprofile(self):
 | 
					
 | 
				
			||||||
 | 
					def test_iccprofile(tmp_path):
 | 
				
			||||||
    # https://github.com/python-pillow/Pillow/issues/1462
 | 
					    # https://github.com/python-pillow/Pillow/issues/1462
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    with Image.open("Tests/images/hopper.iccprofile.tif") as im:
 | 
					    with Image.open("Tests/images/hopper.iccprofile.tif") as im:
 | 
				
			||||||
        im.save(out)
 | 
					        im.save(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,7 +179,8 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
        assert not isinstance(im.info["icc_profile"], tuple)
 | 
					        assert not isinstance(im.info["icc_profile"], tuple)
 | 
				
			||||||
        assert im.info["icc_profile"] == reloaded.info["icc_profile"]
 | 
					        assert im.info["icc_profile"] == reloaded.info["icc_profile"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_iccprofile_binary(self):
 | 
					
 | 
				
			||||||
 | 
					def test_iccprofile_binary():
 | 
				
			||||||
    # https://github.com/python-pillow/Pillow/issues/1526
 | 
					    # https://github.com/python-pillow/Pillow/issues/1526
 | 
				
			||||||
    # We should be able to load this,
 | 
					    # We should be able to load this,
 | 
				
			||||||
    # but probably won't be able to save it.
 | 
					    # but probably won't be able to save it.
 | 
				
			||||||
| 
						 | 
					@ -184,29 +189,33 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
        assert im.tag_v2.tagtype[34675] == 1
 | 
					        assert im.tag_v2.tagtype[34675] == 1
 | 
				
			||||||
        assert im.info["icc_profile"]
 | 
					        assert im.info["icc_profile"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_iccprofile_save_png(self):
 | 
					
 | 
				
			||||||
 | 
					def test_iccprofile_save_png(tmp_path):
 | 
				
			||||||
    with Image.open("Tests/images/hopper.iccprofile.tif") as im:
 | 
					    with Image.open("Tests/images/hopper.iccprofile.tif") as im:
 | 
				
			||||||
            outfile = self.tempfile("temp.png")
 | 
					        outfile = str(tmp_path / "temp.png")
 | 
				
			||||||
        im.save(outfile)
 | 
					        im.save(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_iccprofile_binary_save_png(self):
 | 
					
 | 
				
			||||||
 | 
					def test_iccprofile_binary_save_png(tmp_path):
 | 
				
			||||||
    with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
 | 
					    with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
 | 
				
			||||||
            outfile = self.tempfile("temp.png")
 | 
					        outfile = str(tmp_path / "temp.png")
 | 
				
			||||||
        im.save(outfile)
 | 
					        im.save(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_exif_div_zero(self):
 | 
					
 | 
				
			||||||
 | 
					def test_exif_div_zero(tmp_path):
 | 
				
			||||||
    im = hopper()
 | 
					    im = hopper()
 | 
				
			||||||
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
					    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
				
			||||||
    info[41988] = TiffImagePlugin.IFDRational(0, 0)
 | 
					    info[41988] = TiffImagePlugin.IFDRational(0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
        assert 0 == reloaded.tag_v2[41988].numerator
 | 
					        assert 0 == reloaded.tag_v2[41988].numerator
 | 
				
			||||||
        assert 0 == reloaded.tag_v2[41988].denominator
 | 
					        assert 0 == reloaded.tag_v2[41988].denominator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_ifd_unsigned_rational(self):
 | 
					
 | 
				
			||||||
 | 
					def test_ifd_unsigned_rational(tmp_path):
 | 
				
			||||||
    im = hopper()
 | 
					    im = hopper()
 | 
				
			||||||
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
					    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -217,7 +226,7 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 | 
					    info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
| 
						 | 
					@ -229,14 +238,15 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 | 
					    info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
        assert max_long == reloaded.tag_v2[41493].numerator
 | 
					        assert max_long == reloaded.tag_v2[41493].numerator
 | 
				
			||||||
        assert 1 == reloaded.tag_v2[41493].denominator
 | 
					        assert 1 == reloaded.tag_v2[41493].denominator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_ifd_signed_rational(self):
 | 
					
 | 
				
			||||||
 | 
					def test_ifd_signed_rational(tmp_path):
 | 
				
			||||||
    im = hopper()
 | 
					    im = hopper()
 | 
				
			||||||
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
					    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -246,7 +256,7 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
					    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
| 
						 | 
					@ -258,7 +268,7 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
					    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
| 
						 | 
					@ -271,26 +281,28 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
					    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
        assert 2 ** 31 - 1 == reloaded.tag_v2[37380].numerator
 | 
					        assert 2 ** 31 - 1 == reloaded.tag_v2[37380].numerator
 | 
				
			||||||
        assert -1 == reloaded.tag_v2[37380].denominator
 | 
					        assert -1 == reloaded.tag_v2[37380].denominator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_ifd_signed_long(self):
 | 
					
 | 
				
			||||||
 | 
					def test_ifd_signed_long(tmp_path):
 | 
				
			||||||
    im = hopper()
 | 
					    im = hopper()
 | 
				
			||||||
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
					    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info[37000] = -60000
 | 
					    info[37000] = -60000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile("temp.tiff")
 | 
					    out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
    im.save(out, tiffinfo=info, compression="raw")
 | 
					    im.save(out, tiffinfo=info, compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
        assert reloaded.tag_v2[37000] == -60000
 | 
					        assert reloaded.tag_v2[37000] == -60000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_empty_values(self):
 | 
					
 | 
				
			||||||
 | 
					def test_empty_values():
 | 
				
			||||||
    data = io.BytesIO(
 | 
					    data = io.BytesIO(
 | 
				
			||||||
        b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
 | 
					        b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
 | 
				
			||||||
        b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 | 
					        b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 | 
				
			||||||
| 
						 | 
					@ -304,17 +316,19 @@ class TestFileTiffMetadata(PillowTestCase):
 | 
				
			||||||
    info = dict(info)
 | 
					    info = dict(info)
 | 
				
			||||||
    assert 33432 in info
 | 
					    assert 33432 in info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_PhotoshopInfo(self):
 | 
					
 | 
				
			||||||
 | 
					def test_PhotoshopInfo(tmp_path):
 | 
				
			||||||
    with Image.open("Tests/images/issue_2278.tif") as im:
 | 
					    with Image.open("Tests/images/issue_2278.tif") as im:
 | 
				
			||||||
        assert len(im.tag_v2[34377]) == 1
 | 
					        assert len(im.tag_v2[34377]) == 1
 | 
				
			||||||
        assert isinstance(im.tag_v2[34377][0], bytes)
 | 
					        assert isinstance(im.tag_v2[34377][0], bytes)
 | 
				
			||||||
            out = self.tempfile("temp.tiff")
 | 
					        out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
        im.save(out)
 | 
					        im.save(out)
 | 
				
			||||||
    with Image.open(out) as reloaded:
 | 
					    with Image.open(out) as reloaded:
 | 
				
			||||||
        assert len(reloaded.tag_v2[34377]) == 1
 | 
					        assert len(reloaded.tag_v2[34377]) == 1
 | 
				
			||||||
        assert isinstance(reloaded.tag_v2[34377][0], bytes)
 | 
					        assert isinstance(reloaded.tag_v2[34377][0], bytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_too_many_entries(self):
 | 
					
 | 
				
			||||||
 | 
					def test_too_many_entries():
 | 
				
			||||||
    ifd = TiffImagePlugin.ImageFileDirectory_v2()
 | 
					    ifd = TiffImagePlugin.ImageFileDirectory_v2()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #    277: ("SamplesPerPixel", SHORT, 1),
 | 
					    #    277: ("SamplesPerPixel", SHORT, 1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,24 +3,27 @@ import itertools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_similar, hopper
 | 
					from .helper import assert_image_similar, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFormatHSV(PillowTestCase):
 | 
					def int_to_float(i):
 | 
				
			||||||
    def int_to_float(self, i):
 | 
					 | 
				
			||||||
    return i / 255
 | 
					    return i / 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def str_to_float(self, i):
 | 
					
 | 
				
			||||||
 | 
					def str_to_float(i):
 | 
				
			||||||
    return ord(i) / 255
 | 
					    return ord(i) / 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tuple_to_ints(self, tp):
 | 
					
 | 
				
			||||||
 | 
					def tuple_to_ints(tp):
 | 
				
			||||||
    x, y, z = tp
 | 
					    x, y, z = tp
 | 
				
			||||||
    return int(x * 255.0), int(y * 255.0), int(z * 255.0)
 | 
					    return int(x * 255.0), int(y * 255.0), int(z * 255.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sanity(self):
 | 
					
 | 
				
			||||||
 | 
					def test_sanity():
 | 
				
			||||||
    Image.new("HSV", (100, 100))
 | 
					    Image.new("HSV", (100, 100))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def wedge(self):
 | 
					
 | 
				
			||||||
 | 
					def wedge():
 | 
				
			||||||
    w = Image._wedge()
 | 
					    w = Image._wedge()
 | 
				
			||||||
    w90 = w.rotate(90)
 | 
					    w90 = w.rotate(90)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,18 +46,17 @@ class TestFormatHSV(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return img
 | 
					    return img
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def to_xxx_colorsys(self, im, func, mode):
 | 
					
 | 
				
			||||||
 | 
					def to_xxx_colorsys(im, func, mode):
 | 
				
			||||||
    # convert the hard way using the library colorsys routines.
 | 
					    # convert the hard way using the library colorsys routines.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    (r, g, b) = im.split()
 | 
					    (r, g, b) = im.split()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        conv_func = self.int_to_float
 | 
					    conv_func = int_to_float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    converted = [
 | 
					    converted = [
 | 
				
			||||||
            self.tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
 | 
					        tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
 | 
				
			||||||
            for (_r, _g, _b) in itertools.zip_longest(
 | 
					        for (_r, _g, _b) in itertools.zip_longest(r.tobytes(), g.tobytes(), b.tobytes())
 | 
				
			||||||
                r.tobytes(), g.tobytes(), b.tobytes()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_bytes = b"".join(
 | 
					    new_bytes = b"".join(
 | 
				
			||||||
| 
						 | 
					@ -65,25 +67,25 @@ class TestFormatHSV(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return hsv
 | 
					    return hsv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def to_hsv_colorsys(self, im):
 | 
					 | 
				
			||||||
        return self.to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def to_rgb_colorsys(self, im):
 | 
					def to_hsv_colorsys(im):
 | 
				
			||||||
        return self.to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
 | 
					    return to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_wedge(self):
 | 
					
 | 
				
			||||||
        src = self.wedge().resize((3 * 32, 32), Image.BILINEAR)
 | 
					def to_rgb_colorsys(im):
 | 
				
			||||||
 | 
					    return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_wedge():
 | 
				
			||||||
 | 
					    src = wedge().resize((3 * 32, 32), Image.BILINEAR)
 | 
				
			||||||
    im = src.convert("HSV")
 | 
					    im = src.convert("HSV")
 | 
				
			||||||
        comparable = self.to_hsv_colorsys(src)
 | 
					    comparable = to_hsv_colorsys(src)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
        im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
 | 
					        im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
            im.getchannel(1),
 | 
					        im.getchannel(1), comparable.getchannel(1), 1, "Saturation conversion is wrong",
 | 
				
			||||||
            comparable.getchannel(1),
 | 
					 | 
				
			||||||
            1,
 | 
					 | 
				
			||||||
            "Saturation conversion is wrong",
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
        im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
 | 
					        im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
 | 
				
			||||||
| 
						 | 
					@ -102,43 +104,33 @@ class TestFormatHSV(PillowTestCase):
 | 
				
			||||||
        im.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong"
 | 
					        im.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_convert(self):
 | 
					
 | 
				
			||||||
 | 
					def test_convert():
 | 
				
			||||||
    im = hopper("RGB").convert("HSV")
 | 
					    im = hopper("RGB").convert("HSV")
 | 
				
			||||||
        comparable = self.to_hsv_colorsys(hopper("RGB"))
 | 
					    comparable = to_hsv_colorsys(hopper("RGB"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
        im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
 | 
					        im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
            im.getchannel(1),
 | 
					        im.getchannel(1), comparable.getchannel(1), 1, "Saturation conversion is wrong",
 | 
				
			||||||
            comparable.getchannel(1),
 | 
					 | 
				
			||||||
            1,
 | 
					 | 
				
			||||||
            "Saturation conversion is wrong",
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
        im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
 | 
					        im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_hsv_to_rgb(self):
 | 
					
 | 
				
			||||||
        comparable = self.to_hsv_colorsys(hopper("RGB"))
 | 
					def test_hsv_to_rgb():
 | 
				
			||||||
 | 
					    comparable = to_hsv_colorsys(hopper("RGB"))
 | 
				
			||||||
    converted = comparable.convert("RGB")
 | 
					    converted = comparable.convert("RGB")
 | 
				
			||||||
        comparable = self.to_rgb_colorsys(comparable)
 | 
					    comparable = to_rgb_colorsys(comparable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
            converted.getchannel(0),
 | 
					        converted.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong",
 | 
				
			||||||
            comparable.getchannel(0),
 | 
					 | 
				
			||||||
            3,
 | 
					 | 
				
			||||||
            "R conversion is wrong",
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
            converted.getchannel(1),
 | 
					        converted.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong",
 | 
				
			||||||
            comparable.getchannel(1),
 | 
					 | 
				
			||||||
            3,
 | 
					 | 
				
			||||||
            "G conversion is wrong",
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    assert_image_similar(
 | 
					    assert_image_similar(
 | 
				
			||||||
            converted.getchannel(2),
 | 
					        converted.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong",
 | 
				
			||||||
            comparable.getchannel(2),
 | 
					 | 
				
			||||||
            3,
 | 
					 | 
				
			||||||
            "B conversion is wrong",
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,13 +2,12 @@ import ctypes
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
from distutils import ccompiler, sysconfig
 | 
					from distutils import ccompiler, sysconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, hopper, is_win32, on_ci
 | 
					from .helper import assert_image_equal, hopper, is_win32, on_ci
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
 | 
					# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
 | 
				
			||||||
# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
 | 
					# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
 | 
				
			||||||
| 
						 | 
					@ -22,17 +21,17 @@ else:
 | 
				
			||||||
        cffi = None
 | 
					        cffi = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccessTest(PillowTestCase):
 | 
					class AccessTest:
 | 
				
			||||||
    # initial value
 | 
					    # initial value
 | 
				
			||||||
    _init_cffi_access = Image.USE_CFFI_ACCESS
 | 
					    _init_cffi_access = Image.USE_CFFI_ACCESS
 | 
				
			||||||
    _need_cffi_access = False
 | 
					    _need_cffi_access = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def setUpClass(cls):
 | 
					    def setup_class(cls):
 | 
				
			||||||
        Image.USE_CFFI_ACCESS = cls._need_cffi_access
 | 
					        Image.USE_CFFI_ACCESS = cls._need_cffi_access
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def tearDownClass(cls):
 | 
					    def teardown_class(cls):
 | 
				
			||||||
        Image.USE_CFFI_ACCESS = cls._init_cffi_access
 | 
					        Image.USE_CFFI_ACCESS = cls._init_cffi_access
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,17 +199,17 @@ class TestImageGetPixel(AccessTest):
 | 
				
			||||||
            assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
 | 
					            assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipIf(cffi is None, "No cffi")
 | 
					@pytest.mark.skipif(cffi is None, reason="No CFFI")
 | 
				
			||||||
class TestCffiPutPixel(TestImagePutPixel):
 | 
					class TestCffiPutPixel(TestImagePutPixel):
 | 
				
			||||||
    _need_cffi_access = True
 | 
					    _need_cffi_access = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipIf(cffi is None, "No cffi")
 | 
					@pytest.mark.skipif(cffi is None, reason="No CFFI")
 | 
				
			||||||
class TestCffiGetPixel(TestImageGetPixel):
 | 
					class TestCffiGetPixel(TestImageGetPixel):
 | 
				
			||||||
    _need_cffi_access = True
 | 
					    _need_cffi_access = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipIf(cffi is None, "No cffi")
 | 
					@pytest.mark.skipif(cffi is None, reason="No CFFI")
 | 
				
			||||||
class TestCffi(AccessTest):
 | 
					class TestCffi(AccessTest):
 | 
				
			||||||
    _need_cffi_access = True
 | 
					    _need_cffi_access = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,10 +325,11 @@ class TestCffi(AccessTest):
 | 
				
			||||||
            assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
 | 
					            assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestEmbeddable(unittest.TestCase):
 | 
					class TestEmbeddable:
 | 
				
			||||||
    @unittest.skipIf(
 | 
					    @pytest.mark.skipif(
 | 
				
			||||||
        not is_win32() or on_ci(),
 | 
					        not is_win32() or on_ci(),
 | 
				
			||||||
        "Failing on AppVeyor / GitHub Actions when run from subprocess, not from shell",
 | 
					        reason="Failing on AppVeyor / GitHub Actions when run from subprocess, "
 | 
				
			||||||
 | 
					        "not from shell",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    def test_embeddable(self):
 | 
					    def test_embeddable(self):
 | 
				
			||||||
        with open("embed_pil.c", "w") as fh:
 | 
					        with open("embed_pil.c", "w") as fh:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,10 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import assert_image, assert_image_equal, assert_image_similar, hopper
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    assert_image,
 | 
					 | 
				
			||||||
    assert_image_equal,
 | 
					 | 
				
			||||||
    assert_image_similar,
 | 
					 | 
				
			||||||
    hopper,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestImageConvert(PillowTestCase):
 | 
					def test_sanity():
 | 
				
			||||||
    def test_sanity(self):
 | 
					 | 
				
			||||||
    def convert(im, mode):
 | 
					    def convert(im, mode):
 | 
				
			||||||
        out = im.convert(mode)
 | 
					        out = im.convert(mode)
 | 
				
			||||||
        assert out.mode == mode
 | 
					        assert out.mode == mode
 | 
				
			||||||
| 
						 | 
					@ -43,7 +36,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
        for mode in modes:
 | 
					        for mode in modes:
 | 
				
			||||||
            convert(im, mode)
 | 
					            convert(im, mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_default(self):
 | 
					
 | 
				
			||||||
 | 
					def test_default():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = hopper("P")
 | 
					    im = hopper("P")
 | 
				
			||||||
    assert_image(im, "P", im.size)
 | 
					    assert_image(im, "P", im.size)
 | 
				
			||||||
| 
						 | 
					@ -52,26 +46,32 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    im = im.convert()
 | 
					    im = im.convert()
 | 
				
			||||||
    assert_image(im, "RGB", im.size)
 | 
					    assert_image(im, "RGB", im.size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ref https://github.com/python-pillow/Pillow/issues/274
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _test_float_conversion(self, im):
 | 
					# ref https://github.com/python-pillow/Pillow/issues/274
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _test_float_conversion(im):
 | 
				
			||||||
    orig = im.getpixel((5, 5))
 | 
					    orig = im.getpixel((5, 5))
 | 
				
			||||||
    converted = im.convert("F").getpixel((5, 5))
 | 
					    converted = im.convert("F").getpixel((5, 5))
 | 
				
			||||||
    assert orig == converted
 | 
					    assert orig == converted
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_8bit(self):
 | 
					
 | 
				
			||||||
 | 
					def test_8bit():
 | 
				
			||||||
    with Image.open("Tests/images/hopper.jpg") as im:
 | 
					    with Image.open("Tests/images/hopper.jpg") as im:
 | 
				
			||||||
            self._test_float_conversion(im.convert("L"))
 | 
					        _test_float_conversion(im.convert("L"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.tif") as im:
 | 
					    with Image.open("Tests/images/16bit.cropped.tif") as im:
 | 
				
			||||||
            self._test_float_conversion(im)
 | 
					        _test_float_conversion(im)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_16bit_workaround(self):
 | 
					
 | 
				
			||||||
 | 
					def test_16bit_workaround():
 | 
				
			||||||
    with Image.open("Tests/images/16bit.cropped.tif") as im:
 | 
					    with Image.open("Tests/images/16bit.cropped.tif") as im:
 | 
				
			||||||
            self._test_float_conversion(im.convert("I"))
 | 
					        _test_float_conversion(im.convert("I"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rgba_p(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rgba_p():
 | 
				
			||||||
    im = hopper("RGBA")
 | 
					    im = hopper("RGBA")
 | 
				
			||||||
    im.putalpha(hopper("L"))
 | 
					    im.putalpha(hopper("L"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,11 +80,12 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_image_similar(im, comparable, 20)
 | 
					    assert_image_similar(im, comparable, 20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_trns_p(self):
 | 
					
 | 
				
			||||||
 | 
					def test_trns_p(tmp_path):
 | 
				
			||||||
    im = hopper("P")
 | 
					    im = hopper("P")
 | 
				
			||||||
    im.info["transparency"] = 0
 | 
					    im.info["transparency"] = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f = self.tempfile("temp.png")
 | 
					    f = str(tmp_path / "temp.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im_l = im.convert("L")
 | 
					    im_l = im.convert("L")
 | 
				
			||||||
    assert im_l.info["transparency"] == 0  # undone
 | 
					    assert im_l.info["transparency"] == 0  # undone
 | 
				
			||||||
| 
						 | 
					@ -94,9 +95,11 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    assert im_rgb.info["transparency"] == (0, 0, 0)  # undone
 | 
					    assert im_rgb.info["transparency"] == (0, 0, 0)  # undone
 | 
				
			||||||
    im_rgb.save(f)
 | 
					    im_rgb.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ref https://github.com/python-pillow/Pillow/issues/664
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_trns_p_rgba(self):
 | 
					# ref https://github.com/python-pillow/Pillow/issues/664
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_trns_p_rgba():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    im = hopper("P")
 | 
					    im = hopper("P")
 | 
				
			||||||
    im.info["transparency"] = 128
 | 
					    im.info["transparency"] = 128
 | 
				
			||||||
| 
						 | 
					@ -109,11 +112,12 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    # https://github.com/python-pillow/Pillow/issues/2702
 | 
					    # https://github.com/python-pillow/Pillow/issues/2702
 | 
				
			||||||
    assert im_rgba.palette is None
 | 
					    assert im_rgba.palette is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_trns_l(self):
 | 
					
 | 
				
			||||||
 | 
					def test_trns_l(tmp_path):
 | 
				
			||||||
    im = hopper("L")
 | 
					    im = hopper("L")
 | 
				
			||||||
    im.info["transparency"] = 128
 | 
					    im.info["transparency"] = 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f = self.tempfile("temp.png")
 | 
					    f = str(tmp_path / "temp.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im_rgb = im.convert("RGB")
 | 
					    im_rgb = im.convert("RGB")
 | 
				
			||||||
    assert im_rgb.info["transparency"] == (128, 128, 128)  # undone
 | 
					    assert im_rgb.info["transparency"] == (128, 128, 128)  # undone
 | 
				
			||||||
| 
						 | 
					@ -127,11 +131,12 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    assert "transparency" not in im_p.info
 | 
					    assert "transparency" not in im_p.info
 | 
				
			||||||
    im_p.save(f)
 | 
					    im_p.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_trns_RGB(self):
 | 
					
 | 
				
			||||||
 | 
					def test_trns_RGB(tmp_path):
 | 
				
			||||||
    im = hopper("RGB")
 | 
					    im = hopper("RGB")
 | 
				
			||||||
    im.info["transparency"] = im.getpixel((0, 0))
 | 
					    im.info["transparency"] = im.getpixel((0, 0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f = self.tempfile("temp.png")
 | 
					    f = str(tmp_path / "temp.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im_l = im.convert("L")
 | 
					    im_l = im.convert("L")
 | 
				
			||||||
    assert im_l.info["transparency"] == im_l.getpixel((0, 0))  # undone
 | 
					    assert im_l.info["transparency"] == im_l.getpixel((0, 0))  # undone
 | 
				
			||||||
| 
						 | 
					@ -149,7 +154,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    assert "transparency" not in im_p.info
 | 
					    assert "transparency" not in im_p.info
 | 
				
			||||||
    im_p.save(f)
 | 
					    im_p.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_gif_with_rgba_palette_to_p(self):
 | 
					
 | 
				
			||||||
 | 
					def test_gif_with_rgba_palette_to_p():
 | 
				
			||||||
    # See https://github.com/python-pillow/Pillow/issues/2433
 | 
					    # See https://github.com/python-pillow/Pillow/issues/2433
 | 
				
			||||||
    with Image.open("Tests/images/hopper.gif") as im:
 | 
					    with Image.open("Tests/images/hopper.gif") as im:
 | 
				
			||||||
        im.info["transparency"] = 255
 | 
					        im.info["transparency"] = 255
 | 
				
			||||||
| 
						 | 
					@ -160,7 +166,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    # Should not raise ValueError: unrecognized raw mode
 | 
					    # Should not raise ValueError: unrecognized raw mode
 | 
				
			||||||
    im_p.load()
 | 
					    im_p.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_p_la(self):
 | 
					
 | 
				
			||||||
 | 
					def test_p_la():
 | 
				
			||||||
    im = hopper("RGBA")
 | 
					    im = hopper("RGBA")
 | 
				
			||||||
    alpha = hopper("L")
 | 
					    alpha = hopper("L")
 | 
				
			||||||
    im.putalpha(alpha)
 | 
					    im.putalpha(alpha)
 | 
				
			||||||
| 
						 | 
					@ -169,7 +176,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert_image_similar(alpha, comparable, 5)
 | 
					    assert_image_similar(alpha, comparable, 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_matrix_illegal_conversion(self):
 | 
					
 | 
				
			||||||
 | 
					def test_matrix_illegal_conversion():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    im = hopper("CMYK")
 | 
					    im = hopper("CMYK")
 | 
				
			||||||
    # fmt: off
 | 
					    # fmt: off
 | 
				
			||||||
| 
						 | 
					@ -184,7 +192,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        im.convert(mode="CMYK", matrix=matrix)
 | 
					        im.convert(mode="CMYK", matrix=matrix)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_matrix_wrong_mode(self):
 | 
					
 | 
				
			||||||
 | 
					def test_matrix_wrong_mode():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    im = hopper("L")
 | 
					    im = hopper("L")
 | 
				
			||||||
    # fmt: off
 | 
					    # fmt: off
 | 
				
			||||||
| 
						 | 
					@ -199,7 +208,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        im.convert(mode="L", matrix=matrix)
 | 
					        im.convert(mode="L", matrix=matrix)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_matrix_xyz(self):
 | 
					
 | 
				
			||||||
 | 
					def test_matrix_xyz():
 | 
				
			||||||
    def matrix_convert(mode):
 | 
					    def matrix_convert(mode):
 | 
				
			||||||
        # Arrange
 | 
					        # Arrange
 | 
				
			||||||
        im = hopper("RGB")
 | 
					        im = hopper("RGB")
 | 
				
			||||||
| 
						 | 
					@ -230,7 +240,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
    matrix_convert("RGB")
 | 
					    matrix_convert("RGB")
 | 
				
			||||||
    matrix_convert("L")
 | 
					    matrix_convert("L")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_matrix_identity(self):
 | 
					
 | 
				
			||||||
 | 
					def test_matrix_identity():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    im = hopper("RGB")
 | 
					    im = hopper("RGB")
 | 
				
			||||||
    # fmt: off
 | 
					    # fmt: off
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,29 +10,32 @@ def test_sanity():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_bbox():
 | 
					def test_bbox():
 | 
				
			||||||
 | 
					    def check(im, fill_color):
 | 
				
			||||||
 | 
					        assert im.getbbox() is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        im.paste(fill_color, (10, 25, 90, 75))
 | 
				
			||||||
 | 
					        assert im.getbbox() == (10, 25, 90, 75)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        im.paste(fill_color, (25, 10, 75, 90))
 | 
				
			||||||
 | 
					        assert im.getbbox() == (10, 10, 90, 90)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        im.paste(fill_color, (-10, -10, 110, 110))
 | 
				
			||||||
 | 
					        assert im.getbbox() == (0, 0, 100, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 8-bit mode
 | 
					    # 8-bit mode
 | 
				
			||||||
    im = Image.new("L", (100, 100), 0)
 | 
					    im = Image.new("L", (100, 100), 0)
 | 
				
			||||||
    assert im.getbbox() is None
 | 
					    check(im, 255)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    im.paste(255, (10, 25, 90, 75))
 | 
					 | 
				
			||||||
    assert im.getbbox() == (10, 25, 90, 75)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    im.paste(255, (25, 10, 75, 90))
 | 
					 | 
				
			||||||
    assert im.getbbox() == (10, 10, 90, 90)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    im.paste(255, (-10, -10, 110, 110))
 | 
					 | 
				
			||||||
    assert im.getbbox() == (0, 0, 100, 100)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 32-bit mode
 | 
					    # 32-bit mode
 | 
				
			||||||
    im = Image.new("RGB", (100, 100), 0)
 | 
					    im = Image.new("RGB", (100, 100), 0)
 | 
				
			||||||
    assert im.getbbox() is None
 | 
					    check(im, 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im.paste(255, (10, 25, 90, 75))
 | 
					    for mode in ("RGBA", "RGBa"):
 | 
				
			||||||
    assert im.getbbox() == (10, 25, 90, 75)
 | 
					        for color in ((0, 0, 0, 0), (127, 127, 127, 0), (255, 255, 255, 0)):
 | 
				
			||||||
 | 
					            im = Image.new(mode, (100, 100), color)
 | 
				
			||||||
 | 
					            check(im, (255, 255, 255, 255))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im.paste(255, (25, 10, 75, 90))
 | 
					    for mode in ("La", "LA", "PA"):
 | 
				
			||||||
    assert im.getbbox() == (10, 10, 90, 90)
 | 
					        for color in ((0, 0), (127, 0), (255, 0)):
 | 
				
			||||||
 | 
					            im = Image.new(mode, (100, 100), color)
 | 
				
			||||||
    im.paste(255, (-10, -10, 110, 110))
 | 
					            check(im, (255, 255))
 | 
				
			||||||
    assert im.getbbox() == (0, 0, 100, 100)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,9 @@
 | 
				
			||||||
from PIL import Image, features
 | 
					from PIL import Image, features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, hopper
 | 
					from .helper import assert_image_equal, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestImageSplit(PillowTestCase):
 | 
					def test_split():
 | 
				
			||||||
    def test_split(self):
 | 
					 | 
				
			||||||
    def split(mode):
 | 
					    def split(mode):
 | 
				
			||||||
        layers = hopper(mode).split()
 | 
					        layers = hopper(mode).split()
 | 
				
			||||||
        return [(i.mode, i.size[0], i.size[1]) for i in layers]
 | 
					        return [(i.mode, i.size[0], i.size[1]) for i in layers]
 | 
				
			||||||
| 
						 | 
					@ -29,7 +28,8 @@ class TestImageSplit(PillowTestCase):
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    assert split("YCbCr") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)]
 | 
					    assert split("YCbCr") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_split_merge(self):
 | 
					
 | 
				
			||||||
 | 
					def test_split_merge():
 | 
				
			||||||
    def split_merge(mode):
 | 
					    def split_merge(mode):
 | 
				
			||||||
        return Image.merge(mode, hopper(mode).split())
 | 
					        return Image.merge(mode, hopper(mode).split())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,11 +43,12 @@ class TestImageSplit(PillowTestCase):
 | 
				
			||||||
    assert_image_equal(hopper("CMYK"), split_merge("CMYK"))
 | 
					    assert_image_equal(hopper("CMYK"), split_merge("CMYK"))
 | 
				
			||||||
    assert_image_equal(hopper("YCbCr"), split_merge("YCbCr"))
 | 
					    assert_image_equal(hopper("YCbCr"), split_merge("YCbCr"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_split_open(self):
 | 
					
 | 
				
			||||||
 | 
					def test_split_open(tmp_path):
 | 
				
			||||||
    if features.check("zlib"):
 | 
					    if features.check("zlib"):
 | 
				
			||||||
            test_file = self.tempfile("temp.png")
 | 
					        test_file = str(tmp_path / "temp.png")
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
            test_file = self.tempfile("temp.pcx")
 | 
					        test_file = str(tmp_path / "temp.pcx")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def split_open(mode):
 | 
					    def split_open(mode):
 | 
				
			||||||
        hopper(mode).save(test_file)
 | 
					        hopper(mode).save(test_file)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,9 +38,9 @@ def test_aspect():
 | 
				
			||||||
    im.thumbnail((100, 50))
 | 
					    im.thumbnail((100, 50))
 | 
				
			||||||
    assert im.size == (100, 50)
 | 
					    assert im.size == (100, 50)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = Image.new("L", (128, 128))
 | 
					    im = Image.new("L", (64, 64))
 | 
				
			||||||
    im.thumbnail((100, 100))
 | 
					    im.thumbnail((100, 100))
 | 
				
			||||||
    assert im.size == (100, 100)
 | 
					    assert im.size == (64, 64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = Image.new("L", (256, 162))  # ratio is 1.5802469136
 | 
					    im = Image.new("L", (256, 162))  # ratio is 1.5802469136
 | 
				
			||||||
    im.thumbnail((33, 33))
 | 
					    im.thumbnail((33, 33))
 | 
				
			||||||
| 
						 | 
					@ -50,11 +50,23 @@ def test_aspect():
 | 
				
			||||||
    im.thumbnail((33, 33))
 | 
					    im.thumbnail((33, 33))
 | 
				
			||||||
    assert im.size == (21, 33)  # ratio is 0.6363636364
 | 
					    assert im.size == (21, 33)  # ratio is 0.6363636364
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    im = Image.new("L", (145, 100))  # ratio is 1.45
 | 
				
			||||||
 | 
					    im.thumbnail((50, 50))
 | 
				
			||||||
 | 
					    assert im.size == (50, 34)  # ratio is 1.47058823529
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    im = Image.new("L", (100, 145))  # ratio is 0.689655172414
 | 
				
			||||||
 | 
					    im.thumbnail((50, 50))
 | 
				
			||||||
 | 
					    assert im.size == (34, 50)  # ratio is 0.68
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    im = Image.new("L", (100, 30))  # ratio is 3.333333333333
 | 
				
			||||||
 | 
					    im.thumbnail((75, 75))
 | 
				
			||||||
 | 
					    assert im.size == (75, 23)  # ratio is 3.260869565217
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_float():
 | 
					def test_float():
 | 
				
			||||||
    im = Image.new("L", (128, 128))
 | 
					    im = Image.new("L", (128, 128))
 | 
				
			||||||
    im.thumbnail((99.9, 99.9))
 | 
					    im.thumbnail((99.9, 99.9))
 | 
				
			||||||
    assert im.size == (100, 100)
 | 
					    assert im.size == (99, 99)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_no_resize():
 | 
					def test_no_resize():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -944,6 +944,22 @@ def test_stroke():
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@skip_unless_feature("freetype2")
 | 
				
			||||||
 | 
					def test_stroke_descender():
 | 
				
			||||||
 | 
					    # Arrange
 | 
				
			||||||
 | 
					    im = Image.new("RGB", (120, 130))
 | 
				
			||||||
 | 
					    draw = ImageDraw.Draw(im)
 | 
				
			||||||
 | 
					    font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Act
 | 
				
			||||||
 | 
					    draw.text((10, 0), "y", "#f00", font, stroke_width=2, stroke_fill="#0f0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Assert
 | 
				
			||||||
 | 
					    assert_image_similar(
 | 
				
			||||||
 | 
					        im, Image.open("Tests/images/imagedraw_stroke_descender.png"), 6.76
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@skip_unless_feature("freetype2")
 | 
					@skip_unless_feature("freetype2")
 | 
				
			||||||
def test_stroke_multiline():
 | 
					def test_stroke_multiline():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,17 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image, ImagePalette
 | 
					from PIL import Image, ImagePalette
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal
 | 
					from .helper import assert_image_equal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestImagePalette(PillowTestCase):
 | 
					def test_sanity():
 | 
				
			||||||
    def test_sanity(self):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
 | 
					    ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        ImagePalette.ImagePalette("RGB", list(range(256)) * 2)
 | 
					        ImagePalette.ImagePalette("RGB", list(range(256)) * 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_getcolor(self):
 | 
					
 | 
				
			||||||
 | 
					def test_getcolor():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    palette = ImagePalette.ImagePalette()
 | 
					    palette = ImagePalette.ImagePalette()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,11 +27,12 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        palette.getcolor("unknown")
 | 
					        palette.getcolor("unknown")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_file(self):
 | 
					
 | 
				
			||||||
 | 
					def test_file(tmp_path):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
 | 
					    palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f = self.tempfile("temp.lut")
 | 
					    f = str(tmp_path / "temp.lut")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    palette.save(f)
 | 
					    palette.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +46,8 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    assert isinstance(p, ImagePalette.ImagePalette)
 | 
					    assert isinstance(p, ImagePalette.ImagePalette)
 | 
				
			||||||
    assert p.palette == palette.tobytes()
 | 
					    assert p.palette == palette.tobytes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_make_linear_lut(self):
 | 
					
 | 
				
			||||||
 | 
					def test_make_linear_lut():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    black = 0
 | 
					    black = 0
 | 
				
			||||||
    white = 255
 | 
					    white = 255
 | 
				
			||||||
| 
						 | 
					@ -60,7 +62,8 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    for i in range(0, len(lut)):
 | 
					    for i in range(0, len(lut)):
 | 
				
			||||||
        assert lut[i] == i
 | 
					        assert lut[i] == i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_make_linear_lut_not_yet_implemented(self):
 | 
					
 | 
				
			||||||
 | 
					def test_make_linear_lut_not_yet_implemented():
 | 
				
			||||||
    # Update after FIXME
 | 
					    # Update after FIXME
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    black = 1
 | 
					    black = 1
 | 
				
			||||||
| 
						 | 
					@ -70,7 +73,8 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    with pytest.raises(NotImplementedError):
 | 
					    with pytest.raises(NotImplementedError):
 | 
				
			||||||
        ImagePalette.make_linear_lut(black, white)
 | 
					        ImagePalette.make_linear_lut(black, white)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_make_gamma_lut(self):
 | 
					
 | 
				
			||||||
 | 
					def test_make_gamma_lut():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    exp = 5
 | 
					    exp = 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,7 +91,8 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    assert lut[191] == 60
 | 
					    assert lut[191] == 60
 | 
				
			||||||
    assert lut[255] == 255
 | 
					    assert lut[255] == 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rawmode_valueerrors(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rawmode_valueerrors(tmp_path):
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    palette = ImagePalette.raw("RGB", list(range(256)) * 3)
 | 
					    palette = ImagePalette.raw("RGB", list(range(256)) * 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,11 +101,12 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
        palette.tobytes()
 | 
					        palette.tobytes()
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        palette.getcolor((1, 2, 3))
 | 
					        palette.getcolor((1, 2, 3))
 | 
				
			||||||
        f = self.tempfile("temp.lut")
 | 
					    f = str(tmp_path / "temp.lut")
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        palette.save(f)
 | 
					        palette.save(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_getdata(self):
 | 
					
 | 
				
			||||||
 | 
					def test_getdata():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    data_in = list(range(256)) * 3
 | 
					    data_in = list(range(256)) * 3
 | 
				
			||||||
    palette = ImagePalette.ImagePalette("RGB", data_in)
 | 
					    palette = ImagePalette.ImagePalette("RGB", data_in)
 | 
				
			||||||
| 
						 | 
					@ -111,7 +117,8 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    # Assert
 | 
					    # Assert
 | 
				
			||||||
    assert mode == "RGB;L"
 | 
					    assert mode == "RGB;L"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rawmode_getdata(self):
 | 
					
 | 
				
			||||||
 | 
					def test_rawmode_getdata():
 | 
				
			||||||
    # Arrange
 | 
					    # Arrange
 | 
				
			||||||
    data_in = list(range(256)) * 3
 | 
					    data_in = list(range(256)) * 3
 | 
				
			||||||
    palette = ImagePalette.raw("RGB", data_in)
 | 
					    palette = ImagePalette.raw("RGB", data_in)
 | 
				
			||||||
| 
						 | 
					@ -123,9 +130,10 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    assert rawmode == "RGB"
 | 
					    assert rawmode == "RGB"
 | 
				
			||||||
    assert data_in == data_out
 | 
					    assert data_in == data_out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_2bit_palette(self):
 | 
					
 | 
				
			||||||
 | 
					def test_2bit_palette(tmp_path):
 | 
				
			||||||
    # issue #2258, 2 bit palettes are corrupted.
 | 
					    # issue #2258, 2 bit palettes are corrupted.
 | 
				
			||||||
        outfile = self.tempfile("temp.png")
 | 
					    outfile = str(tmp_path / "temp.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rgb = b"\x00" * 2 + b"\x01" * 2 + b"\x02" * 2
 | 
					    rgb = b"\x00" * 2 + b"\x01" * 2 + b"\x02" * 2
 | 
				
			||||||
    img = Image.frombytes("P", (6, 1), rgb)
 | 
					    img = Image.frombytes("P", (6, 1), rgb)
 | 
				
			||||||
| 
						 | 
					@ -135,6 +143,7 @@ class TestImagePalette(PillowTestCase):
 | 
				
			||||||
    with Image.open(outfile) as reloaded:
 | 
					    with Image.open(outfile) as reloaded:
 | 
				
			||||||
        assert_image_equal(img, reloaded)
 | 
					        assert_image_equal(img, reloaded)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_palette(self):
 | 
					
 | 
				
			||||||
 | 
					def test_invalid_palette():
 | 
				
			||||||
    with pytest.raises(IOError):
 | 
					    with pytest.raises(IOError):
 | 
				
			||||||
        ImagePalette.load("Tests/images/hopper.jpg")
 | 
					        ImagePalette.load("Tests/images/hopper.jpg")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,12 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from PIL import Image, ImageSequence, TiffImagePlugin
 | 
					from PIL import Image, ImageSequence, TiffImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, hopper, skip_unless_feature
 | 
					from .helper import assert_image_equal, hopper, skip_unless_feature
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestImageSequence(PillowTestCase):
 | 
					def test_sanity(tmp_path):
 | 
				
			||||||
    def test_sanity(self):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_file = self.tempfile("temp.im")
 | 
					    test_file = str(tmp_path / "temp.im")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = hopper("RGB")
 | 
					    im = hopper("RGB")
 | 
				
			||||||
    im.save(test_file)
 | 
					    im.save(test_file)
 | 
				
			||||||
| 
						 | 
					@ -25,7 +24,8 @@ class TestImageSequence(PillowTestCase):
 | 
				
			||||||
    with pytest.raises(AttributeError):
 | 
					    with pytest.raises(AttributeError):
 | 
				
			||||||
        ImageSequence.Iterator(0)
 | 
					        ImageSequence.Iterator(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_iterator(self):
 | 
					
 | 
				
			||||||
 | 
					def test_iterator():
 | 
				
			||||||
    with Image.open("Tests/images/multipage.tiff") as im:
 | 
					    with Image.open("Tests/images/multipage.tiff") as im:
 | 
				
			||||||
        i = ImageSequence.Iterator(im)
 | 
					        i = ImageSequence.Iterator(im)
 | 
				
			||||||
        for index in range(0, im.n_frames):
 | 
					        for index in range(0, im.n_frames):
 | 
				
			||||||
| 
						 | 
					@ -35,29 +35,34 @@ class TestImageSequence(PillowTestCase):
 | 
				
			||||||
        with pytest.raises(StopIteration):
 | 
					        with pytest.raises(StopIteration):
 | 
				
			||||||
            next(i)
 | 
					            next(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_iterator_min_frame(self):
 | 
					
 | 
				
			||||||
 | 
					def test_iterator_min_frame():
 | 
				
			||||||
    with Image.open("Tests/images/hopper.psd") as im:
 | 
					    with Image.open("Tests/images/hopper.psd") as im:
 | 
				
			||||||
        i = ImageSequence.Iterator(im)
 | 
					        i = ImageSequence.Iterator(im)
 | 
				
			||||||
        for index in range(1, im.n_frames):
 | 
					        for index in range(1, im.n_frames):
 | 
				
			||||||
            assert i[index] == next(i)
 | 
					            assert i[index] == next(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _test_multipage_tiff(self):
 | 
					
 | 
				
			||||||
 | 
					def _test_multipage_tiff():
 | 
				
			||||||
    with Image.open("Tests/images/multipage.tiff") as im:
 | 
					    with Image.open("Tests/images/multipage.tiff") as im:
 | 
				
			||||||
        for index, frame in enumerate(ImageSequence.Iterator(im)):
 | 
					        for index, frame in enumerate(ImageSequence.Iterator(im)):
 | 
				
			||||||
            frame.load()
 | 
					            frame.load()
 | 
				
			||||||
            assert index == im.tell()
 | 
					            assert index == im.tell()
 | 
				
			||||||
            frame.convert("RGB")
 | 
					            frame.convert("RGB")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_tiff(self):
 | 
					 | 
				
			||||||
        self._test_multipage_tiff()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @skip_unless_feature("libtiff")
 | 
					def test_tiff():
 | 
				
			||||||
    def test_libtiff(self):
 | 
					    _test_multipage_tiff()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@skip_unless_feature("libtiff")
 | 
				
			||||||
 | 
					def test_libtiff():
 | 
				
			||||||
    TiffImagePlugin.READ_LIBTIFF = True
 | 
					    TiffImagePlugin.READ_LIBTIFF = True
 | 
				
			||||||
        self._test_multipage_tiff()
 | 
					    _test_multipage_tiff()
 | 
				
			||||||
    TiffImagePlugin.READ_LIBTIFF = False
 | 
					    TiffImagePlugin.READ_LIBTIFF = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_consecutive(self):
 | 
					
 | 
				
			||||||
 | 
					def test_consecutive():
 | 
				
			||||||
    with Image.open("Tests/images/multipage.tiff") as im:
 | 
					    with Image.open("Tests/images/multipage.tiff") as im:
 | 
				
			||||||
        firstFrame = None
 | 
					        firstFrame = None
 | 
				
			||||||
        for frame in ImageSequence.Iterator(im):
 | 
					        for frame in ImageSequence.Iterator(im):
 | 
				
			||||||
| 
						 | 
					@ -67,7 +72,8 @@ class TestImageSequence(PillowTestCase):
 | 
				
			||||||
            assert_image_equal(frame, firstFrame)
 | 
					            assert_image_equal(frame, firstFrame)
 | 
				
			||||||
            break
 | 
					            break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_palette_mmap(self):
 | 
					
 | 
				
			||||||
 | 
					def test_palette_mmap():
 | 
				
			||||||
    # Using mmap in ImageFile can require to reload the palette.
 | 
					    # Using mmap in ImageFile can require to reload the palette.
 | 
				
			||||||
    with Image.open("Tests/images/multipage-mmap.tiff") as im:
 | 
					    with Image.open("Tests/images/multipage-mmap.tiff") as im:
 | 
				
			||||||
        color1 = im.getpalette()[0:3]
 | 
					        color1 = im.getpalette()[0:3]
 | 
				
			||||||
| 
						 | 
					@ -75,7 +81,8 @@ class TestImageSequence(PillowTestCase):
 | 
				
			||||||
        color2 = im.getpalette()[0:3]
 | 
					        color2 = im.getpalette()[0:3]
 | 
				
			||||||
        assert color1 == color2
 | 
					        assert color1 == color2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_all_frames(self):
 | 
					
 | 
				
			||||||
 | 
					def test_all_frames():
 | 
				
			||||||
    # Test a single image
 | 
					    # Test a single image
 | 
				
			||||||
    with Image.open("Tests/images/iss634.gif") as im:
 | 
					    with Image.open("Tests/images/iss634.gif") as im:
 | 
				
			||||||
        ims = ImageSequence.all_frames(im)
 | 
					        ims = ImageSequence.all_frames(im)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,10 @@
 | 
				
			||||||
import unittest
 | 
					import pytest
 | 
				
			||||||
 | 
					 | 
				
			||||||
from PIL import ImageWin
 | 
					from PIL import ImageWin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, hopper, is_win32
 | 
					from .helper import hopper, is_win32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestImageWin(PillowTestCase):
 | 
					class TestImageWin:
 | 
				
			||||||
    def test_sanity(self):
 | 
					    def test_sanity(self):
 | 
				
			||||||
        dir(ImageWin)
 | 
					        dir(ImageWin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,8 +31,8 @@ class TestImageWin(PillowTestCase):
 | 
				
			||||||
        assert wnd2 == 50
 | 
					        assert wnd2 == 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipUnless(is_win32(), "Windows only")
 | 
					@pytest.mark.skipif(not is_win32(), reason="Windows only")
 | 
				
			||||||
class TestImageWinDib(PillowTestCase):
 | 
					class TestImageWinDib:
 | 
				
			||||||
    def test_dib_image(self):
 | 
					    def test_dib_image(self):
 | 
				
			||||||
        # Arrange
 | 
					        # Arrange
 | 
				
			||||||
        im = hopper()
 | 
					        im = hopper()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,9 @@
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
from PIL import GifImagePlugin, Image, JpegImagePlugin
 | 
					from PIL import GifImagePlugin, Image, JpegImagePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import (
 | 
					from .helper import cjpeg_available, djpeg_available, is_win32, netpbm_available
 | 
				
			||||||
    PillowTestCase,
 | 
					 | 
				
			||||||
    cjpeg_available,
 | 
					 | 
				
			||||||
    djpeg_available,
 | 
					 | 
				
			||||||
    is_win32,
 | 
					 | 
				
			||||||
    netpbm_available,
 | 
					 | 
				
			||||||
    unittest,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_JPG = "Tests/images/hopper.jpg"
 | 
					TEST_JPG = "Tests/images/hopper.jpg"
 | 
				
			||||||
TEST_GIF = "Tests/images/hopper.gif"
 | 
					TEST_GIF = "Tests/images/hopper.gif"
 | 
				
			||||||
| 
						 | 
					@ -17,38 +11,38 @@ TEST_GIF = "Tests/images/hopper.gif"
 | 
				
			||||||
test_filenames = ("temp_';", 'temp_";', "temp_'\"|", "temp_'\"||", "temp_'\"&&")
 | 
					test_filenames = ("temp_';", 'temp_";', "temp_'\"|", "temp_'\"||", "temp_'\"&&")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipIf(is_win32(), "requires Unix or macOS")
 | 
					@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
 | 
				
			||||||
class TestShellInjection(PillowTestCase):
 | 
					class TestShellInjection:
 | 
				
			||||||
    def assert_save_filename_check(self, src_img, save_func):
 | 
					    def assert_save_filename_check(self, tmp_path, src_img, save_func):
 | 
				
			||||||
        for filename in test_filenames:
 | 
					        for filename in test_filenames:
 | 
				
			||||||
            dest_file = self.tempfile(filename)
 | 
					            dest_file = str(tmp_path / filename)
 | 
				
			||||||
            save_func(src_img, 0, dest_file)
 | 
					            save_func(src_img, 0, dest_file)
 | 
				
			||||||
            # If file can't be opened, shell injection probably occurred
 | 
					            # If file can't be opened, shell injection probably occurred
 | 
				
			||||||
            with Image.open(dest_file) as im:
 | 
					            with Image.open(dest_file) as im:
 | 
				
			||||||
                im.load()
 | 
					                im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(djpeg_available(), "djpeg not available")
 | 
					    @pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
 | 
				
			||||||
    def test_load_djpeg_filename(self):
 | 
					    def test_load_djpeg_filename(self, tmp_path):
 | 
				
			||||||
        for filename in test_filenames:
 | 
					        for filename in test_filenames:
 | 
				
			||||||
            src_file = self.tempfile(filename)
 | 
					            src_file = str(tmp_path / filename)
 | 
				
			||||||
            shutil.copy(TEST_JPG, src_file)
 | 
					            shutil.copy(TEST_JPG, src_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with Image.open(src_file) as im:
 | 
					            with Image.open(src_file) as im:
 | 
				
			||||||
                im.load_djpeg()
 | 
					                im.load_djpeg()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(cjpeg_available(), "cjpeg not available")
 | 
					    @pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
 | 
				
			||||||
    def test_save_cjpeg_filename(self):
 | 
					    def test_save_cjpeg_filename(self, tmp_path):
 | 
				
			||||||
        with Image.open(TEST_JPG) as im:
 | 
					        with Image.open(TEST_JPG) as im:
 | 
				
			||||||
            self.assert_save_filename_check(im, JpegImagePlugin._save_cjpeg)
 | 
					            self.assert_save_filename_check(tmp_path, im, JpegImagePlugin._save_cjpeg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(netpbm_available(), "netpbm not available")
 | 
					    @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
 | 
				
			||||||
    def test_save_netpbm_filename_bmp_mode(self):
 | 
					    def test_save_netpbm_filename_bmp_mode(self, tmp_path):
 | 
				
			||||||
        with Image.open(TEST_GIF) as im:
 | 
					        with Image.open(TEST_GIF) as im:
 | 
				
			||||||
            im = im.convert("RGB")
 | 
					            im = im.convert("RGB")
 | 
				
			||||||
            self.assert_save_filename_check(im, GifImagePlugin._save_netpbm)
 | 
					            self.assert_save_filename_check(tmp_path, im, GifImagePlugin._save_netpbm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(netpbm_available(), "netpbm not available")
 | 
					    @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
 | 
				
			||||||
    def test_save_netpbm_filename_l_mode(self):
 | 
					    def test_save_netpbm_filename_l_mode(self, tmp_path):
 | 
				
			||||||
        with Image.open(TEST_GIF) as im:
 | 
					        with Image.open(TEST_GIF) as im:
 | 
				
			||||||
            im = im.convert("L")
 | 
					            im = im.convert("L")
 | 
				
			||||||
            self.assert_save_filename_check(im, GifImagePlugin._save_netpbm)
 | 
					            self.assert_save_filename_check(tmp_path, im, GifImagePlugin._save_netpbm)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,32 +3,33 @@ from fractions import Fraction
 | 
				
			||||||
from PIL import Image, TiffImagePlugin, features
 | 
					from PIL import Image, TiffImagePlugin, features
 | 
				
			||||||
from PIL.TiffImagePlugin import IFDRational
 | 
					from PIL.TiffImagePlugin import IFDRational
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import PillowTestCase, hopper
 | 
					from .helper import hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Test_IFDRational(PillowTestCase):
 | 
					def _test_equal(num, denom, target):
 | 
				
			||||||
    def _test_equal(self, num, denom, target):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    t = IFDRational(num, denom)
 | 
					    t = IFDRational(num, denom)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert target == t
 | 
					    assert target == t
 | 
				
			||||||
    assert t == target
 | 
					    assert t == target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sanity(self):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._test_equal(1, 1, 1)
 | 
					def test_sanity():
 | 
				
			||||||
        self._test_equal(1, 1, Fraction(1, 1))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._test_equal(2, 2, 1)
 | 
					    _test_equal(1, 1, 1)
 | 
				
			||||||
        self._test_equal(1.0, 1, Fraction(1, 1))
 | 
					    _test_equal(1, 1, Fraction(1, 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._test_equal(Fraction(1, 1), 1, Fraction(1, 1))
 | 
					    _test_equal(2, 2, 1)
 | 
				
			||||||
        self._test_equal(IFDRational(1, 1), 1, 1)
 | 
					    _test_equal(1.0, 1, Fraction(1, 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._test_equal(1, 2, Fraction(1, 2))
 | 
					    _test_equal(Fraction(1, 1), 1, Fraction(1, 1))
 | 
				
			||||||
        self._test_equal(1, 2, IFDRational(1, 2))
 | 
					    _test_equal(IFDRational(1, 1), 1, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_nonetype(self):
 | 
					    _test_equal(1, 2, Fraction(1, 2))
 | 
				
			||||||
 | 
					    _test_equal(1, 2, IFDRational(1, 2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_nonetype():
 | 
				
			||||||
    # Fails if the _delegate function doesn't return a valid function
 | 
					    # Fails if the _delegate function doesn't return a valid function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xres = IFDRational(72)
 | 
					    xres = IFDRational(72)
 | 
				
			||||||
| 
						 | 
					@ -41,7 +42,8 @@ class Test_IFDRational(PillowTestCase):
 | 
				
			||||||
    assert xres and 1
 | 
					    assert xres and 1
 | 
				
			||||||
    assert xres and yres
 | 
					    assert xres and yres
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_ifd_rational_save(self):
 | 
					
 | 
				
			||||||
 | 
					def test_ifd_rational_save(tmp_path):
 | 
				
			||||||
    methods = (True, False)
 | 
					    methods = (True, False)
 | 
				
			||||||
    if not features.check("libtiff"):
 | 
					    if not features.check("libtiff"):
 | 
				
			||||||
        methods = (False,)
 | 
					        methods = (False,)
 | 
				
			||||||
| 
						 | 
					@ -50,7 +52,7 @@ class Test_IFDRational(PillowTestCase):
 | 
				
			||||||
        TiffImagePlugin.WRITE_LIBTIFF = libtiff
 | 
					        TiffImagePlugin.WRITE_LIBTIFF = libtiff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = hopper()
 | 
					        im = hopper()
 | 
				
			||||||
            out = self.tempfile("temp.tiff")
 | 
					        out = str(tmp_path / "temp.tiff")
 | 
				
			||||||
        res = IFDRational(301, 1)
 | 
					        res = IFDRational(301, 1)
 | 
				
			||||||
        im.save(out, dpi=(res, res), compression="raw")
 | 
					        im.save(out, dpi=(res, res), compression="raw")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper
 | 
					from .helper import assert_image_equal, assert_image_similar, hopper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestUploader(PillowTestCase):
 | 
					def check_upload_equal():
 | 
				
			||||||
    def check_upload_equal(self):
 | 
					 | 
				
			||||||
    result = hopper("P").convert("RGB")
 | 
					    result = hopper("P").convert("RGB")
 | 
				
			||||||
    target = hopper("RGB")
 | 
					    target = hopper("RGB")
 | 
				
			||||||
    assert_image_equal(result, target)
 | 
					    assert_image_equal(result, target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_upload_similar(self):
 | 
					
 | 
				
			||||||
 | 
					def check_upload_similar():
 | 
				
			||||||
    result = hopper("P").convert("RGB")
 | 
					    result = hopper("P").convert("RGB")
 | 
				
			||||||
    target = hopper("RGB")
 | 
					    target = hopper("RGB")
 | 
				
			||||||
    assert_image_similar(result, target, 0)
 | 
					    assert_image_similar(result, target, 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,6 +298,11 @@ The :py:meth:`~PIL.Image.Image.open` method may set the following
 | 
				
			||||||
**exif**
 | 
					**exif**
 | 
				
			||||||
    Raw EXIF data from the image.
 | 
					    Raw EXIF data from the image.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**comment**
 | 
				
			||||||
 | 
					    A comment about the image.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .. versionadded:: 7.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The :py:meth:`~PIL.Image.Image.save` method supports the following options:
 | 
					The :py:meth:`~PIL.Image.Image.save` method supports the following options:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,8 @@ Convert files to JPEG
 | 
				
			||||||
        outfile = f + ".jpg"
 | 
					        outfile = f + ".jpg"
 | 
				
			||||||
        if infile != outfile:
 | 
					        if infile != outfile:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                Image.open(infile).save(outfile)
 | 
					                with Image.open(infile) as im:
 | 
				
			||||||
 | 
					                    im.save(outfile)
 | 
				
			||||||
            except IOError:
 | 
					            except IOError:
 | 
				
			||||||
                print("cannot convert", infile)
 | 
					                print("cannot convert", infile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,8 +47,8 @@ Basic Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Install Pillow with :command:`pip`::
 | 
					Install Pillow with :command:`pip`::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade pip
 | 
					    python3 -m pip install --upgrade pip
 | 
				
			||||||
    python -m pip install --upgrade Pillow
 | 
					    python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Windows Installation
 | 
					Windows Installation
 | 
				
			||||||
| 
						 | 
					@ -59,8 +59,8 @@ supported Pythons in both 32 and 64-bit versions in wheel, egg, and
 | 
				
			||||||
executable installers. These binaries have all of the optional
 | 
					executable installers. These binaries have all of the optional
 | 
				
			||||||
libraries included except for raqm and libimagequant::
 | 
					libraries included except for raqm and libimagequant::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade pip
 | 
					    python3 -m pip install --upgrade pip
 | 
				
			||||||
    python -m pip install --upgrade Pillow
 | 
					    python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macOS Installation
 | 
					macOS Installation
 | 
				
			||||||
| 
						 | 
					@ -71,8 +71,8 @@ versions in the wheel format. These include support for all optional
 | 
				
			||||||
libraries except libimagequant.  Raqm support requires libraqm,
 | 
					libraries except libimagequant.  Raqm support requires libraqm,
 | 
				
			||||||
fribidi, and harfbuzz to be installed separately::
 | 
					fribidi, and harfbuzz to be installed separately::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade pip
 | 
					    python3 -m pip install --upgrade pip
 | 
				
			||||||
    python -m pip install --upgrade Pillow
 | 
					    python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Linux Installation
 | 
					Linux Installation
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
| 
						 | 
					@ -82,8 +82,8 @@ versions in the manylinux wheel format. These include support for all
 | 
				
			||||||
optional libraries except libimagequant. Raqm support requires
 | 
					optional libraries except libimagequant. Raqm support requires
 | 
				
			||||||
libraqm, fribidi, and harfbuzz to be installed separately::
 | 
					libraqm, fribidi, and harfbuzz to be installed separately::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade pip
 | 
					    python3 -m pip install --upgrade pip
 | 
				
			||||||
    python -m pip install --upgrade Pillow
 | 
					    python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Most major Linux distributions, including Fedora, Debian/Ubuntu and
 | 
					Most major Linux distributions, including Fedora, Debian/Ubuntu and
 | 
				
			||||||
ArchLinux also include Pillow in packages that previously contained
 | 
					ArchLinux also include Pillow in packages that previously contained
 | 
				
			||||||
| 
						 | 
					@ -195,8 +195,8 @@ Many of Pillow's features require external libraries:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Once you have installed the prerequisites, run::
 | 
					Once you have installed the prerequisites, run::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade pip
 | 
					    python3 -m pip install --upgrade pip
 | 
				
			||||||
    python -m pip install --upgrade Pillow
 | 
					    python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If the prerequisites are installed in the standard library locations
 | 
					If the prerequisites are installed in the standard library locations
 | 
				
			||||||
for your machine (e.g. :file:`/usr` or :file:`/usr/local`), no
 | 
					for your machine (e.g. :file:`/usr` or :file:`/usr/local`), no
 | 
				
			||||||
| 
						 | 
					@ -206,7 +206,7 @@ those locations by editing :file:`setup.py` or
 | 
				
			||||||
:file:`setup.cfg`, or by adding environment variables on the command
 | 
					:file:`setup.cfg`, or by adding environment variables on the command
 | 
				
			||||||
line::
 | 
					line::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CFLAGS="-I/usr/pkg/include" python -m pip install --upgrade Pillow
 | 
					    CFLAGS="-I/usr/pkg/include" python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If Pillow has been previously built without the required
 | 
					If Pillow has been previously built without the required
 | 
				
			||||||
prerequisites, it may be necessary to manually clear the pip cache or
 | 
					prerequisites, it may be necessary to manually clear the pip cache or
 | 
				
			||||||
| 
						 | 
					@ -254,7 +254,7 @@ Sample usage::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
or using pip::
 | 
					or using pip::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade Pillow --global-option="build_ext" --global-option="--enable-[feature]"
 | 
					    python3 -m pip install --upgrade Pillow --global-option="build_ext" --global-option="--enable-[feature]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Building on macOS
 | 
					Building on macOS
 | 
				
			||||||
| 
						 | 
					@ -280,8 +280,8 @@ Then see ``depends/install_raqm_cmake.sh`` to install libraqm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Now install Pillow with::
 | 
					Now install Pillow with::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    python -m pip install --upgrade pip
 | 
					    python3 -m pip install --upgrade pip
 | 
				
			||||||
    python -m pip install --upgrade Pillow
 | 
					    python3 -m pip install --upgrade Pillow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
or from within the uncompressed source directory::
 | 
					or from within the uncompressed source directory::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ Example: Draw a gray cross over an image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from PIL import Image, ImageDraw
 | 
					    from PIL import Image, ImageDraw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = Image.open("hopper.jpg")
 | 
					    with Image.open("hopper.jpg") as im:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        draw = ImageDraw.Draw(im)
 | 
					        draw = ImageDraw.Draw(im)
 | 
				
			||||||
        draw.line((0, 0) + im.size, fill=128)
 | 
					        draw.line((0, 0) + im.size, fill=128)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,7 @@ Extracting frames from an animation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from PIL import Image, ImageSequence
 | 
					    from PIL import Image, ImageSequence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = Image.open("animation.fli")
 | 
					    with Image.open("animation.fli") as im:
 | 
				
			||||||
 | 
					 | 
				
			||||||
        index = 1
 | 
					        index = 1
 | 
				
			||||||
        for frame in ImageSequence.Iterator(im):
 | 
					        for frame in ImageSequence.Iterator(im):
 | 
				
			||||||
            frame.save("frame%d.png" % index)
 | 
					            frame.save("frame%d.png" % index)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ changes it.
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from PIL import Image
 | 
					    from PIL import Image
 | 
				
			||||||
    im = Image.open('hopper.jpg')
 | 
					    with Image.open('hopper.jpg') as im:
 | 
				
			||||||
        px = im.load()
 | 
					        px = im.load()
 | 
				
			||||||
    print (px[4,4])
 | 
					    print (px[4,4])
 | 
				
			||||||
    px[4,4] = (0,0,0)
 | 
					    px[4,4] = (0,0,0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ The following script loads an image, accesses one pixel from it, then changes it
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from PIL import Image
 | 
					    from PIL import Image
 | 
				
			||||||
    im = Image.open('hopper.jpg')
 | 
					    with Image.open('hopper.jpg') as im:
 | 
				
			||||||
        px = im.load()
 | 
					        px = im.load()
 | 
				
			||||||
    print (px[4,4])
 | 
					    print (px[4,4])
 | 
				
			||||||
    px[4,4] = (0,0,0)
 | 
					    px[4,4] = (0,0,0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,27 @@ been resolved.
 | 
				
			||||||
    im = Image.open("hopper.jpg")
 | 
					    im = Image.open("hopper.jpg")
 | 
				
			||||||
    im.save("out.jpg", quality=0)
 | 
					    im.save("out.jpg", quality=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					API Additions
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Reading JPEG comments
 | 
				
			||||||
 | 
					^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When opening a JPEG image, the comment may now be read into
 | 
				
			||||||
 | 
					:py:attr:`~PIL.Image.Image.info`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Other Changes
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If present, only use alpha channel for bounding box
 | 
				
			||||||
 | 
					^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When the :py:meth:`~PIL.Image.Image.getbbox` method calculates the bounding
 | 
				
			||||||
 | 
					box, for an RGB image it trims black pixels. Similarly, for an RGBA image it
 | 
				
			||||||
 | 
					would trim black transparent pixels. This is now changed so that if an image
 | 
				
			||||||
 | 
					has an alpha channel (RGBA, RGBa, PA, LA, La), any transparent pixels are
 | 
				
			||||||
 | 
					trimmed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Improved APNG support
 | 
					Improved APNG support
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,8 +141,8 @@ def Ghostscript(tile, size, fp, scale=1):
 | 
				
			||||||
            startupinfo = subprocess.STARTUPINFO()
 | 
					            startupinfo = subprocess.STARTUPINFO()
 | 
				
			||||||
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
 | 
					            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
 | 
				
			||||||
        subprocess.check_call(command, startupinfo=startupinfo)
 | 
					        subprocess.check_call(command, startupinfo=startupinfo)
 | 
				
			||||||
        im = Image.open(outfile)
 | 
					        out_im = Image.open(outfile)
 | 
				
			||||||
        im.load()
 | 
					        out_im.load()
 | 
				
			||||||
    finally:
 | 
					    finally:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            os.unlink(outfile)
 | 
					            os.unlink(outfile)
 | 
				
			||||||
| 
						 | 
					@ -151,7 +151,9 @@ def Ghostscript(tile, size, fp, scale=1):
 | 
				
			||||||
        except OSError:
 | 
					        except OSError:
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return im.im.copy()
 | 
					    im = out_im.im.copy()
 | 
				
			||||||
 | 
					    out_im.close()
 | 
				
			||||||
 | 
					    return im
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PSFile:
 | 
					class PSFile:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -370,7 +370,7 @@ if __name__ == "__main__":
 | 
				
			||||||
        for size in imf.info["sizes"]:
 | 
					        for size in imf.info["sizes"]:
 | 
				
			||||||
            imf.size = size
 | 
					            imf.size = size
 | 
				
			||||||
            imf.save("out-%s-%s-%s.png" % size)
 | 
					            imf.save("out-%s-%s-%s.png" % size)
 | 
				
			||||||
        im = Image.open(sys.argv[1])
 | 
					        with Image.open(sys.argv[1]) as im:
 | 
				
			||||||
            im.save("out.png")
 | 
					            im.save("out.png")
 | 
				
			||||||
        if sys.platform == "windows":
 | 
					        if sys.platform == "windows":
 | 
				
			||||||
            os.startfile("out.png")
 | 
					            os.startfile("out.png")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2236,20 +2236,22 @@ class Image:
 | 
				
			||||||
        :returns: None
 | 
					        :returns: None
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # preserve aspect ratio
 | 
					        x, y = map(math.floor, size)
 | 
				
			||||||
        x, y = self.size
 | 
					        if x >= self.width and y >= self.height:
 | 
				
			||||||
        if x > size[0]:
 | 
					 | 
				
			||||||
            y = max(round(y * size[0] / x), 1)
 | 
					 | 
				
			||||||
            x = round(size[0])
 | 
					 | 
				
			||||||
        if y > size[1]:
 | 
					 | 
				
			||||||
            x = max(round(x * size[1] / y), 1)
 | 
					 | 
				
			||||||
            y = round(size[1])
 | 
					 | 
				
			||||||
        size = x, y
 | 
					 | 
				
			||||||
        box = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if size == self.size:
 | 
					 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def round_aspect(number, key):
 | 
				
			||||||
 | 
					            return max(min(math.floor(number), math.ceil(number), key=key), 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # preserve aspect ratio
 | 
				
			||||||
 | 
					        aspect = self.width / self.height
 | 
				
			||||||
 | 
					        if x / y >= aspect:
 | 
				
			||||||
 | 
					            x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            y = round_aspect(x / aspect, key=lambda n: abs(aspect - x / n))
 | 
				
			||||||
 | 
					        size = (x, y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        box = None
 | 
				
			||||||
        if reducing_gap is not None:
 | 
					        if reducing_gap is not None:
 | 
				
			||||||
            res = self.draft(None, (size[0] * reducing_gap, size[1] * reducing_gap))
 | 
					            res = self.draft(None, (size[0] * reducing_gap, size[1] * reducing_gap))
 | 
				
			||||||
            if res is not None:
 | 
					            if res is not None:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,7 +71,10 @@ class ImageFont:
 | 
				
			||||||
    def _load_pilfont(self, filename):
 | 
					    def _load_pilfont(self, filename):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with open(filename, "rb") as fp:
 | 
					        with open(filename, "rb") as fp:
 | 
				
			||||||
 | 
					            image = None
 | 
				
			||||||
            for ext in (".png", ".gif", ".pbm"):
 | 
					            for ext in (".png", ".gif", ".pbm"):
 | 
				
			||||||
 | 
					                if image:
 | 
				
			||||||
 | 
					                    image.close()
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    fullname = os.path.splitext(filename)[0] + ext
 | 
					                    fullname = os.path.splitext(filename)[0] + ext
 | 
				
			||||||
                    image = Image.open(fullname)
 | 
					                    image = Image.open(fullname)
 | 
				
			||||||
| 
						 | 
					@ -81,11 +84,14 @@ class ImageFont:
 | 
				
			||||||
                    if image and image.mode in ("1", "L"):
 | 
					                    if image and image.mode in ("1", "L"):
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
 | 
					                if image:
 | 
				
			||||||
 | 
					                    image.close()
 | 
				
			||||||
                raise OSError("cannot find glyph data file")
 | 
					                raise OSError("cannot find glyph data file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.file = fullname
 | 
					            self.file = fullname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return self._load_pilfont_data(fp, image)
 | 
					            self._load_pilfont_data(fp, image)
 | 
				
			||||||
 | 
					            image.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _load_pilfont_data(self, file, image):
 | 
					    def _load_pilfont_data(self, file, image):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,9 @@ def grab(bbox=None, include_layered_windows=False, all_screens=False):
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        os.unlink(filepath)
 | 
					        os.unlink(filepath)
 | 
				
			||||||
        if bbox:
 | 
					        if bbox:
 | 
				
			||||||
            im = im.crop(bbox)
 | 
					            im_cropped = im.crop(bbox)
 | 
				
			||||||
 | 
					            im.close()
 | 
				
			||||||
 | 
					            return im_cropped
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        offset, size, data = Image.core.grabscreen(include_layered_windows, all_screens)
 | 
					        offset, size, data = Image.core.grabscreen(include_layered_windows, all_screens)
 | 
				
			||||||
        im = Image.frombytes(
 | 
					        im = Image.frombytes(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,4 +203,5 @@ if __name__ == "__main__":
 | 
				
			||||||
        print("Syntax: python ImageShow.py imagefile [title]")
 | 
					        print("Syntax: python ImageShow.py imagefile [title]")
 | 
				
			||||||
        sys.exit()
 | 
					        sys.exit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print(show(Image.open(sys.argv[1]), *sys.argv[2:]))
 | 
					    with Image.open(sys.argv[1]) as im:
 | 
				
			||||||
 | 
					        print(show(im, *sys.argv[2:]))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,7 +158,7 @@ class IptcImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        o.close()
 | 
					        o.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            _im = Image.open(outfile)
 | 
					            with Image.open(outfile) as _im:
 | 
				
			||||||
                _im.load()
 | 
					                _im.load()
 | 
				
			||||||
                self.im = _im.im
 | 
					                self.im = _im.im
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -176,6 +176,7 @@ def COM(self, marker):
 | 
				
			||||||
    n = i16(self.fp.read(2)) - 2
 | 
					    n = i16(self.fp.read(2)) - 2
 | 
				
			||||||
    s = ImageFile._safe_read(self.fp, n)
 | 
					    s = ImageFile._safe_read(self.fp, n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.info["comment"] = s
 | 
				
			||||||
    self.app["COM"] = s  # compatibility
 | 
					    self.app["COM"] = s  # compatibility
 | 
				
			||||||
    self.applist.append(("COM", s))
 | 
					    self.applist.append(("COM", s))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -448,7 +449,7 @@ class JpegImageFile(ImageFile.ImageFile):
 | 
				
			||||||
            raise ValueError("Invalid Filename")
 | 
					            raise ValueError("Invalid Filename")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            _im = Image.open(path)
 | 
					            with Image.open(path) as _im:
 | 
				
			||||||
                _im.load()
 | 
					                _im.load()
 | 
				
			||||||
                self.im = _im.im
 | 
					                self.im = _im.im
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -304,7 +304,7 @@ if __name__ == "__main__":
 | 
				
			||||||
        print("input image must be in Spider format")
 | 
					        print("input image must be in Spider format")
 | 
				
			||||||
        sys.exit()
 | 
					        sys.exit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im = Image.open(filename)
 | 
					    with Image.open(filename) as im:
 | 
				
			||||||
        print("image: " + str(im))
 | 
					        print("image: " + str(im))
 | 
				
			||||||
        print("format: " + str(im.format))
 | 
					        print("format: " + str(im.format))
 | 
				
			||||||
        print("size: " + str(im.size))
 | 
					        print("size: " + str(im.size))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import collections
 | 
					import collections
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					import warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import PIL
 | 
					import PIL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,14 +77,14 @@ def get_supported_features():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check(feature):
 | 
					def check(feature):
 | 
				
			||||||
    return (
 | 
					    if feature in modules:
 | 
				
			||||||
        feature in modules
 | 
					        return check_module(feature)
 | 
				
			||||||
        and check_module(feature)
 | 
					    if feature in codecs:
 | 
				
			||||||
        or feature in codecs
 | 
					        return check_codec(feature)
 | 
				
			||||||
        and check_codec(feature)
 | 
					    if feature in features:
 | 
				
			||||||
        or feature in features
 | 
					        return check_feature(feature)
 | 
				
			||||||
        and check_feature(feature)
 | 
					    warnings.warn("Unknown feature '%s'." % feature, stacklevel=2)
 | 
				
			||||||
    )
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_supported():
 | 
					def get_supported():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -782,9 +782,6 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    im = (Imaging) id;
 | 
					    im = (Imaging) id;
 | 
				
			||||||
    /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
 | 
					    /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
 | 
				
			||||||
    load_flags = FT_LOAD_NO_BITMAP;
 | 
					    load_flags = FT_LOAD_NO_BITMAP;
 | 
				
			||||||
    if (stroker == NULL) {
 | 
					 | 
				
			||||||
        load_flags |= FT_LOAD_RENDER;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (mask) {
 | 
					    if (mask) {
 | 
				
			||||||
        load_flags |= FT_LOAD_TARGET_MONO;
 | 
					        load_flags |= FT_LOAD_TARGET_MONO;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -792,7 +789,7 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    ascender = 0;
 | 
					    ascender = 0;
 | 
				
			||||||
    for (i = 0; i < count; i++) {
 | 
					    for (i = 0; i < count; i++) {
 | 
				
			||||||
        index = glyph_info[i].index;
 | 
					        index = glyph_info[i].index;
 | 
				
			||||||
        error = FT_Load_Glyph(self->face, index, load_flags);
 | 
					        error = FT_Load_Glyph(self->face, index, load_flags | FT_LOAD_RENDER);
 | 
				
			||||||
        if (error) {
 | 
					        if (error) {
 | 
				
			||||||
            return geterror(error);
 | 
					            return geterror(error);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -806,6 +803,10 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
            ascender = temp;
 | 
					            ascender = temp;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (stroker == NULL) {
 | 
				
			||||||
 | 
					        load_flags |= FT_LOAD_RENDER;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    x = y = 0;
 | 
					    x = y = 0;
 | 
				
			||||||
    horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
 | 
					    horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
 | 
				
			||||||
    for (i = 0; i < count; i++) {
 | 
					    for (i = 0; i < count; i++) {
 | 
				
			||||||
| 
						 | 
					@ -908,7 +909,7 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\
 | 
					    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\
 | 
				
			||||||
    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1)
 | 
					    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1)
 | 
				
			||||||
    static PyObject*
 | 
					    static PyObject*
 | 
				
			||||||
    font_getvarnames(FontObject* self, PyObject* args)
 | 
					    font_getvarnames(FontObject* self)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int error;
 | 
					        int error;
 | 
				
			||||||
        FT_UInt i, j, num_namedstyles, name_count;
 | 
					        FT_UInt i, j, num_namedstyles, name_count;
 | 
				
			||||||
| 
						 | 
					@ -947,7 +948,7 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static PyObject*
 | 
					    static PyObject*
 | 
				
			||||||
    font_getvaraxes(FontObject* self, PyObject* args)
 | 
					    font_getvaraxes(FontObject* self)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int error;
 | 
					        int error;
 | 
				
			||||||
        FT_UInt i, j, num_axis, name_count;
 | 
					        FT_UInt i, j, num_axis, name_count;
 | 
				
			||||||
| 
						 | 
					@ -1077,8 +1078,8 @@ static PyMethodDef font_methods[] = {
 | 
				
			||||||
#if FREETYPE_MAJOR > 2 ||\
 | 
					#if FREETYPE_MAJOR > 2 ||\
 | 
				
			||||||
    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\
 | 
					    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\
 | 
				
			||||||
    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1)
 | 
					    (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1)
 | 
				
			||||||
    {"getvarnames", (PyCFunction) font_getvarnames, METH_VARARGS },
 | 
					    {"getvarnames", (PyCFunction) font_getvarnames, METH_NOARGS },
 | 
				
			||||||
    {"getvaraxes", (PyCFunction) font_getvaraxes, METH_VARARGS },
 | 
					    {"getvaraxes", (PyCFunction) font_getvaraxes, METH_NOARGS },
 | 
				
			||||||
    {"setvarname", (PyCFunction) font_setvarname, METH_VARARGS},
 | 
					    {"setvarname", (PyCFunction) font_setvarname, METH_VARARGS},
 | 
				
			||||||
    {"setvaraxes", (PyCFunction) font_setvaraxes, METH_VARARGS},
 | 
					    {"setvaraxes", (PyCFunction) font_setvaraxes, METH_VARARGS},
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/_webp.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								src/_webp.c
									
									
									
									
									
								
							| 
						 | 
					@ -369,7 +369,7 @@ PyObject* _anim_decoder_dealloc(PyObject* self)
 | 
				
			||||||
    Py_RETURN_NONE;
 | 
					    Py_RETURN_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyObject* _anim_decoder_get_info(PyObject* self, PyObject* args)
 | 
					PyObject* _anim_decoder_get_info(PyObject* self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
 | 
					    WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
 | 
				
			||||||
    WebPAnimInfo* info = &(decp->info);
 | 
					    WebPAnimInfo* info = &(decp->info);
 | 
				
			||||||
| 
						 | 
					@ -406,7 +406,7 @@ PyObject* _anim_decoder_get_chunk(PyObject* self, PyObject* args)
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args)
 | 
					PyObject* _anim_decoder_get_next(PyObject* self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t* buf;
 | 
					    uint8_t* buf;
 | 
				
			||||||
    int timestamp;
 | 
					    int timestamp;
 | 
				
			||||||
| 
						 | 
					@ -428,13 +428,7 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args)
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyObject* _anim_decoder_has_more_frames(PyObject* self, PyObject* args)
 | 
					PyObject* _anim_decoder_reset(PyObject* self)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self;
 | 
					 | 
				
			||||||
    return Py_BuildValue("i", WebPAnimDecoderHasMoreFrames(decp->dec));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PyObject* _anim_decoder_reset(PyObject* self, PyObject* args)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
 | 
					    WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
 | 
				
			||||||
    WebPAnimDecoderReset(decp->dec);
 | 
					    WebPAnimDecoderReset(decp->dec);
 | 
				
			||||||
| 
						 | 
					@ -489,11 +483,10 @@ static PyTypeObject WebPAnimEncoder_Type = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WebPAnimDecoder methods
 | 
					// WebPAnimDecoder methods
 | 
				
			||||||
static struct PyMethodDef _anim_decoder_methods[] = {
 | 
					static struct PyMethodDef _anim_decoder_methods[] = {
 | 
				
			||||||
    {"get_info", (PyCFunction)_anim_decoder_get_info, METH_VARARGS, "get_info"},
 | 
					    {"get_info", (PyCFunction)_anim_decoder_get_info, METH_NOARGS, "get_info"},
 | 
				
			||||||
    {"get_chunk", (PyCFunction)_anim_decoder_get_chunk, METH_VARARGS, "get_chunk"},
 | 
					    {"get_chunk", (PyCFunction)_anim_decoder_get_chunk, METH_VARARGS, "get_chunk"},
 | 
				
			||||||
    {"get_next", (PyCFunction)_anim_decoder_get_next, METH_VARARGS, "get_next"},
 | 
					    {"get_next", (PyCFunction)_anim_decoder_get_next, METH_NOARGS, "get_next"},
 | 
				
			||||||
    {"has_more_frames", (PyCFunction)_anim_decoder_has_more_frames, METH_VARARGS, "has_more_frames"},
 | 
					    {"reset", (PyCFunction)_anim_decoder_reset, METH_NOARGS, "reset"},
 | 
				
			||||||
    {"reset", (PyCFunction)_anim_decoder_reset, METH_VARARGS, "reset"},
 | 
					 | 
				
			||||||
    {NULL, NULL} /* sentinel */
 | 
					    {NULL, NULL} /* sentinel */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -775,7 +768,7 @@ end:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Return the decoder's version number, packed in hexadecimal using 8bits for
 | 
					// Return the decoder's version number, packed in hexadecimal using 8bits for
 | 
				
			||||||
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
 | 
					// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
 | 
				
			||||||
PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){
 | 
					PyObject* WebPDecoderVersion_wrapper() {
 | 
				
			||||||
    return Py_BuildValue("i", WebPGetDecoderVersion());
 | 
					    return Py_BuildValue("i", WebPGetDecoderVersion());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -787,7 +780,7 @@ int WebPDecoderBuggyAlpha(void) {
 | 
				
			||||||
    return WebPGetDecoderVersion()==0x0103;
 | 
					    return WebPGetDecoderVersion()==0x0103;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){
 | 
					PyObject* WebPDecoderBuggyAlpha_wrapper() {
 | 
				
			||||||
    return Py_BuildValue("i", WebPDecoderBuggyAlpha());
 | 
					    return Py_BuildValue("i", WebPDecoderBuggyAlpha());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -803,8 +796,8 @@ static PyMethodDef webpMethods[] =
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"},
 | 
					    {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"},
 | 
				
			||||||
    {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"},
 | 
					    {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"},
 | 
				
			||||||
    {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_VARARGS, "WebPVersion"},
 | 
					    {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_NOARGS, "WebPVersion"},
 | 
				
			||||||
    {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_VARARGS, "WebPDecoderBuggyAlpha"},
 | 
					    {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_NOARGS, "WebPDecoderBuggyAlpha"},
 | 
				
			||||||
    {NULL, NULL}
 | 
					    {NULL, NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,8 +55,19 @@ ImagingGetBBox(Imaging im, int bbox[4])
 | 
				
			||||||
	GETBBOX(image8, 0xff);
 | 
						GETBBOX(image8, 0xff);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
	INT32 mask = 0xffffffff;
 | 
						INT32 mask = 0xffffffff;
 | 
				
			||||||
	if (im->bands == 3)
 | 
						if (im->bands == 3) {
 | 
				
			||||||
	    ((UINT8*) &mask)[3] = 0;
 | 
						    ((UINT8*) &mask)[3] = 0;
 | 
				
			||||||
 | 
						} else if (strcmp(im->mode, "RGBa") == 0 ||
 | 
				
			||||||
 | 
						           strcmp(im->mode, "RGBA") == 0 ||
 | 
				
			||||||
 | 
						           strcmp(im->mode, "La") == 0 ||
 | 
				
			||||||
 | 
						           strcmp(im->mode, "LA") == 0 ||
 | 
				
			||||||
 | 
						           strcmp(im->mode, "PA") == 0) {
 | 
				
			||||||
 | 
					#ifdef WORDS_BIGENDIAN
 | 
				
			||||||
 | 
						    mask = 0x000000ff;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						    mask = 0xff000000;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	GETBBOX(image32, mask);
 | 
						GETBBOX(image32, mask);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user