mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Removed use of PillowTestCase
This commit is contained in:
parent
7859f81828
commit
7ff2db143d
|
@ -7,267 +7,280 @@ import time
|
|||
import pytest
|
||||
from PIL import Image, PdfParser
|
||||
|
||||
from .helper import PillowTestCase, hopper
|
||||
from .helper import hopper
|
||||
|
||||
|
||||
class TestFilePdf(PillowTestCase):
|
||||
def helper_save_as_pdf(self, mode, **kwargs):
|
||||
# Arrange
|
||||
im = hopper(mode)
|
||||
outfile = self.tempfile("temp_" + mode + ".pdf")
|
||||
def helper_save_as_pdf(tmp_path, mode, **kwargs):
|
||||
# Arrange
|
||||
im = hopper(mode)
|
||||
outfile = str(tmp_path / ("temp_" + mode + ".pdf"))
|
||||
|
||||
# Act
|
||||
im.save(outfile, **kwargs)
|
||||
# Act
|
||||
im.save(outfile, **kwargs)
|
||||
|
||||
# Assert
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
with PdfParser.PdfParser(outfile) as pdf:
|
||||
if kwargs.get("append_images", False) or kwargs.get("append", False):
|
||||
assert len(pdf.pages) > 1
|
||||
else:
|
||||
assert len(pdf.pages) > 0
|
||||
with open(outfile, "rb") as fp:
|
||||
contents = fp.read()
|
||||
size = tuple(
|
||||
int(d)
|
||||
for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
|
||||
)
|
||||
assert im.size == size
|
||||
# Assert
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
with PdfParser.PdfParser(outfile) as pdf:
|
||||
if kwargs.get("append_images", False) or kwargs.get("append", False):
|
||||
assert len(pdf.pages) > 1
|
||||
else:
|
||||
assert len(pdf.pages) > 0
|
||||
with open(outfile, "rb") as fp:
|
||||
contents = fp.read()
|
||||
size = tuple(
|
||||
int(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
|
||||
)
|
||||
assert im.size == size
|
||||
|
||||
return outfile
|
||||
return outfile
|
||||
|
||||
def test_monochrome(self):
|
||||
# Arrange
|
||||
mode = "1"
|
||||
|
||||
# Act / Assert
|
||||
self.helper_save_as_pdf(mode)
|
||||
def test_monochrome(tmp_path):
|
||||
# Arrange
|
||||
mode = "1"
|
||||
|
||||
def test_greyscale(self):
|
||||
# Arrange
|
||||
mode = "L"
|
||||
# Act / Assert
|
||||
helper_save_as_pdf(tmp_path, mode)
|
||||
|
||||
# Act / Assert
|
||||
self.helper_save_as_pdf(mode)
|
||||
|
||||
def test_rgb(self):
|
||||
# Arrange
|
||||
mode = "RGB"
|
||||
def test_greyscale(tmp_path):
|
||||
# Arrange
|
||||
mode = "L"
|
||||
|
||||
# Act / Assert
|
||||
self.helper_save_as_pdf(mode)
|
||||
# Act / Assert
|
||||
helper_save_as_pdf(tmp_path, mode)
|
||||
|
||||
def test_p_mode(self):
|
||||
# Arrange
|
||||
mode = "P"
|
||||
|
||||
# Act / Assert
|
||||
self.helper_save_as_pdf(mode)
|
||||
def test_rgb(tmp_path):
|
||||
# Arrange
|
||||
mode = "RGB"
|
||||
|
||||
def test_cmyk_mode(self):
|
||||
# Arrange
|
||||
mode = "CMYK"
|
||||
# Act / Assert
|
||||
helper_save_as_pdf(tmp_path, mode)
|
||||
|
||||
# Act / Assert
|
||||
self.helper_save_as_pdf(mode)
|
||||
|
||||
def test_unsupported_mode(self):
|
||||
im = hopper("LA")
|
||||
outfile = self.tempfile("temp_LA.pdf")
|
||||
def test_p_mode(tmp_path):
|
||||
# Arrange
|
||||
mode = "P"
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
im.save(outfile)
|
||||
# Act / Assert
|
||||
helper_save_as_pdf(tmp_path, mode)
|
||||
|
||||
def test_save_all(self):
|
||||
# Single frame image
|
||||
self.helper_save_as_pdf("RGB", save_all=True)
|
||||
|
||||
# Multiframe image
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
def test_cmyk_mode(tmp_path):
|
||||
# Arrange
|
||||
mode = "CMYK"
|
||||
|
||||
outfile = self.tempfile("temp.pdf")
|
||||
im.save(outfile, save_all=True)
|
||||
# Act / Assert
|
||||
helper_save_as_pdf(tmp_path, mode)
|
||||
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
|
||||
# Append images
|
||||
ims = [hopper()]
|
||||
im.copy().save(outfile, save_all=True, append_images=ims)
|
||||
def test_unsupported_mode(tmp_path):
|
||||
im = hopper("LA")
|
||||
outfile = str(tmp_path / "temp_LA.pdf")
|
||||
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
with pytest.raises(ValueError):
|
||||
im.save(outfile)
|
||||
|
||||
# Test appending using a generator
|
||||
def imGenerator(ims):
|
||||
yield from ims
|
||||
|
||||
im.save(outfile, save_all=True, append_images=imGenerator(ims))
|
||||
def test_save_all(tmp_path):
|
||||
# Single frame image
|
||||
helper_save_as_pdf(tmp_path, "RGB", save_all=True)
|
||||
|
||||
# Multiframe image
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
|
||||
outfile = str(tmp_path / "temp.pdf")
|
||||
im.save(outfile, save_all=True)
|
||||
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
|
||||
# Append JPEG images
|
||||
with Image.open("Tests/images/flower.jpg") as jpeg:
|
||||
jpeg.save(outfile, save_all=True, append_images=[jpeg.copy()])
|
||||
# Append images
|
||||
ims = [hopper()]
|
||||
im.copy().save(outfile, save_all=True, append_images=ims)
|
||||
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
|
||||
def test_multiframe_normal_save(self):
|
||||
# Test saving a multiframe image without save_all
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
# Test appending using a generator
|
||||
def imGenerator(ims):
|
||||
yield from ims
|
||||
|
||||
outfile = self.tempfile("temp.pdf")
|
||||
im.save(outfile)
|
||||
im.save(outfile, save_all=True, append_images=imGenerator(ims))
|
||||
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
|
||||
def test_pdf_open(self):
|
||||
# fail on a buffer full of null bytes
|
||||
with pytest.raises(PdfParser.PdfFormatError):
|
||||
PdfParser.PdfParser(buf=bytearray(65536))
|
||||
# Append JPEG images
|
||||
with Image.open("Tests/images/flower.jpg") as jpeg:
|
||||
jpeg.save(outfile, save_all=True, append_images=[jpeg.copy()])
|
||||
|
||||
# make an empty PDF object
|
||||
with PdfParser.PdfParser() as empty_pdf:
|
||||
assert len(empty_pdf.pages) == 0
|
||||
assert len(empty_pdf.info) == 0
|
||||
assert not empty_pdf.should_close_buf
|
||||
assert not empty_pdf.should_close_file
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
|
||||
# make a PDF file
|
||||
pdf_filename = self.helper_save_as_pdf("RGB")
|
||||
|
||||
# open the PDF file
|
||||
with PdfParser.PdfParser(filename=pdf_filename) as hopper_pdf:
|
||||
def test_multiframe_normal_save(tmp_path):
|
||||
# Test saving a multiframe image without save_all
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
|
||||
outfile = str(tmp_path / "temp.pdf")
|
||||
im.save(outfile)
|
||||
|
||||
assert os.path.isfile(outfile)
|
||||
assert os.path.getsize(outfile) > 0
|
||||
|
||||
|
||||
def test_pdf_open(tmp_path):
|
||||
# fail on a buffer full of null bytes
|
||||
with pytest.raises(PdfParser.PdfFormatError):
|
||||
PdfParser.PdfParser(buf=bytearray(65536))
|
||||
|
||||
# make an empty PDF object
|
||||
with PdfParser.PdfParser() as empty_pdf:
|
||||
assert len(empty_pdf.pages) == 0
|
||||
assert len(empty_pdf.info) == 0
|
||||
assert not empty_pdf.should_close_buf
|
||||
assert not empty_pdf.should_close_file
|
||||
|
||||
# make a PDF file
|
||||
pdf_filename = helper_save_as_pdf(tmp_path, "RGB")
|
||||
|
||||
# open the PDF file
|
||||
with PdfParser.PdfParser(filename=pdf_filename) as hopper_pdf:
|
||||
assert len(hopper_pdf.pages) == 1
|
||||
assert hopper_pdf.should_close_buf
|
||||
assert hopper_pdf.should_close_file
|
||||
|
||||
# read a PDF file from a buffer with a non-zero offset
|
||||
with open(pdf_filename, "rb") as f:
|
||||
content = b"xyzzy" + f.read()
|
||||
with PdfParser.PdfParser(buf=content, start_offset=5) as hopper_pdf:
|
||||
assert len(hopper_pdf.pages) == 1
|
||||
assert not hopper_pdf.should_close_buf
|
||||
assert not hopper_pdf.should_close_file
|
||||
|
||||
# read a PDF file from an already open file
|
||||
with open(pdf_filename, "rb") as f:
|
||||
with PdfParser.PdfParser(f=f) as hopper_pdf:
|
||||
assert len(hopper_pdf.pages) == 1
|
||||
assert hopper_pdf.should_close_buf
|
||||
assert hopper_pdf.should_close_file
|
||||
|
||||
# read a PDF file from a buffer with a non-zero offset
|
||||
with open(pdf_filename, "rb") as f:
|
||||
content = b"xyzzy" + f.read()
|
||||
with PdfParser.PdfParser(buf=content, start_offset=5) as hopper_pdf:
|
||||
assert len(hopper_pdf.pages) == 1
|
||||
assert not hopper_pdf.should_close_buf
|
||||
assert not hopper_pdf.should_close_file
|
||||
|
||||
# read a PDF file from an already open file
|
||||
with open(pdf_filename, "rb") as f:
|
||||
with PdfParser.PdfParser(f=f) as hopper_pdf:
|
||||
assert len(hopper_pdf.pages) == 1
|
||||
assert hopper_pdf.should_close_buf
|
||||
assert not hopper_pdf.should_close_file
|
||||
|
||||
def test_pdf_append_fails_on_nonexistent_file(self):
|
||||
im = hopper("RGB")
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
with pytest.raises(IOError):
|
||||
im.save(os.path.join(temp_dir, "nonexistent.pdf"), append=True)
|
||||
def test_pdf_append_fails_on_nonexistent_file():
|
||||
im = hopper("RGB")
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
with pytest.raises(IOError):
|
||||
im.save(os.path.join(temp_dir, "nonexistent.pdf"), append=True)
|
||||
|
||||
def check_pdf_pages_consistency(self, pdf):
|
||||
pages_info = pdf.read_indirect(pdf.pages_ref)
|
||||
assert b"Parent" not in pages_info
|
||||
assert b"Kids" in pages_info
|
||||
kids_not_used = pages_info[b"Kids"]
|
||||
for page_ref in pdf.pages:
|
||||
while True:
|
||||
if page_ref in kids_not_used:
|
||||
kids_not_used.remove(page_ref)
|
||||
page_info = pdf.read_indirect(page_ref)
|
||||
assert b"Parent" in page_info
|
||||
page_ref = page_info[b"Parent"]
|
||||
if page_ref == pdf.pages_ref:
|
||||
break
|
||||
assert pdf.pages_ref == page_info[b"Parent"]
|
||||
assert kids_not_used == []
|
||||
|
||||
def test_pdf_append(self):
|
||||
# make a PDF file
|
||||
pdf_filename = self.helper_save_as_pdf("RGB", producer="PdfParser")
|
||||
def check_pdf_pages_consistency(pdf):
|
||||
pages_info = pdf.read_indirect(pdf.pages_ref)
|
||||
assert b"Parent" not in pages_info
|
||||
assert b"Kids" in pages_info
|
||||
kids_not_used = pages_info[b"Kids"]
|
||||
for page_ref in pdf.pages:
|
||||
while True:
|
||||
if page_ref in kids_not_used:
|
||||
kids_not_used.remove(page_ref)
|
||||
page_info = pdf.read_indirect(page_ref)
|
||||
assert b"Parent" in page_info
|
||||
page_ref = page_info[b"Parent"]
|
||||
if page_ref == pdf.pages_ref:
|
||||
break
|
||||
assert pdf.pages_ref == page_info[b"Parent"]
|
||||
assert kids_not_used == []
|
||||
|
||||
# open it, check pages and info
|
||||
with PdfParser.PdfParser(pdf_filename, mode="r+b") as pdf:
|
||||
assert len(pdf.pages) == 1
|
||||
assert len(pdf.info) == 4
|
||||
assert pdf.info.Title == os.path.splitext(os.path.basename(pdf_filename))[0]
|
||||
assert pdf.info.Producer == "PdfParser"
|
||||
assert b"CreationDate" in pdf.info
|
||||
assert b"ModDate" in pdf.info
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
|
||||
# append some info
|
||||
pdf.info.Title = "abc"
|
||||
pdf.info.Author = "def"
|
||||
pdf.info.Subject = "ghi\uABCD"
|
||||
pdf.info.Keywords = "qw)e\\r(ty"
|
||||
pdf.info.Creator = "hopper()"
|
||||
pdf.start_writing()
|
||||
pdf.write_xref_and_trailer()
|
||||
def test_pdf_append(tmp_path):
|
||||
# make a PDF file
|
||||
pdf_filename = helper_save_as_pdf(tmp_path, "RGB", producer="PdfParser")
|
||||
|
||||
# open it again, check pages and info again
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
assert len(pdf.pages) == 1
|
||||
assert len(pdf.info) == 8
|
||||
assert pdf.info.Title == "abc"
|
||||
assert b"CreationDate" in pdf.info
|
||||
assert b"ModDate" in pdf.info
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
# open it, check pages and info
|
||||
with PdfParser.PdfParser(pdf_filename, mode="r+b") as pdf:
|
||||
assert len(pdf.pages) == 1
|
||||
assert len(pdf.info) == 4
|
||||
assert pdf.info.Title == os.path.splitext(os.path.basename(pdf_filename))[0]
|
||||
assert pdf.info.Producer == "PdfParser"
|
||||
assert b"CreationDate" in pdf.info
|
||||
assert b"ModDate" in pdf.info
|
||||
check_pdf_pages_consistency(pdf)
|
||||
|
||||
# append two images
|
||||
mode_CMYK = hopper("CMYK")
|
||||
mode_P = hopper("P")
|
||||
mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P])
|
||||
# append some info
|
||||
pdf.info.Title = "abc"
|
||||
pdf.info.Author = "def"
|
||||
pdf.info.Subject = "ghi\uABCD"
|
||||
pdf.info.Keywords = "qw)e\\r(ty"
|
||||
pdf.info.Creator = "hopper()"
|
||||
pdf.start_writing()
|
||||
pdf.write_xref_and_trailer()
|
||||
|
||||
# open the PDF again, check pages and info again
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
assert len(pdf.pages) == 3
|
||||
assert len(pdf.info) == 8
|
||||
assert PdfParser.decode_text(pdf.info[b"Title"]) == "abc"
|
||||
assert pdf.info.Title == "abc"
|
||||
assert pdf.info.Producer == "PdfParser"
|
||||
assert pdf.info.Keywords == "qw)e\\r(ty"
|
||||
assert pdf.info.Subject == "ghi\uABCD"
|
||||
assert b"CreationDate" in pdf.info
|
||||
assert b"ModDate" in pdf.info
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
# open it again, check pages and info again
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
assert len(pdf.pages) == 1
|
||||
assert len(pdf.info) == 8
|
||||
assert pdf.info.Title == "abc"
|
||||
assert b"CreationDate" in pdf.info
|
||||
assert b"ModDate" in pdf.info
|
||||
check_pdf_pages_consistency(pdf)
|
||||
|
||||
def test_pdf_info(self):
|
||||
# make a PDF file
|
||||
pdf_filename = self.helper_save_as_pdf(
|
||||
"RGB",
|
||||
title="title",
|
||||
author="author",
|
||||
subject="subject",
|
||||
keywords="keywords",
|
||||
creator="creator",
|
||||
producer="producer",
|
||||
creationDate=time.strptime("2000", "%Y"),
|
||||
modDate=time.strptime("2001", "%Y"),
|
||||
)
|
||||
# append two images
|
||||
mode_CMYK = hopper("CMYK")
|
||||
mode_P = hopper("P")
|
||||
mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P])
|
||||
|
||||
# open it, check pages and info
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
assert len(pdf.info) == 8
|
||||
assert pdf.info.Title == "title"
|
||||
assert pdf.info.Author == "author"
|
||||
assert pdf.info.Subject == "subject"
|
||||
assert pdf.info.Keywords == "keywords"
|
||||
assert pdf.info.Creator == "creator"
|
||||
assert pdf.info.Producer == "producer"
|
||||
assert pdf.info.CreationDate == time.strptime("2000", "%Y")
|
||||
assert pdf.info.ModDate == time.strptime("2001", "%Y")
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
# open the PDF again, check pages and info again
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
assert len(pdf.pages) == 3
|
||||
assert len(pdf.info) == 8
|
||||
assert PdfParser.decode_text(pdf.info[b"Title"]) == "abc"
|
||||
assert pdf.info.Title == "abc"
|
||||
assert pdf.info.Producer == "PdfParser"
|
||||
assert pdf.info.Keywords == "qw)e\\r(ty"
|
||||
assert pdf.info.Subject == "ghi\uABCD"
|
||||
assert b"CreationDate" in pdf.info
|
||||
assert b"ModDate" in pdf.info
|
||||
check_pdf_pages_consistency(pdf)
|
||||
|
||||
def test_pdf_append_to_bytesio(self):
|
||||
im = hopper("RGB")
|
||||
f = io.BytesIO()
|
||||
im.save(f, format="PDF")
|
||||
initial_size = len(f.getvalue())
|
||||
assert initial_size > 0
|
||||
im = hopper("P")
|
||||
f = io.BytesIO(f.getvalue())
|
||||
im.save(f, format="PDF", append=True)
|
||||
assert len(f.getvalue()) > initial_size
|
||||
|
||||
def test_pdf_info(tmp_path):
|
||||
# make a PDF file
|
||||
pdf_filename = helper_save_as_pdf(
|
||||
tmp_path,
|
||||
"RGB",
|
||||
title="title",
|
||||
author="author",
|
||||
subject="subject",
|
||||
keywords="keywords",
|
||||
creator="creator",
|
||||
producer="producer",
|
||||
creationDate=time.strptime("2000", "%Y"),
|
||||
modDate=time.strptime("2001", "%Y"),
|
||||
)
|
||||
|
||||
# open it, check pages and info
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
assert len(pdf.info) == 8
|
||||
assert pdf.info.Title == "title"
|
||||
assert pdf.info.Author == "author"
|
||||
assert pdf.info.Subject == "subject"
|
||||
assert pdf.info.Keywords == "keywords"
|
||||
assert pdf.info.Creator == "creator"
|
||||
assert pdf.info.Producer == "producer"
|
||||
assert pdf.info.CreationDate == time.strptime("2000", "%Y")
|
||||
assert pdf.info.ModDate == time.strptime("2001", "%Y")
|
||||
check_pdf_pages_consistency(pdf)
|
||||
|
||||
|
||||
def test_pdf_append_to_bytesio():
|
||||
im = hopper("RGB")
|
||||
f = io.BytesIO()
|
||||
im.save(f, format="PDF")
|
||||
initial_size = len(f.getvalue())
|
||||
assert initial_size > 0
|
||||
im = hopper("P")
|
||||
f = io.BytesIO(f.getvalue())
|
||||
im.save(f, format="PDF", append=True)
|
||||
assert len(f.getvalue()) > initial_size
|
||||
|
|
|
@ -5,204 +5,202 @@ from itertools import product
|
|||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
||||
from .helper import assert_image_equal, hopper
|
||||
|
||||
_TGA_DIR = os.path.join("Tests", "images", "tga")
|
||||
_TGA_DIR_COMMON = os.path.join(_TGA_DIR, "common")
|
||||
|
||||
|
||||
class TestFileTga(PillowTestCase):
|
||||
_MODES = ("L", "LA", "P", "RGB", "RGBA")
|
||||
_ORIGINS = ("tl", "bl")
|
||||
|
||||
_MODES = ("L", "LA", "P", "RGB", "RGBA")
|
||||
_ORIGINS = ("tl", "bl")
|
||||
_ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
|
||||
|
||||
_ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
|
||||
|
||||
def test_sanity(self):
|
||||
for mode in self._MODES:
|
||||
png_paths = glob(
|
||||
os.path.join(_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower()))
|
||||
)
|
||||
def test_sanity(tmp_path):
|
||||
for mode in _MODES:
|
||||
|
||||
for png_path in png_paths:
|
||||
with Image.open(png_path) as reference_im:
|
||||
assert reference_im.mode == mode
|
||||
def roundtrip(original_im):
|
||||
out = str(tmp_path / "temp.tga")
|
||||
|
||||
path_no_ext = os.path.splitext(png_path)[0]
|
||||
for origin, rle in product(self._ORIGINS, (True, False)):
|
||||
tga_path = "{}_{}_{}.tga".format(
|
||||
path_no_ext, origin, "rle" if rle else "raw"
|
||||
original_im.save(out, rle=rle)
|
||||
with Image.open(out) as saved_im:
|
||||
if rle:
|
||||
assert (
|
||||
saved_im.info["compression"] == original_im.info["compression"]
|
||||
)
|
||||
assert saved_im.info["orientation"] == original_im.info["orientation"]
|
||||
if mode == "P":
|
||||
assert saved_im.getpalette() == original_im.getpalette()
|
||||
|
||||
assert_image_equal(saved_im, original_im)
|
||||
|
||||
png_paths = glob(
|
||||
os.path.join(_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower()))
|
||||
)
|
||||
|
||||
for png_path in png_paths:
|
||||
with Image.open(png_path) as reference_im:
|
||||
assert reference_im.mode == mode
|
||||
|
||||
path_no_ext = os.path.splitext(png_path)[0]
|
||||
for origin, rle in product(_ORIGINS, (True, False)):
|
||||
tga_path = "{}_{}_{}.tga".format(
|
||||
path_no_ext, origin, "rle" if rle else "raw"
|
||||
)
|
||||
|
||||
with Image.open(tga_path) as original_im:
|
||||
assert original_im.format == "TGA"
|
||||
assert original_im.get_format_mimetype() == "image/x-tga"
|
||||
if rle:
|
||||
assert original_im.info["compression"] == "tga_rle"
|
||||
assert (
|
||||
original_im.info["orientation"]
|
||||
== _ORIGIN_TO_ORIENTATION[origin]
|
||||
)
|
||||
if mode == "P":
|
||||
assert original_im.getpalette() == reference_im.getpalette()
|
||||
|
||||
with Image.open(tga_path) as original_im:
|
||||
assert original_im.format == "TGA"
|
||||
assert original_im.get_format_mimetype() == "image/x-tga"
|
||||
if rle:
|
||||
assert original_im.info["compression"] == "tga_rle"
|
||||
assert (
|
||||
original_im.info["orientation"]
|
||||
== self._ORIGIN_TO_ORIENTATION[origin]
|
||||
)
|
||||
if mode == "P":
|
||||
assert (
|
||||
original_im.getpalette()
|
||||
== reference_im.getpalette()
|
||||
)
|
||||
assert_image_equal(original_im, reference_im)
|
||||
|
||||
assert_image_equal(original_im, reference_im)
|
||||
roundtrip(original_im)
|
||||
|
||||
# Generate a new test name every time so the
|
||||
# test will not fail with permission error
|
||||
# on Windows.
|
||||
out = self.tempfile("temp.tga")
|
||||
|
||||
original_im.save(out, rle=rle)
|
||||
with Image.open(out) as saved_im:
|
||||
if rle:
|
||||
assert (
|
||||
saved_im.info["compression"]
|
||||
== original_im.info["compression"]
|
||||
)
|
||||
assert (
|
||||
saved_im.info["orientation"]
|
||||
== original_im.info["orientation"]
|
||||
)
|
||||
if mode == "P":
|
||||
assert (
|
||||
saved_im.getpalette()
|
||||
== original_im.getpalette()
|
||||
)
|
||||
def test_id_field():
|
||||
# tga file with id field
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
|
||||
assert_image_equal(saved_im, original_im)
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
def test_id_field(self):
|
||||
# tga file with id field
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
# Assert
|
||||
assert im.size == (100, 100)
|
||||
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Assert
|
||||
assert im.size == (100, 100)
|
||||
def test_id_field_rle():
|
||||
# tga file with id field
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
|
||||
def test_id_field_rle(self):
|
||||
# tga file with id field
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
# Assert
|
||||
assert im.size == (199, 199)
|
||||
|
||||
# Assert
|
||||
assert im.size == (199, 199)
|
||||
|
||||
def test_save(self):
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
out = self.tempfile("temp.tga")
|
||||
def test_save(tmp_path):
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
out = str(tmp_path / "temp.tga")
|
||||
|
||||
# Save
|
||||
im.save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (100, 100)
|
||||
assert test_im.info["id_section"] == im.info["id_section"]
|
||||
|
||||
# RGBA save
|
||||
im.convert("RGBA").save(out)
|
||||
# Save
|
||||
im.save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (100, 100)
|
||||
|
||||
def test_save_wrong_mode(self):
|
||||
im = hopper("PA")
|
||||
out = self.tempfile("temp.tga")
|
||||
|
||||
with pytest.raises(OSError):
|
||||
im.save(out)
|
||||
|
||||
def test_save_id_section(self):
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
with Image.open(test_file) as im:
|
||||
out = self.tempfile("temp.tga")
|
||||
|
||||
# Check there is no id section
|
||||
im.save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert "id_section" not in test_im.info
|
||||
|
||||
# Save with custom id section
|
||||
im.save(out, id_section=b"Test content")
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["id_section"] == b"Test content"
|
||||
|
||||
# Save with custom id section greater than 255 characters
|
||||
id_section = b"Test content" * 25
|
||||
pytest.warns(UserWarning, lambda: im.save(out, id_section=id_section))
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["id_section"] == id_section[:255]
|
||||
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Save with no id section
|
||||
im.save(out, id_section="")
|
||||
with Image.open(out) as test_im:
|
||||
assert "id_section" not in test_im.info
|
||||
|
||||
def test_save_orientation(self):
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
out = self.tempfile("temp.tga")
|
||||
with Image.open(test_file) as im:
|
||||
assert im.info["orientation"] == -1
|
||||
|
||||
im.save(out, orientation=1)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["orientation"] == 1
|
||||
|
||||
def test_save_rle(self):
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
with Image.open(test_file) as im:
|
||||
assert im.info["compression"] == "tga_rle"
|
||||
|
||||
out = self.tempfile("temp.tga")
|
||||
|
||||
# Save
|
||||
im.save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (199, 199)
|
||||
assert test_im.info["compression"] == "tga_rle"
|
||||
|
||||
# Save without compression
|
||||
im.save(out, compression=None)
|
||||
with Image.open(out) as test_im:
|
||||
assert "compression" not in test_im.info
|
||||
assert test_im.info["id_section"] == im.info["id_section"]
|
||||
|
||||
# RGBA save
|
||||
im.convert("RGBA").save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (199, 199)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (100, 100)
|
||||
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
assert "compression" not in im.info
|
||||
|
||||
# Save with compression
|
||||
im.save(out, compression="tga_rle")
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["compression"] == "tga_rle"
|
||||
def test_save_wrong_mode(tmp_path):
|
||||
im = hopper("PA")
|
||||
out = str(tmp_path / "temp.tga")
|
||||
|
||||
def test_save_l_transparency(self):
|
||||
# There are 559 transparent pixels in la.tga.
|
||||
num_transparent = 559
|
||||
with pytest.raises(OSError):
|
||||
im.save(out)
|
||||
|
||||
in_file = "Tests/images/la.tga"
|
||||
with Image.open(in_file) as im:
|
||||
assert im.mode == "LA"
|
||||
assert im.getchannel("A").getcolors()[0][0] == num_transparent
|
||||
|
||||
out = self.tempfile("temp.tga")
|
||||
im.save(out)
|
||||
def test_save_id_section(tmp_path):
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
with Image.open(test_file) as im:
|
||||
out = str(tmp_path / "temp.tga")
|
||||
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.mode == "LA"
|
||||
assert test_im.getchannel("A").getcolors()[0][0] == num_transparent
|
||||
# Check there is no id section
|
||||
im.save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert "id_section" not in test_im.info
|
||||
|
||||
assert_image_equal(im, test_im)
|
||||
# Save with custom id section
|
||||
im.save(out, id_section=b"Test content")
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["id_section"] == b"Test content"
|
||||
|
||||
# Save with custom id section greater than 255 characters
|
||||
id_section = b"Test content" * 25
|
||||
pytest.warns(UserWarning, lambda: im.save(out, id_section=id_section))
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["id_section"] == id_section[:255]
|
||||
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Save with no id section
|
||||
im.save(out, id_section="")
|
||||
with Image.open(out) as test_im:
|
||||
assert "id_section" not in test_im.info
|
||||
|
||||
|
||||
def test_save_orientation(tmp_path):
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
out = str(tmp_path / "temp.tga")
|
||||
with Image.open(test_file) as im:
|
||||
assert im.info["orientation"] == -1
|
||||
|
||||
im.save(out, orientation=1)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["orientation"] == 1
|
||||
|
||||
|
||||
def test_save_rle(tmp_path):
|
||||
test_file = "Tests/images/rgb32rle.tga"
|
||||
with Image.open(test_file) as im:
|
||||
assert im.info["compression"] == "tga_rle"
|
||||
|
||||
out = str(tmp_path / "temp.tga")
|
||||
|
||||
# Save
|
||||
im.save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (199, 199)
|
||||
assert test_im.info["compression"] == "tga_rle"
|
||||
|
||||
# Save without compression
|
||||
im.save(out, compression=None)
|
||||
with Image.open(out) as test_im:
|
||||
assert "compression" not in test_im.info
|
||||
|
||||
# RGBA save
|
||||
im.convert("RGBA").save(out)
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.size == (199, 199)
|
||||
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
assert "compression" not in im.info
|
||||
|
||||
# Save with compression
|
||||
im.save(out, compression="tga_rle")
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.info["compression"] == "tga_rle"
|
||||
|
||||
|
||||
def test_save_l_transparency(tmp_path):
|
||||
# There are 559 transparent pixels in la.tga.
|
||||
num_transparent = 559
|
||||
|
||||
in_file = "Tests/images/la.tga"
|
||||
with Image.open(in_file) as im:
|
||||
assert im.mode == "LA"
|
||||
assert im.getchannel("A").getcolors()[0][0] == num_transparent
|
||||
|
||||
out = str(tmp_path / "temp.tga")
|
||||
im.save(out)
|
||||
|
||||
with Image.open(out) as test_im:
|
||||
assert test_im.mode == "LA"
|
||||
assert test_im.getchannel("A").getcolors()[0][0] == num_transparent
|
||||
|
||||
assert_image_equal(im, test_im)
|
||||
|
|
|
@ -2,7 +2,6 @@ import pytest
|
|||
from PIL import Image, WebPImagePlugin
|
||||
|
||||
from .helper import (
|
||||
PillowTestCase,
|
||||
assert_image_similar,
|
||||
assert_image_similar_tofile,
|
||||
hopper,
|
||||
|
@ -17,23 +16,21 @@ except ImportError:
|
|||
HAVE_WEBP = False
|
||||
|
||||
|
||||
class TestUnsupportedWebp(PillowTestCase):
|
||||
class TestUnsupportedWebp:
|
||||
def test_unsupported(self):
|
||||
if HAVE_WEBP:
|
||||
WebPImagePlugin.SUPPORTED = False
|
||||
|
||||
file_path = "Tests/images/hopper.webp"
|
||||
pytest.warns(
|
||||
UserWarning, lambda: self.assertRaises(IOError, Image.open, file_path)
|
||||
)
|
||||
pytest.warns(UserWarning, lambda: pytest.raises(IOError, Image.open, file_path))
|
||||
|
||||
if HAVE_WEBP:
|
||||
WebPImagePlugin.SUPPORTED = True
|
||||
|
||||
|
||||
@skip_unless_feature("webp")
|
||||
class TestFileWebp(PillowTestCase):
|
||||
def setUp(self):
|
||||
class TestFileWebp:
|
||||
def setup_method(self):
|
||||
self.rgb_mode = "RGB"
|
||||
|
||||
def test_version(self):
|
||||
|
@ -57,13 +54,13 @@ class TestFileWebp(PillowTestCase):
|
|||
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
|
||||
assert_image_similar_tofile(image, "Tests/images/hopper_webp_bits.ppm", 1.0)
|
||||
|
||||
def test_write_rgb(self):
|
||||
def test_write_rgb(self, tmp_path):
|
||||
"""
|
||||
Can we write a RGB mode file to webp without error.
|
||||
Does it have the bits we expect?
|
||||
"""
|
||||
|
||||
temp_file = self.tempfile("temp.webp")
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
|
||||
hopper(self.rgb_mode).save(temp_file)
|
||||
with Image.open(temp_file) as image:
|
||||
|
@ -86,13 +83,13 @@ class TestFileWebp(PillowTestCase):
|
|||
target = hopper(self.rgb_mode)
|
||||
assert_image_similar(image, target, 12.0)
|
||||
|
||||
def test_write_unsupported_mode_L(self):
|
||||
def test_write_unsupported_mode_L(self, tmp_path):
|
||||
"""
|
||||
Saving a black-and-white file to WebP format should work, and be
|
||||
similar to the original file.
|
||||
"""
|
||||
|
||||
temp_file = self.tempfile("temp.webp")
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
hopper("L").save(temp_file)
|
||||
with Image.open(temp_file) as image:
|
||||
assert image.mode == self.rgb_mode
|
||||
|
@ -105,13 +102,13 @@ class TestFileWebp(PillowTestCase):
|
|||
|
||||
assert_image_similar(image, target, 10.0)
|
||||
|
||||
def test_write_unsupported_mode_P(self):
|
||||
def test_write_unsupported_mode_P(self, tmp_path):
|
||||
"""
|
||||
Saving a palette-based file to WebP format should work, and be
|
||||
similar to the original file.
|
||||
"""
|
||||
|
||||
temp_file = self.tempfile("temp.webp")
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
hopper("P").save(temp_file)
|
||||
with Image.open(temp_file) as image:
|
||||
assert image.mode == self.rgb_mode
|
||||
|
@ -146,10 +143,10 @@ class TestFileWebp(PillowTestCase):
|
|||
with pytest.raises(TypeError):
|
||||
_webp.WebPDecode()
|
||||
|
||||
def test_no_resource_warning(self):
|
||||
def test_no_resource_warning(self, tmp_path):
|
||||
file_path = "Tests/images/hopper.webp"
|
||||
with Image.open(file_path) as image:
|
||||
temp_file = self.tempfile("temp.webp")
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
pytest.warns(None, image.save, temp_file)
|
||||
|
||||
def test_file_pointer_could_be_reused(self):
|
||||
|
@ -160,16 +157,16 @@ class TestFileWebp(PillowTestCase):
|
|||
|
||||
@skip_unless_feature("webp")
|
||||
@skip_unless_feature("webp_anim")
|
||||
def test_background_from_gif(self):
|
||||
def test_background_from_gif(self, tmp_path):
|
||||
with Image.open("Tests/images/chi.gif") as im:
|
||||
original_value = im.convert("RGB").getpixel((1, 1))
|
||||
|
||||
# Save as WEBP
|
||||
out_webp = self.tempfile("temp.webp")
|
||||
out_webp = str(tmp_path / "temp.webp")
|
||||
im.save(out_webp, save_all=True)
|
||||
|
||||
# Save as GIF
|
||||
out_gif = self.tempfile("temp.gif")
|
||||
out_gif = str(tmp_path / "temp.gif")
|
||||
Image.open(out_webp).save(out_gif)
|
||||
|
||||
with Image.open(out_gif) as reread:
|
||||
|
|
|
@ -1,238 +1,249 @@
|
|||
import pytest
|
||||
from PIL import Image, ImageMath, ImageMode
|
||||
|
||||
from .helper import PillowTestCase, convert_to_comparable
|
||||
from .helper import convert_to_comparable
|
||||
|
||||
# There are several internal implementations
|
||||
remarkable_factors = [
|
||||
# special implementations
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
# 1xN implementation
|
||||
(1, 2),
|
||||
(1, 3),
|
||||
(1, 4),
|
||||
(1, 7),
|
||||
# Nx1 implementation
|
||||
(2, 1),
|
||||
(3, 1),
|
||||
(4, 1),
|
||||
(7, 1),
|
||||
# general implementation with different paths
|
||||
(4, 6),
|
||||
(5, 6),
|
||||
(4, 7),
|
||||
(5, 7),
|
||||
(19, 17),
|
||||
]
|
||||
|
||||
gradients_image = Image.open("Tests/images/radial_gradients.png")
|
||||
gradients_image.load()
|
||||
|
||||
|
||||
class TestImageReduce(PillowTestCase):
|
||||
# There are several internal implementations
|
||||
remarkable_factors = [
|
||||
# special implementations
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
# 1xN implementation
|
||||
(1, 2),
|
||||
(1, 3),
|
||||
(1, 4),
|
||||
(1, 7),
|
||||
# Nx1 implementation
|
||||
(2, 1),
|
||||
(3, 1),
|
||||
(4, 1),
|
||||
(7, 1),
|
||||
# general implementation with different paths
|
||||
(4, 6),
|
||||
(5, 6),
|
||||
(4, 7),
|
||||
(5, 7),
|
||||
(19, 17),
|
||||
]
|
||||
def test_args_factor():
|
||||
im = Image.new("L", (10, 10))
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.gradients_image = Image.open("Tests/images/radial_gradients.png")
|
||||
cls.gradients_image.load()
|
||||
assert (4, 4) == im.reduce(3).size
|
||||
assert (4, 10) == im.reduce((3, 1)).size
|
||||
assert (10, 4) == im.reduce((1, 3)).size
|
||||
|
||||
def test_args_factor(self):
|
||||
im = Image.new("L", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(0)
|
||||
with pytest.raises(TypeError):
|
||||
im.reduce(2.0)
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce((0, 10))
|
||||
|
||||
assert (4, 4) == im.reduce(3).size
|
||||
assert (4, 10) == im.reduce((3, 1)).size
|
||||
assert (10, 4) == im.reduce((1, 3)).size
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(0)
|
||||
with pytest.raises(TypeError):
|
||||
im.reduce(2.0)
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce((0, 10))
|
||||
def test_args_box():
|
||||
im = Image.new("L", (10, 10))
|
||||
|
||||
def test_args_box(self):
|
||||
im = Image.new("L", (10, 10))
|
||||
assert (5, 5) == im.reduce(2, (0, 0, 10, 10)).size
|
||||
assert (1, 1) == im.reduce(2, (5, 5, 6, 6)).size
|
||||
|
||||
assert (5, 5) == im.reduce(2, (0, 0, 10, 10)).size
|
||||
assert (1, 1) == im.reduce(2, (5, 5, 6, 6)).size
|
||||
with pytest.raises(TypeError):
|
||||
im.reduce(2, "stri")
|
||||
with pytest.raises(TypeError):
|
||||
im.reduce(2, 2)
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, 0, 11, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, 0, 10, 11))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (-1, 0, 10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, -1, 10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, 5, 10, 5))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (5, 0, 5, 10))
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
im.reduce(2, "stri")
|
||||
with pytest.raises(TypeError):
|
||||
im.reduce(2, 2)
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, 0, 11, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, 0, 10, 11))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (-1, 0, 10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, -1, 10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (0, 5, 10, 5))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(2, (5, 0, 5, 10))
|
||||
|
||||
def test_unsupported_modes(self):
|
||||
im = Image.new("P", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
def test_unsupported_modes():
|
||||
im = Image.new("P", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
|
||||
im = Image.new("1", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
im = Image.new("1", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
|
||||
im = Image.new("I;16", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
im = Image.new("I;16", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
|
||||
def get_image(self, mode):
|
||||
mode_info = ImageMode.getmode(mode)
|
||||
if mode_info.basetype == "L":
|
||||
bands = [self.gradients_image]
|
||||
for _ in mode_info.bands[1:]:
|
||||
# rotate previous image
|
||||
band = bands[-1].transpose(Image.ROTATE_90)
|
||||
bands.append(band)
|
||||
# Correct alpha channel by transforming completely transparent pixels.
|
||||
# Low alpha values also emphasize error after alpha multiplication.
|
||||
if mode.endswith("A"):
|
||||
bands[-1] = bands[-1].point(lambda x: int(85 + x / 1.5))
|
||||
im = Image.merge(mode, bands)
|
||||
else:
|
||||
assert len(mode_info.bands) == 1
|
||||
im = self.gradients_image.convert(mode)
|
||||
# change the height to make a not-square image
|
||||
return im.crop((0, 0, im.width, im.height - 5))
|
||||
|
||||
def compare_reduce_with_box(self, im, factor):
|
||||
box = (11, 13, 146, 164)
|
||||
reduced = im.reduce(factor, box=box)
|
||||
reference = im.crop(box).reduce(factor)
|
||||
assert reduced == reference
|
||||
def get_image(mode):
|
||||
mode_info = ImageMode.getmode(mode)
|
||||
if mode_info.basetype == "L":
|
||||
bands = [gradients_image]
|
||||
for _ in mode_info.bands[1:]:
|
||||
# rotate previous image
|
||||
band = bands[-1].transpose(Image.ROTATE_90)
|
||||
bands.append(band)
|
||||
# Correct alpha channel by transforming completely transparent pixels.
|
||||
# Low alpha values also emphasize error after alpha multiplication.
|
||||
if mode.endswith("A"):
|
||||
bands[-1] = bands[-1].point(lambda x: int(85 + x / 1.5))
|
||||
im = Image.merge(mode, bands)
|
||||
else:
|
||||
assert len(mode_info.bands) == 1
|
||||
im = gradients_image.convert(mode)
|
||||
# change the height to make a not-square image
|
||||
return im.crop((0, 0, im.width, im.height - 5))
|
||||
|
||||
def compare_reduce_with_reference(self, im, factor, average_diff=0.4, max_diff=1):
|
||||
"""Image.reduce() should look very similar to Image.resize(BOX).
|
||||
|
||||
A reference image is compiled from a large source area
|
||||
and possible last column and last row.
|
||||
+-----------+
|
||||
|..........c|
|
||||
|..........c|
|
||||
|..........c|
|
||||
|rrrrrrrrrrp|
|
||||
+-----------+
|
||||
"""
|
||||
reduced = im.reduce(factor)
|
||||
def compare_reduce_with_box(im, factor):
|
||||
box = (11, 13, 146, 164)
|
||||
reduced = im.reduce(factor, box=box)
|
||||
reference = im.crop(box).reduce(factor)
|
||||
assert reduced == reference
|
||||
|
||||
if not isinstance(factor, (list, tuple)):
|
||||
factor = (factor, factor)
|
||||
|
||||
reference = Image.new(im.mode, reduced.size)
|
||||
area_size = (im.size[0] // factor[0], im.size[1] // factor[1])
|
||||
area_box = (0, 0, area_size[0] * factor[0], area_size[1] * factor[1])
|
||||
area = im.resize(area_size, Image.BOX, area_box)
|
||||
reference.paste(area, (0, 0))
|
||||
def compare_reduce_with_reference(im, factor, average_diff=0.4, max_diff=1):
|
||||
"""Image.reduce() should look very similar to Image.resize(BOX).
|
||||
|
||||
if area_size[0] < reduced.size[0]:
|
||||
assert reduced.size[0] - area_size[0] == 1
|
||||
last_column_box = (area_box[2], 0, im.size[0], area_box[3])
|
||||
last_column = im.resize((1, area_size[1]), Image.BOX, last_column_box)
|
||||
reference.paste(last_column, (area_size[0], 0))
|
||||
A reference image is compiled from a large source area
|
||||
and possible last column and last row.
|
||||
+-----------+
|
||||
|..........c|
|
||||
|..........c|
|
||||
|..........c|
|
||||
|rrrrrrrrrrp|
|
||||
+-----------+
|
||||
"""
|
||||
reduced = im.reduce(factor)
|
||||
|
||||
if area_size[1] < reduced.size[1]:
|
||||
assert reduced.size[1] - area_size[1] == 1
|
||||
last_row_box = (0, area_box[3], area_box[2], im.size[1])
|
||||
last_row = im.resize((area_size[0], 1), Image.BOX, last_row_box)
|
||||
reference.paste(last_row, (0, area_size[1]))
|
||||
if not isinstance(factor, (list, tuple)):
|
||||
factor = (factor, factor)
|
||||
|
||||
if area_size[0] < reduced.size[0] and area_size[1] < reduced.size[1]:
|
||||
last_pixel_box = (area_box[2], area_box[3], im.size[0], im.size[1])
|
||||
last_pixel = im.resize((1, 1), Image.BOX, last_pixel_box)
|
||||
reference.paste(last_pixel, area_size)
|
||||
reference = Image.new(im.mode, reduced.size)
|
||||
area_size = (im.size[0] // factor[0], im.size[1] // factor[1])
|
||||
area_box = (0, 0, area_size[0] * factor[0], area_size[1] * factor[1])
|
||||
area = im.resize(area_size, Image.BOX, area_box)
|
||||
reference.paste(area, (0, 0))
|
||||
|
||||
self.assert_compare_images(reduced, reference, average_diff, max_diff)
|
||||
if area_size[0] < reduced.size[0]:
|
||||
assert reduced.size[0] - area_size[0] == 1
|
||||
last_column_box = (area_box[2], 0, im.size[0], area_box[3])
|
||||
last_column = im.resize((1, area_size[1]), Image.BOX, last_column_box)
|
||||
reference.paste(last_column, (area_size[0], 0))
|
||||
|
||||
def assert_compare_images(self, a, b, max_average_diff, max_diff=255):
|
||||
assert a.mode == b.mode, "got mode %r, expected %r" % (a.mode, b.mode)
|
||||
assert a.size == b.size, "got size %r, expected %r" % (a.size, b.size)
|
||||
if area_size[1] < reduced.size[1]:
|
||||
assert reduced.size[1] - area_size[1] == 1
|
||||
last_row_box = (0, area_box[3], area_box[2], im.size[1])
|
||||
last_row = im.resize((area_size[0], 1), Image.BOX, last_row_box)
|
||||
reference.paste(last_row, (0, area_size[1]))
|
||||
|
||||
a, b = convert_to_comparable(a, b)
|
||||
if area_size[0] < reduced.size[0] and area_size[1] < reduced.size[1]:
|
||||
last_pixel_box = (area_box[2], area_box[3], im.size[0], im.size[1])
|
||||
last_pixel = im.resize((1, 1), Image.BOX, last_pixel_box)
|
||||
reference.paste(last_pixel, area_size)
|
||||
|
||||
bands = ImageMode.getmode(a.mode).bands
|
||||
for band, ach, bch in zip(bands, a.split(), b.split()):
|
||||
ch_diff = ImageMath.eval("convert(abs(a - b), 'L')", a=ach, b=bch)
|
||||
ch_hist = ch_diff.histogram()
|
||||
assert_compare_images(reduced, reference, average_diff, max_diff)
|
||||
|
||||
average_diff = sum(i * num for i, num in enumerate(ch_hist)) / (
|
||||
a.size[0] * a.size[1]
|
||||
)
|
||||
msg = "average pixel value difference {:.4f} > expected {:.4f} "
|
||||
"for '{}' band".format(average_diff, max_average_diff, band)
|
||||
assert max_average_diff >= average_diff, msg
|
||||
|
||||
last_diff = [i for i, num in enumerate(ch_hist) if num > 0][-1]
|
||||
assert (
|
||||
max_diff >= last_diff
|
||||
), "max pixel value difference {} > expected {} for '{}' band".format(
|
||||
last_diff, max_diff, band
|
||||
)
|
||||
def assert_compare_images(a, b, max_average_diff, max_diff=255):
|
||||
assert a.mode == b.mode, "got mode %r, expected %r" % (a.mode, b.mode)
|
||||
assert a.size == b.size, "got size %r, expected %r" % (a.size, b.size)
|
||||
|
||||
def test_mode_L(self):
|
||||
im = self.get_image("L")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
a, b = convert_to_comparable(a, b)
|
||||
|
||||
def test_mode_LA(self):
|
||||
im = self.get_image("LA")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor, 0.8, 5)
|
||||
bands = ImageMode.getmode(a.mode).bands
|
||||
for band, ach, bch in zip(bands, a.split(), b.split()):
|
||||
ch_diff = ImageMath.eval("convert(abs(a - b), 'L')", a=ach, b=bch)
|
||||
ch_hist = ch_diff.histogram()
|
||||
|
||||
# With opaque alpha, an error should be way smaller.
|
||||
im.putalpha(Image.new("L", im.size, 255))
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
average_diff = sum(i * num for i, num in enumerate(ch_hist)) / (
|
||||
a.size[0] * a.size[1]
|
||||
)
|
||||
msg = "average pixel value difference {:.4f} > expected {:.4f} "
|
||||
"for '{}' band".format(average_diff, max_average_diff, band)
|
||||
assert max_average_diff >= average_diff, msg
|
||||
|
||||
def test_mode_La(self):
|
||||
im = self.get_image("La")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
last_diff = [i for i, num in enumerate(ch_hist) if num > 0][-1]
|
||||
assert (
|
||||
max_diff >= last_diff
|
||||
), "max pixel value difference {} > expected {} for '{}' band".format(
|
||||
last_diff, max_diff, band
|
||||
)
|
||||
|
||||
def test_mode_RGB(self):
|
||||
im = self.get_image("RGB")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
|
||||
def test_mode_RGBA(self):
|
||||
im = self.get_image("RGBA")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor, 0.8, 5)
|
||||
def test_mode_L():
|
||||
im = get_image("L")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
# With opaque alpha, an error should be way smaller.
|
||||
im.putalpha(Image.new("L", im.size, 255))
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
|
||||
def test_mode_RGBa(self):
|
||||
im = self.get_image("RGBa")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
def test_mode_LA():
|
||||
im = get_image("LA")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor, 0.8, 5)
|
||||
|
||||
def test_mode_I(self):
|
||||
im = self.get_image("I")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
# With opaque alpha, an error should be way smaller.
|
||||
im.putalpha(Image.new("L", im.size, 255))
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
def test_mode_F(self):
|
||||
im = self.get_image("F")
|
||||
for factor in self.remarkable_factors:
|
||||
self.compare_reduce_with_reference(im, factor, 0, 0)
|
||||
self.compare_reduce_with_box(im, factor)
|
||||
|
||||
def test_mode_La():
|
||||
im = get_image("La")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
def test_mode_RGB():
|
||||
im = get_image("RGB")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
def test_mode_RGBA():
|
||||
im = get_image("RGBA")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor, 0.8, 5)
|
||||
|
||||
# With opaque alpha, an error should be way smaller.
|
||||
im.putalpha(Image.new("L", im.size, 255))
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
def test_mode_RGBa():
|
||||
im = get_image("RGBa")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
def test_mode_I():
|
||||
im = get_image("I")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
def test_mode_F():
|
||||
im = get_image("F")
|
||||
for factor in remarkable_factors:
|
||||
compare_reduce_with_reference(im, factor, 0, 0)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
|
|
@ -3,10 +3,10 @@ import math
|
|||
import pytest
|
||||
from PIL import Image, ImageTransform
|
||||
|
||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper
|
||||
from .helper import assert_image_equal, assert_image_similar, hopper
|
||||
|
||||
|
||||
class TestImageTransform(PillowTestCase):
|
||||
class TestImageTransform:
|
||||
def test_sanity(self):
|
||||
im = Image.new("L", (100, 100))
|
||||
|
||||
|
@ -177,7 +177,7 @@ class TestImageTransform(PillowTestCase):
|
|||
im.transform((100, 100), Image.EXTENT, (0, 0, w, h), resample)
|
||||
|
||||
|
||||
class TestImageTransformAffine(PillowTestCase):
|
||||
class TestImageTransformAffine:
|
||||
transform = Image.AFFINE
|
||||
|
||||
def _test_image(self):
|
||||
|
|
|
@ -4,7 +4,6 @@ import pytest
|
|||
from PIL import EpsImagePlugin, Image, ImageFile, features
|
||||
|
||||
from .helper import (
|
||||
PillowTestCase,
|
||||
assert_image,
|
||||
assert_image_equal,
|
||||
assert_image_similar,
|
||||
|
@ -19,7 +18,7 @@ MAXBLOCK = ImageFile.MAXBLOCK
|
|||
SAFEBLOCK = ImageFile.SAFEBLOCK
|
||||
|
||||
|
||||
class TestImageFile(PillowTestCase):
|
||||
class TestImageFile:
|
||||
def test_parser(self):
|
||||
def roundtrip(format):
|
||||
|
||||
|
@ -163,7 +162,7 @@ class MockImageFile(ImageFile.ImageFile):
|
|||
self.tile = [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 32, None)]
|
||||
|
||||
|
||||
class TestPyDecoder(PillowTestCase):
|
||||
class TestPyDecoder:
|
||||
def get_decoder(self):
|
||||
decoder = MockPyDecoder(None)
|
||||
|
||||
|
@ -239,7 +238,7 @@ class TestPyDecoder(PillowTestCase):
|
|||
assert im.format is None
|
||||
assert im.get_format_mimetype() is None
|
||||
|
||||
def test_exif_jpeg(self):
|
||||
def test_exif_jpeg(self, tmp_path):
|
||||
with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian
|
||||
exif = im.getexif()
|
||||
assert 258 not in exif
|
||||
|
@ -247,7 +246,7 @@ class TestPyDecoder(PillowTestCase):
|
|||
assert exif[40963] == 450
|
||||
assert exif[11] == "gThumb 3.0.1"
|
||||
|
||||
out = self.tempfile("temp.jpg")
|
||||
out = str(tmp_path / "temp.jpg")
|
||||
exif[258] = 8
|
||||
del exif[40960]
|
||||
exif[40963] = 455
|
||||
|
@ -267,7 +266,7 @@ class TestPyDecoder(PillowTestCase):
|
|||
assert exif[40963] == 200
|
||||
assert exif[305] == "Adobe Photoshop CC 2017 (Macintosh)"
|
||||
|
||||
out = self.tempfile("temp.jpg")
|
||||
out = str(tmp_path / "temp.jpg")
|
||||
exif[258] = 8
|
||||
del exif[34665]
|
||||
exif[40963] = 455
|
||||
|
@ -282,12 +281,12 @@ class TestPyDecoder(PillowTestCase):
|
|||
|
||||
@skip_unless_feature("webp")
|
||||
@skip_unless_feature("webp_anim")
|
||||
def test_exif_webp(self):
|
||||
def test_exif_webp(self, tmp_path):
|
||||
with Image.open("Tests/images/hopper.webp") as im:
|
||||
exif = im.getexif()
|
||||
assert exif == {}
|
||||
|
||||
out = self.tempfile("temp.webp")
|
||||
out = str(tmp_path / "temp.webp")
|
||||
exif[258] = 8
|
||||
exif[40963] = 455
|
||||
exif[305] = "Pillow test"
|
||||
|
@ -304,12 +303,12 @@ class TestPyDecoder(PillowTestCase):
|
|||
im.save(out, exif=exif, save_all=True)
|
||||
check_exif()
|
||||
|
||||
def test_exif_png(self):
|
||||
def test_exif_png(self, tmp_path):
|
||||
with Image.open("Tests/images/exif.png") as im:
|
||||
exif = im.getexif()
|
||||
assert exif == {274: 1}
|
||||
|
||||
out = self.tempfile("temp.png")
|
||||
out = str(tmp_path / "temp.png")
|
||||
exif[258] = 8
|
||||
del exif[274]
|
||||
exif[40963] = 455
|
||||
|
|
|
@ -1,193 +1,207 @@
|
|||
import pytest
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
from .helper import PillowTestCase, assert_image_similar, skip_unless_feature
|
||||
from .helper import assert_image_similar, skip_unless_feature
|
||||
|
||||
FONT_SIZE = 20
|
||||
FONT_PATH = "Tests/fonts/DejaVuSans.ttf"
|
||||
|
||||
pytestmark = skip_unless_feature("raqm")
|
||||
|
||||
@skip_unless_feature("raqm")
|
||||
class TestImagecomplextext(PillowTestCase):
|
||||
def test_english(self):
|
||||
# smoke test, this should not fail
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "TEST", font=ttf, fill=500, direction="ltr")
|
||||
|
||||
def test_complex_text(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
def test_english():
|
||||
# smoke test, this should not fail
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "TEST", font=ttf, fill=500, direction="ltr")
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "اهلا عمان", font=ttf, fill=500)
|
||||
|
||||
target = "Tests/images/test_text.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
def test_complex_text():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
def test_y_offset(self):
|
||||
ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "اهلا عمان", font=ttf, fill=500)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "العالم العربي", font=ttf, fill=500)
|
||||
target = "Tests/images/test_text.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
target = "Tests/images/test_y_offset.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 1.7)
|
||||
|
||||
def test_complex_unicode_text(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
def test_y_offset():
|
||||
ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "السلام عليكم", font=ttf, fill=500)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "العالم العربي", font=ttf, fill=500)
|
||||
|
||||
target = "Tests/images/test_complex_unicode_text.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
target = "Tests/images/test_y_offset.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 1.7)
|
||||
|
||||
ttf = ImageFont.truetype("Tests/fonts/KhmerOSBattambang-Regular.ttf", FONT_SIZE)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "លោកុប្បត្តិ", font=ttf, fill=500)
|
||||
def test_complex_unicode_text():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
target = "Tests/images/test_complex_unicode_text2.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 2.3)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "السلام عليكم", font=ttf, fill=500)
|
||||
|
||||
def test_text_direction_rtl(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
target = "Tests/images/test_complex_unicode_text.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "English عربي", font=ttf, fill=500, direction="rtl")
|
||||
ttf = ImageFont.truetype("Tests/fonts/KhmerOSBattambang-Regular.ttf", FONT_SIZE)
|
||||
|
||||
target = "Tests/images/test_direction_rtl.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "លោកុប្បត្តិ", font=ttf, fill=500)
|
||||
|
||||
def test_text_direction_ltr(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
target = "Tests/images/test_complex_unicode_text2.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 2.3)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "سلطنة عمان Oman", font=ttf, fill=500, direction="ltr")
|
||||
|
||||
target = "Tests/images/test_direction_ltr.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
def test_text_direction_rtl():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
def test_text_direction_rtl2(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "English عربي", font=ttf, fill=500, direction="rtl")
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "Oman سلطنة عمان", font=ttf, fill=500, direction="rtl")
|
||||
target = "Tests/images/test_direction_rtl.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
target = "Tests/images/test_direction_ltr.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
def test_text_direction_ttb(self):
|
||||
ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", FONT_SIZE)
|
||||
def test_text_direction_ltr():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
im = Image.new(mode="RGB", size=(100, 300))
|
||||
draw = ImageDraw.Draw(im)
|
||||
try:
|
||||
draw.text((0, 0), "English あい", font=ttf, fill=500, direction="ttb")
|
||||
except ValueError as ex:
|
||||
if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction":
|
||||
self.skipTest("libraqm 0.7 or greater not available")
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "سلطنة عمان Oman", font=ttf, fill=500, direction="ltr")
|
||||
|
||||
target = "Tests/images/test_direction_ttb.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 1.15)
|
||||
target = "Tests/images/test_direction_ltr.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
def test_text_direction_ttb_stroke(self):
|
||||
ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", 50)
|
||||
|
||||
im = Image.new(mode="RGB", size=(100, 300))
|
||||
draw = ImageDraw.Draw(im)
|
||||
try:
|
||||
draw.text(
|
||||
(25, 25),
|
||||
"あい",
|
||||
font=ttf,
|
||||
fill=500,
|
||||
direction="ttb",
|
||||
stroke_width=2,
|
||||
stroke_fill="#0f0",
|
||||
)
|
||||
except ValueError as ex:
|
||||
if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction":
|
||||
self.skipTest("libraqm 0.7 or greater not available")
|
||||
def test_text_direction_rtl2():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
target = "Tests/images/test_direction_ttb_stroke.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 12.4)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "Oman سلطنة عمان", font=ttf, fill=500, direction="rtl")
|
||||
|
||||
def test_ligature_features(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
target = "Tests/images/test_direction_ltr.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "filling", font=ttf, fill=500, features=["-liga"])
|
||||
target = "Tests/images/test_ligature_features.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
liga_size = ttf.getsize("fi", features=["-liga"])
|
||||
assert liga_size == (13, 19)
|
||||
def test_text_direction_ttb():
|
||||
ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", FONT_SIZE)
|
||||
|
||||
def test_kerning_features(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
im = Image.new(mode="RGB", size=(100, 300))
|
||||
draw = ImageDraw.Draw(im)
|
||||
try:
|
||||
draw.text((0, 0), "English あい", font=ttf, fill=500, direction="ttb")
|
||||
except ValueError as ex:
|
||||
if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction":
|
||||
pytest.skip("libraqm 0.7 or greater not available")
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "TeToAV", font=ttf, fill=500, features=["-kern"])
|
||||
target = "Tests/images/test_direction_ttb.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 1.15)
|
||||
|
||||
target = "Tests/images/test_kerning_features.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
def test_arabictext_features(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
def test_text_direction_ttb_stroke():
|
||||
ttf = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf", 50)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
im = Image.new(mode="RGB", size=(100, 300))
|
||||
draw = ImageDraw.Draw(im)
|
||||
try:
|
||||
draw.text(
|
||||
(0, 0),
|
||||
"اللغة العربية",
|
||||
(25, 25),
|
||||
"あい",
|
||||
font=ttf,
|
||||
fill=500,
|
||||
features=["-fina", "-init", "-medi"],
|
||||
direction="ttb",
|
||||
stroke_width=2,
|
||||
stroke_fill="#0f0",
|
||||
)
|
||||
except ValueError as ex:
|
||||
if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction":
|
||||
pytest.skip("libraqm 0.7 or greater not available")
|
||||
|
||||
target = "Tests/images/test_arabictext_features.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
target = "Tests/images/test_direction_ttb_stroke.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 12.4)
|
||||
|
||||
def test_x_max_and_y_offset(self):
|
||||
ttf = ImageFont.truetype("Tests/fonts/ArefRuqaa-Regular.ttf", 40)
|
||||
|
||||
im = Image.new(mode="RGB", size=(50, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "لح", font=ttf, fill=500)
|
||||
def test_ligature_features():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
target = "Tests/images/test_x_max_and_y_offset.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "filling", font=ttf, fill=500, features=["-liga"])
|
||||
target = "Tests/images/test_ligature_features.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
def test_language(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
liga_size = ttf.getsize("fi", features=["-liga"])
|
||||
assert liga_size == (13, 19)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "абвг", font=ttf, fill=500, language="sr")
|
||||
|
||||
target = "Tests/images/test_language.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
def test_kerning_features():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "TeToAV", font=ttf, fill=500, features=["-kern"])
|
||||
|
||||
target = "Tests/images/test_kerning_features.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
|
||||
def test_arabictext_features():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text(
|
||||
(0, 0),
|
||||
"اللغة العربية",
|
||||
font=ttf,
|
||||
fill=500,
|
||||
features=["-fina", "-init", "-medi"],
|
||||
)
|
||||
|
||||
target = "Tests/images/test_arabictext_features.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
|
||||
def test_x_max_and_y_offset():
|
||||
ttf = ImageFont.truetype("Tests/fonts/ArefRuqaa-Regular.ttf", 40)
|
||||
|
||||
im = Image.new(mode="RGB", size=(50, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "لح", font=ttf, fill=500)
|
||||
|
||||
target = "Tests/images/test_x_max_and_y_offset.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
||||
|
||||
def test_language():
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), "абвг", font=ttf, fill=500, language="sr")
|
||||
|
||||
target = "Tests/images/test_language.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 0.5)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import subprocess
|
||||
import sys
|
||||
|
||||
from .helper import PillowTestCase, assert_image
|
||||
import pytest
|
||||
|
||||
from .helper import assert_image
|
||||
|
||||
try:
|
||||
from PIL import ImageGrab
|
||||
|
||||
class TestImageGrab(PillowTestCase):
|
||||
class TestImageGrab:
|
||||
def test_grab(self):
|
||||
for im in [
|
||||
ImageGrab.grab(),
|
||||
|
@ -39,12 +41,13 @@ $bmp = New-Object Drawing.Bitmap 200, 200
|
|||
|
||||
except ImportError:
|
||||
|
||||
class TestImageGrab(PillowTestCase):
|
||||
class TestImageGrab:
|
||||
@pytest.mark.skip(reason="ImageGrab ImportError")
|
||||
def test_skip(self):
|
||||
self.skipTest("ImportError")
|
||||
pass
|
||||
|
||||
|
||||
class TestImageGrabImport(PillowTestCase):
|
||||
class TestImageGrabImport:
|
||||
def test_import(self):
|
||||
# Arrange
|
||||
exception = None
|
||||
|
|
|
@ -2,318 +2,340 @@
|
|||
import pytest
|
||||
from PIL import Image, ImageMorph, _imagingmorph
|
||||
|
||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
||||
from .helper import assert_image_equal, hopper
|
||||
|
||||
|
||||
class MorphTests(PillowTestCase):
|
||||
def setUp(self):
|
||||
self.A = self.string_to_img(
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..111..
|
||||
..111..
|
||||
..111..
|
||||
.......
|
||||
.......
|
||||
"""
|
||||
)
|
||||
def string_to_img(image_string):
|
||||
"""Turn a string image representation into a binary image"""
|
||||
rows = [s for s in image_string.replace(" ", "").split("\n") if len(s)]
|
||||
height = len(rows)
|
||||
width = len(rows[0])
|
||||
im = Image.new("L", (width, height))
|
||||
for i in range(width):
|
||||
for j in range(height):
|
||||
c = rows[j][i]
|
||||
v = c in "X1"
|
||||
im.putpixel((i, j), v)
|
||||
|
||||
def img_to_string(self, im):
|
||||
"""Turn a (small) binary image into a string representation"""
|
||||
chars = ".1"
|
||||
width, height = im.size
|
||||
return "\n".join(
|
||||
"".join(chars[im.getpixel((c, r)) > 0] for c in range(width))
|
||||
for r in range(height)
|
||||
)
|
||||
return im
|
||||
|
||||
def string_to_img(self, image_string):
|
||||
"""Turn a string image representation into a binary image"""
|
||||
rows = [s for s in image_string.replace(" ", "").split("\n") if len(s)]
|
||||
height = len(rows)
|
||||
width = len(rows[0])
|
||||
im = Image.new("L", (width, height))
|
||||
for i in range(width):
|
||||
for j in range(height):
|
||||
c = rows[j][i]
|
||||
v = c in "X1"
|
||||
im.putpixel((i, j), v)
|
||||
|
||||
return im
|
||||
A = string_to_img(
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..111..
|
||||
..111..
|
||||
..111..
|
||||
.......
|
||||
.......
|
||||
"""
|
||||
)
|
||||
|
||||
def img_string_normalize(self, im):
|
||||
return self.img_to_string(self.string_to_img(im))
|
||||
|
||||
def assert_img_equal(self, A, B):
|
||||
assert self.img_to_string(A) == self.img_to_string(B)
|
||||
def img_to_string(im):
|
||||
"""Turn a (small) binary image into a string representation"""
|
||||
chars = ".1"
|
||||
width, height = im.size
|
||||
return "\n".join(
|
||||
"".join(chars[im.getpixel((c, r)) > 0] for c in range(width))
|
||||
for r in range(height)
|
||||
)
|
||||
|
||||
def assert_img_equal_img_string(self, A, Bstring):
|
||||
assert self.img_to_string(A) == self.img_string_normalize(Bstring)
|
||||
|
||||
def test_str_to_img(self):
|
||||
with Image.open("Tests/images/morph_a.png") as im:
|
||||
assert_image_equal(self.A, im)
|
||||
def img_string_normalize(im):
|
||||
return img_to_string(string_to_img(im))
|
||||
|
||||
def create_lut(self):
|
||||
for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"):
|
||||
lb = ImageMorph.LutBuilder(op_name=op)
|
||||
lut = lb.build_lut()
|
||||
with open("Tests/images/%s.lut" % op, "wb") as f:
|
||||
f.write(lut)
|
||||
|
||||
# create_lut()
|
||||
def test_lut(self):
|
||||
for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"):
|
||||
lb = ImageMorph.LutBuilder(op_name=op)
|
||||
assert lb.get_lut() is None
|
||||
def assert_img_equal(A, B):
|
||||
assert img_to_string(A) == img_to_string(B)
|
||||
|
||||
lut = lb.build_lut()
|
||||
with open("Tests/images/%s.lut" % op, "rb") as f:
|
||||
assert lut == bytearray(f.read())
|
||||
|
||||
def test_no_operator_loaded(self):
|
||||
mop = ImageMorph.MorphOp()
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.apply(None)
|
||||
assert str(e.value) == "No operator loaded"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.match(None)
|
||||
assert str(e.value) == "No operator loaded"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.save_lut(None)
|
||||
assert str(e.value) == "No operator loaded"
|
||||
def assert_img_equal_img_string(A, Bstring):
|
||||
assert img_to_string(A) == img_string_normalize(Bstring)
|
||||
|
||||
# Test the named patterns
|
||||
def test_erosion8(self):
|
||||
# erosion8
|
||||
mop = ImageMorph.MorphOp(op_name="erosion8")
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 8
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
...1...
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
def test_dialation8(self):
|
||||
# dialation8
|
||||
mop = ImageMorph.MorphOp(op_name="dilation8")
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 16
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
.......
|
||||
""",
|
||||
)
|
||||
def test_str_to_img():
|
||||
with Image.open("Tests/images/morph_a.png") as im:
|
||||
assert_image_equal(A, im)
|
||||
|
||||
def test_erosion4(self):
|
||||
# erosion4
|
||||
mop = ImageMorph.MorphOp(op_name="dilation4")
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 12
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
..111..
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
..111..
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
def test_edge(self):
|
||||
# edge
|
||||
mop = ImageMorph.MorphOp(op_name="edge")
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 1
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..111..
|
||||
..1.1..
|
||||
..111..
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
def test_corner(self):
|
||||
# Create a corner detector pattern
|
||||
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "4:(00. 01. ...)->1"])
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 5
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
# Test the coordinate counting with the same operator
|
||||
coords = mop.match(self.A)
|
||||
assert len(coords) == 4
|
||||
assert tuple(coords) == ((2, 2), (4, 2), (2, 4), (4, 4))
|
||||
|
||||
coords = mop.get_on_pixels(Aout)
|
||||
assert len(coords) == 4
|
||||
assert tuple(coords) == ((2, 2), (4, 2), (2, 4), (4, 4))
|
||||
|
||||
def test_mirroring(self):
|
||||
# Test 'M' for mirroring
|
||||
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "M:(00. 01. ...)->1"])
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 7
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
def test_negate(self):
|
||||
# Test 'N' for negate
|
||||
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "N:(00. 01. ...)->1"])
|
||||
count, Aout = mop.apply(self.A)
|
||||
assert count == 8
|
||||
self.assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1....
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
def test_non_binary_images(self):
|
||||
im = hopper("RGB")
|
||||
mop = ImageMorph.MorphOp(op_name="erosion8")
|
||||
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.apply(im)
|
||||
assert str(e.value) == "Image must be binary, meaning it must use mode L"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.match(im)
|
||||
assert str(e.value) == "Image must be binary, meaning it must use mode L"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.get_on_pixels(im)
|
||||
assert str(e.value) == "Image must be binary, meaning it must use mode L"
|
||||
|
||||
def test_add_patterns(self):
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name="corner")
|
||||
assert lb.patterns == ["1:(... ... ...)->0", "4:(00. 01. ...)->1"]
|
||||
new_patterns = ["M:(00. 01. ...)->1", "N:(00. 01. ...)->1"]
|
||||
|
||||
# Act
|
||||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Assert
|
||||
assert lb.patterns == [
|
||||
"1:(... ... ...)->0",
|
||||
"4:(00. 01. ...)->1",
|
||||
"M:(00. 01. ...)->1",
|
||||
"N:(00. 01. ...)->1",
|
||||
]
|
||||
|
||||
def test_unknown_pattern(self):
|
||||
with pytest.raises(Exception):
|
||||
ImageMorph.LutBuilder(op_name="unknown")
|
||||
|
||||
def test_pattern_syntax_error(self):
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name="corner")
|
||||
new_patterns = ["a pattern with a syntax error"]
|
||||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(Exception) as e:
|
||||
lb.build_lut()
|
||||
assert str(e.value) == 'Syntax error in pattern "a pattern with a syntax error"'
|
||||
|
||||
def test_load_invalid_mrl(self):
|
||||
# Arrange
|
||||
invalid_mrl = "Tests/images/hopper.png"
|
||||
mop = ImageMorph.MorphOp()
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.load_lut(invalid_mrl)
|
||||
assert str(e.value) == "Wrong size operator file!"
|
||||
|
||||
def test_roundtrip_mrl(self):
|
||||
# Arrange
|
||||
tempfile = self.tempfile("temp.mrl")
|
||||
mop = ImageMorph.MorphOp(op_name="corner")
|
||||
initial_lut = mop.lut
|
||||
|
||||
# Act
|
||||
mop.save_lut(tempfile)
|
||||
mop.load_lut(tempfile)
|
||||
|
||||
# Act / Assert
|
||||
assert mop.lut == initial_lut
|
||||
|
||||
def test_set_lut(self):
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name="corner")
|
||||
def create_lut():
|
||||
for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"):
|
||||
lb = ImageMorph.LutBuilder(op_name=op)
|
||||
lut = lb.build_lut()
|
||||
mop = ImageMorph.MorphOp()
|
||||
with open("Tests/images/%s.lut" % op, "wb") as f:
|
||||
f.write(lut)
|
||||
|
||||
# Act
|
||||
mop.set_lut(lut)
|
||||
|
||||
# Assert
|
||||
assert mop.lut == lut
|
||||
# create_lut()
|
||||
def test_lut():
|
||||
for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"):
|
||||
lb = ImageMorph.LutBuilder(op_name=op)
|
||||
assert lb.get_lut() is None
|
||||
|
||||
def test_wrong_mode(self):
|
||||
lut = ImageMorph.LutBuilder(op_name="corner").build_lut()
|
||||
imrgb = Image.new("RGB", (10, 10))
|
||||
iml = Image.new("L", (10, 10))
|
||||
lut = lb.build_lut()
|
||||
with open("Tests/images/%s.lut" % op, "rb") as f:
|
||||
assert lut == bytearray(f.read())
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
_imagingmorph.apply(bytes(lut), imrgb.im.id, iml.im.id)
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
_imagingmorph.apply(bytes(lut), iml.im.id, imrgb.im.id)
|
||||
def test_no_operator_loaded():
|
||||
mop = ImageMorph.MorphOp()
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.apply(None)
|
||||
assert str(e.value) == "No operator loaded"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.match(None)
|
||||
assert str(e.value) == "No operator loaded"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.save_lut(None)
|
||||
assert str(e.value) == "No operator loaded"
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
_imagingmorph.match(bytes(lut), imrgb.im.id)
|
||||
|
||||
# Should not raise
|
||||
_imagingmorph.match(bytes(lut), iml.im.id)
|
||||
# Test the named patterns
|
||||
def test_erosion8():
|
||||
# erosion8
|
||||
mop = ImageMorph.MorphOp(op_name="erosion8")
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 8
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
...1...
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def test_dialation8():
|
||||
# dialation8
|
||||
mop = ImageMorph.MorphOp(op_name="dilation8")
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 16
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def test_erosion4():
|
||||
# erosion4
|
||||
mop = ImageMorph.MorphOp(op_name="dilation4")
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 12
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
..111..
|
||||
.11111.
|
||||
.11111.
|
||||
.11111.
|
||||
..111..
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def test_edge():
|
||||
# edge
|
||||
mop = ImageMorph.MorphOp(op_name="edge")
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 1
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..111..
|
||||
..1.1..
|
||||
..111..
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def test_corner():
|
||||
# Create a corner detector pattern
|
||||
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "4:(00. 01. ...)->1"])
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 5
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
# Test the coordinate counting with the same operator
|
||||
coords = mop.match(A)
|
||||
assert len(coords) == 4
|
||||
assert tuple(coords) == ((2, 2), (4, 2), (2, 4), (4, 4))
|
||||
|
||||
coords = mop.get_on_pixels(Aout)
|
||||
assert len(coords) == 4
|
||||
assert tuple(coords) == ((2, 2), (4, 2), (2, 4), (4, 4))
|
||||
|
||||
|
||||
def test_mirroring():
|
||||
# Test 'M' for mirroring
|
||||
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "M:(00. 01. ...)->1"])
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 7
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def test_negate():
|
||||
# Test 'N' for negate
|
||||
mop = ImageMorph.MorphOp(patterns=["1:(... ... ...)->0", "N:(00. 01. ...)->1"])
|
||||
count, Aout = mop.apply(A)
|
||||
assert count == 8
|
||||
assert_img_equal_img_string(
|
||||
Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1....
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def test_non_binary_images():
|
||||
im = hopper("RGB")
|
||||
mop = ImageMorph.MorphOp(op_name="erosion8")
|
||||
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.apply(im)
|
||||
assert str(e.value) == "Image must be binary, meaning it must use mode L"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.match(im)
|
||||
assert str(e.value) == "Image must be binary, meaning it must use mode L"
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.get_on_pixels(im)
|
||||
assert str(e.value) == "Image must be binary, meaning it must use mode L"
|
||||
|
||||
|
||||
def test_add_patterns():
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name="corner")
|
||||
assert lb.patterns == ["1:(... ... ...)->0", "4:(00. 01. ...)->1"]
|
||||
new_patterns = ["M:(00. 01. ...)->1", "N:(00. 01. ...)->1"]
|
||||
|
||||
# Act
|
||||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Assert
|
||||
assert lb.patterns == [
|
||||
"1:(... ... ...)->0",
|
||||
"4:(00. 01. ...)->1",
|
||||
"M:(00. 01. ...)->1",
|
||||
"N:(00. 01. ...)->1",
|
||||
]
|
||||
|
||||
|
||||
def test_unknown_pattern():
|
||||
with pytest.raises(Exception):
|
||||
ImageMorph.LutBuilder(op_name="unknown")
|
||||
|
||||
|
||||
def test_pattern_syntax_error():
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name="corner")
|
||||
new_patterns = ["a pattern with a syntax error"]
|
||||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(Exception) as e:
|
||||
lb.build_lut()
|
||||
assert str(e.value) == 'Syntax error in pattern "a pattern with a syntax error"'
|
||||
|
||||
|
||||
def test_load_invalid_mrl():
|
||||
# Arrange
|
||||
invalid_mrl = "Tests/images/hopper.png"
|
||||
mop = ImageMorph.MorphOp()
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(Exception) as e:
|
||||
mop.load_lut(invalid_mrl)
|
||||
assert str(e.value) == "Wrong size operator file!"
|
||||
|
||||
|
||||
def test_roundtrip_mrl(tmp_path):
|
||||
# Arrange
|
||||
tempfile = str(tmp_path / "temp.mrl")
|
||||
mop = ImageMorph.MorphOp(op_name="corner")
|
||||
initial_lut = mop.lut
|
||||
|
||||
# Act
|
||||
mop.save_lut(tempfile)
|
||||
mop.load_lut(tempfile)
|
||||
|
||||
# Act / Assert
|
||||
assert mop.lut == initial_lut
|
||||
|
||||
|
||||
def test_set_lut():
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name="corner")
|
||||
lut = lb.build_lut()
|
||||
mop = ImageMorph.MorphOp()
|
||||
|
||||
# Act
|
||||
mop.set_lut(lut)
|
||||
|
||||
# Assert
|
||||
assert mop.lut == lut
|
||||
|
||||
|
||||
def test_wrong_mode():
|
||||
lut = ImageMorph.LutBuilder(op_name="corner").build_lut()
|
||||
imrgb = Image.new("RGB", (10, 10))
|
||||
iml = Image.new("L", (10, 10))
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
_imagingmorph.apply(bytes(lut), imrgb.im.id, iml.im.id)
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
_imagingmorph.apply(bytes(lut), iml.im.id, imrgb.im.id)
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
_imagingmorph.match(bytes(lut), imrgb.im.id)
|
||||
|
||||
# Should not raise
|
||||
_imagingmorph.match(bytes(lut), iml.im.id)
|
||||
|
|
|
@ -4,10 +4,8 @@ import struct
|
|||
import pytest
|
||||
from PIL import Image, ImagePath
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
|
||||
class TestImagePath(PillowTestCase):
|
||||
class TestImagePath:
|
||||
def test_path(self):
|
||||
|
||||
p = ImagePath.Path(list(range(10)))
|
||||
|
|
|
@ -3,12 +3,10 @@ import sys
|
|||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
X = 255
|
||||
|
||||
|
||||
class TestLibPack(PillowTestCase):
|
||||
class TestLibPack:
|
||||
def assert_pack(self, mode, rawmode, data, *pixels):
|
||||
"""
|
||||
data - either raw bytes with data or just number of bytes in rawmode.
|
||||
|
@ -223,7 +221,7 @@ class TestLibPack(PillowTestCase):
|
|||
)
|
||||
|
||||
|
||||
class TestLibUnpack(PillowTestCase):
|
||||
class TestLibUnpack:
|
||||
def assert_unpack(self, mode, rawmode, data, *pixels):
|
||||
"""
|
||||
data - either raw bytes with data or just number of bytes in rawmode.
|
||||
|
|
|
@ -1,105 +1,106 @@
|
|||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, hopper
|
||||
from .helper import hopper
|
||||
|
||||
original = hopper().resize((32, 32)).convert("I")
|
||||
|
||||
|
||||
class TestModeI16(PillowTestCase):
|
||||
def verify(im1):
|
||||
im2 = original.copy()
|
||||
assert im1.size == im2.size
|
||||
pix1 = im1.load()
|
||||
pix2 = im2.load()
|
||||
for y in range(im1.size[1]):
|
||||
for x in range(im1.size[0]):
|
||||
xy = x, y
|
||||
p1 = pix1[xy]
|
||||
p2 = pix2[xy]
|
||||
assert p1 == p2, "got {!r} from mode {} at {}, expected {!r}".format(
|
||||
p1, im1.mode, xy, p2
|
||||
)
|
||||
|
||||
original = hopper().resize((32, 32)).convert("I")
|
||||
|
||||
def verify(self, im1):
|
||||
im2 = self.original.copy()
|
||||
assert im1.size == im2.size
|
||||
pix1 = im1.load()
|
||||
pix2 = im2.load()
|
||||
for y in range(im1.size[1]):
|
||||
for x in range(im1.size[0]):
|
||||
xy = x, y
|
||||
p1 = pix1[xy]
|
||||
p2 = pix2[xy]
|
||||
assert p1 == p2, "got {!r} from mode {} at {}, expected {!r}".format(
|
||||
p1, im1.mode, xy, p2
|
||||
)
|
||||
def test_basic(tmp_path):
|
||||
# PIL 1.1 has limited support for 16-bit image data. Check that
|
||||
# create/copy/transform and save works as expected.
|
||||
|
||||
def test_basic(self):
|
||||
# PIL 1.1 has limited support for 16-bit image data. Check that
|
||||
# create/copy/transform and save works as expected.
|
||||
def basic(mode):
|
||||
|
||||
def basic(mode):
|
||||
imIn = original.convert(mode)
|
||||
verify(imIn)
|
||||
|
||||
imIn = self.original.convert(mode)
|
||||
self.verify(imIn)
|
||||
w, h = imIn.size
|
||||
|
||||
w, h = imIn.size
|
||||
imOut = imIn.copy()
|
||||
verify(imOut) # copy
|
||||
|
||||
imOut = imIn.copy()
|
||||
self.verify(imOut) # copy
|
||||
imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h))
|
||||
verify(imOut) # transform
|
||||
|
||||
imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h))
|
||||
self.verify(imOut) # transform
|
||||
filename = str(tmp_path / "temp.im")
|
||||
imIn.save(filename)
|
||||
|
||||
filename = self.tempfile("temp.im")
|
||||
imIn.save(filename)
|
||||
with Image.open(filename) as imOut:
|
||||
|
||||
with Image.open(filename) as imOut:
|
||||
verify(imIn)
|
||||
verify(imOut)
|
||||
|
||||
self.verify(imIn)
|
||||
self.verify(imOut)
|
||||
imOut = imIn.crop((0, 0, w, h))
|
||||
verify(imOut)
|
||||
|
||||
imOut = imIn.crop((0, 0, w, h))
|
||||
self.verify(imOut)
|
||||
imOut = Image.new(mode, (w, h), None)
|
||||
imOut.paste(imIn.crop((0, 0, w // 2, h)), (0, 0))
|
||||
imOut.paste(imIn.crop((w // 2, 0, w, h)), (w // 2, 0))
|
||||
|
||||
imOut = Image.new(mode, (w, h), None)
|
||||
imOut.paste(imIn.crop((0, 0, w // 2, h)), (0, 0))
|
||||
imOut.paste(imIn.crop((w // 2, 0, w, h)), (w // 2, 0))
|
||||
verify(imIn)
|
||||
verify(imOut)
|
||||
|
||||
self.verify(imIn)
|
||||
self.verify(imOut)
|
||||
imIn = Image.new(mode, (1, 1), 1)
|
||||
assert imIn.getpixel((0, 0)) == 1
|
||||
|
||||
imIn = Image.new(mode, (1, 1), 1)
|
||||
assert imIn.getpixel((0, 0)) == 1
|
||||
imIn.putpixel((0, 0), 2)
|
||||
assert imIn.getpixel((0, 0)) == 2
|
||||
|
||||
imIn.putpixel((0, 0), 2)
|
||||
assert imIn.getpixel((0, 0)) == 2
|
||||
if mode == "L":
|
||||
maximum = 255
|
||||
else:
|
||||
maximum = 32767
|
||||
|
||||
if mode == "L":
|
||||
maximum = 255
|
||||
else:
|
||||
maximum = 32767
|
||||
imIn = Image.new(mode, (1, 1), 256)
|
||||
assert imIn.getpixel((0, 0)) == min(256, maximum)
|
||||
|
||||
imIn = Image.new(mode, (1, 1), 256)
|
||||
assert imIn.getpixel((0, 0)) == min(256, maximum)
|
||||
imIn.putpixel((0, 0), 512)
|
||||
assert imIn.getpixel((0, 0)) == min(512, maximum)
|
||||
|
||||
imIn.putpixel((0, 0), 512)
|
||||
assert imIn.getpixel((0, 0)) == min(512, maximum)
|
||||
basic("L")
|
||||
|
||||
basic("L")
|
||||
basic("I;16")
|
||||
basic("I;16B")
|
||||
basic("I;16L")
|
||||
|
||||
basic("I;16")
|
||||
basic("I;16B")
|
||||
basic("I;16L")
|
||||
basic("I")
|
||||
|
||||
basic("I")
|
||||
|
||||
def test_tobytes(self):
|
||||
def tobytes(mode):
|
||||
return Image.new(mode, (1, 1), 1).tobytes()
|
||||
def test_tobytes():
|
||||
def tobytes(mode):
|
||||
return Image.new(mode, (1, 1), 1).tobytes()
|
||||
|
||||
order = 1 if Image._ENDIAN == "<" else -1
|
||||
order = 1 if Image._ENDIAN == "<" else -1
|
||||
|
||||
assert tobytes("L") == b"\x01"
|
||||
assert tobytes("I;16") == b"\x01\x00"
|
||||
assert tobytes("I;16B") == b"\x00\x01"
|
||||
assert tobytes("I") == b"\x01\x00\x00\x00"[::order]
|
||||
assert tobytes("L") == b"\x01"
|
||||
assert tobytes("I;16") == b"\x01\x00"
|
||||
assert tobytes("I;16B") == b"\x00\x01"
|
||||
assert tobytes("I") == b"\x01\x00\x00\x00"[::order]
|
||||
|
||||
def test_convert(self):
|
||||
|
||||
im = self.original.copy()
|
||||
def test_convert():
|
||||
|
||||
self.verify(im.convert("I;16"))
|
||||
self.verify(im.convert("I;16").convert("L"))
|
||||
self.verify(im.convert("I;16").convert("I"))
|
||||
im = original.copy()
|
||||
|
||||
self.verify(im.convert("I;16B"))
|
||||
self.verify(im.convert("I;16B").convert("L"))
|
||||
self.verify(im.convert("I;16B").convert("I"))
|
||||
verify(im.convert("I;16"))
|
||||
verify(im.convert("I;16").convert("L"))
|
||||
verify(im.convert("I;16").convert("I"))
|
||||
|
||||
verify(im.convert("I;16B"))
|
||||
verify(im.convert("I;16B").convert("L"))
|
||||
verify(im.convert("I;16B").convert("I"))
|
||||
|
|
|
@ -2,88 +2,89 @@ import pickle
|
|||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
def helper_pickle_file(tmp_path, pickle, protocol=0, mode=None):
|
||||
# Arrange
|
||||
with Image.open("Tests/images/hopper.jpg") as im:
|
||||
filename = str(tmp_path / "temp.pkl")
|
||||
if mode:
|
||||
im = im.convert(mode)
|
||||
|
||||
# Act
|
||||
with open(filename, "wb") as f:
|
||||
pickle.dump(im, f, protocol)
|
||||
with open(filename, "rb") as f:
|
||||
loaded_im = pickle.load(f)
|
||||
|
||||
# Assert
|
||||
assert im == loaded_im
|
||||
|
||||
|
||||
class TestPickle(PillowTestCase):
|
||||
def helper_pickle_file(self, pickle, protocol=0, mode=None):
|
||||
# Arrange
|
||||
with Image.open("Tests/images/hopper.jpg") as im:
|
||||
filename = self.tempfile("temp.pkl")
|
||||
if mode:
|
||||
im = im.convert(mode)
|
||||
def helper_pickle_string(
|
||||
pickle, protocol=0, test_file="Tests/images/hopper.jpg", mode=None
|
||||
):
|
||||
with Image.open(test_file) as im:
|
||||
if mode:
|
||||
im = im.convert(mode)
|
||||
|
||||
# Act
|
||||
with open(filename, "wb") as f:
|
||||
pickle.dump(im, f, protocol)
|
||||
with open(filename, "rb") as f:
|
||||
loaded_im = pickle.load(f)
|
||||
# Act
|
||||
dumped_string = pickle.dumps(im, protocol)
|
||||
loaded_im = pickle.loads(dumped_string)
|
||||
|
||||
# Assert
|
||||
assert im == loaded_im
|
||||
# Assert
|
||||
assert im == loaded_im
|
||||
|
||||
def helper_pickle_string(
|
||||
self, pickle, protocol=0, test_file="Tests/images/hopper.jpg", mode=None
|
||||
):
|
||||
with Image.open(test_file) as im:
|
||||
if mode:
|
||||
im = im.convert(mode)
|
||||
|
||||
# Act
|
||||
dumped_string = pickle.dumps(im, protocol)
|
||||
loaded_im = pickle.loads(dumped_string)
|
||||
def test_pickle_image(tmp_path):
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
helper_pickle_string(pickle, protocol)
|
||||
helper_pickle_file(tmp_path, pickle, protocol)
|
||||
|
||||
# Assert
|
||||
assert im == loaded_im
|
||||
|
||||
def test_pickle_image(self):
|
||||
# Act / Assert
|
||||
def test_pickle_p_mode():
|
||||
# Act / Assert
|
||||
for test_file in [
|
||||
"Tests/images/test-card.png",
|
||||
"Tests/images/zero_bb.png",
|
||||
"Tests/images/zero_bb_scale2.png",
|
||||
"Tests/images/non_zero_bb.png",
|
||||
"Tests/images/non_zero_bb_scale2.png",
|
||||
"Tests/images/p_trns_single.png",
|
||||
"Tests/images/pil123p.png",
|
||||
"Tests/images/itxt_chunks.png",
|
||||
]:
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
self.helper_pickle_string(pickle, protocol)
|
||||
self.helper_pickle_file(pickle, protocol)
|
||||
helper_pickle_string(pickle, protocol=protocol, test_file=test_file)
|
||||
|
||||
def test_pickle_p_mode(self):
|
||||
# Act / Assert
|
||||
for test_file in [
|
||||
"Tests/images/test-card.png",
|
||||
"Tests/images/zero_bb.png",
|
||||
"Tests/images/zero_bb_scale2.png",
|
||||
"Tests/images/non_zero_bb.png",
|
||||
"Tests/images/non_zero_bb_scale2.png",
|
||||
"Tests/images/p_trns_single.png",
|
||||
"Tests/images/pil123p.png",
|
||||
"Tests/images/itxt_chunks.png",
|
||||
]:
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
self.helper_pickle_string(
|
||||
pickle, protocol=protocol, test_file=test_file
|
||||
)
|
||||
|
||||
def test_pickle_pa_mode(self):
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
self.helper_pickle_string(pickle, protocol, mode="PA")
|
||||
self.helper_pickle_file(pickle, protocol, mode="PA")
|
||||
def test_pickle_pa_mode(tmp_path):
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
helper_pickle_string(pickle, protocol, mode="PA")
|
||||
helper_pickle_file(tmp_path, pickle, protocol, mode="PA")
|
||||
|
||||
def test_pickle_l_mode(self):
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
self.helper_pickle_string(pickle, protocol, mode="L")
|
||||
self.helper_pickle_file(pickle, protocol, mode="L")
|
||||
|
||||
def test_pickle_la_mode_with_palette(self):
|
||||
# Arrange
|
||||
filename = self.tempfile("temp.pkl")
|
||||
with Image.open("Tests/images/hopper.jpg") as im:
|
||||
im = im.convert("PA")
|
||||
def test_pickle_l_mode(tmp_path):
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
helper_pickle_string(pickle, protocol, mode="L")
|
||||
helper_pickle_file(tmp_path, pickle, protocol, mode="L")
|
||||
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
im.mode = "LA"
|
||||
with open(filename, "wb") as f:
|
||||
pickle.dump(im, f, protocol)
|
||||
with open(filename, "rb") as f:
|
||||
loaded_im = pickle.load(f)
|
||||
|
||||
im.mode = "PA"
|
||||
assert im == loaded_im
|
||||
def test_pickle_la_mode_with_palette(tmp_path):
|
||||
# Arrange
|
||||
filename = str(tmp_path / "temp.pkl")
|
||||
with Image.open("Tests/images/hopper.jpg") as im:
|
||||
im = im.convert("PA")
|
||||
|
||||
# Act / Assert
|
||||
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||
im.mode = "LA"
|
||||
with open(filename, "wb") as f:
|
||||
pickle.dump(im, f, protocol)
|
||||
with open(filename, "rb") as f:
|
||||
loaded_im = pickle.load(f)
|
||||
|
||||
im.mode = "PA"
|
||||
assert im == loaded_im
|
||||
|
|
Loading…
Reference in New Issue
Block a user