mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 02:06:18 +03:00
Convert to use pytest
This commit is contained in:
parent
54b4b98455
commit
2cc6a9a974
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -101,13 +99,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 +138,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 +164,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 +182,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 +200,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 +299,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 +344,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 +387,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 +468,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 +494,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 +516,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 +553,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 +575,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 +688,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
|
# These two test pre-written JPEG 2000 files that were not written with
|
||||||
# PIL (they were made using Adobe Photoshop)
|
# PIL (they were made using Adobe Photoshop)
|
||||||
|
|
||||||
def test_lossless(self):
|
|
||||||
|
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")
|
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
|
||||||
def test_16bit_monochrome_jp2_like_tiff(self):
|
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")
|
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
|
||||||
def test_16bit_monochrome_j2k_like_tiff(self):
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestFilePalm(PillowTestCase):
|
|
||||||
_roundtrip = imagemagick_available()
|
_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,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,
|
||||||
assert_image_similar,
|
assert_image_similar,
|
||||||
|
@ -56,7 +54,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:
|
||||||
|
@ -73,12 +71,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)
|
||||||
|
|
||||||
|
@ -233,14 +231,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
|
||||||
|
@ -254,14 +252,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
|
||||||
|
@ -277,14 +275,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
|
||||||
|
@ -295,7 +293,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:
|
||||||
|
@ -305,7 +303,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:
|
||||||
|
@ -316,10 +314,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):
|
||||||
|
@ -484,12 +482,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:
|
||||||
|
@ -540,9 +538,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)
|
||||||
|
@ -599,27 +597,27 @@ 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:
|
||||||
|
@ -636,7 +634,7 @@ class TestFilePng(PillowTestCase):
|
||||||
assert_image_similar(im, expected, 0.23)
|
assert_image_similar(im, expected, 0.23)
|
||||||
|
|
||||||
|
|
||||||
@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,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,13 +510,16 @@ 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)
|
||||||
|
|
||||||
|
for mode in ["P", "PA"]:
|
||||||
|
roundtrip(mode)
|
||||||
|
|
||||||
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"))
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
|
|
@ -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,7 +21,7 @@ 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
|
||||||
|
@ -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,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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user