Converted to pytest

This commit is contained in:
Andrew Murray 2020-02-25 20:57:27 +11:00
parent 80994bc0e5
commit 09b9198176
14 changed files with 1190 additions and 1144 deletions

View File

@ -3,109 +3,108 @@ import os
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_similar from .helper import assert_image_similar
base = os.path.join("Tests", "images", "bmp") base = os.path.join("Tests", "images", "bmp")
class TestBmpReference(PillowTestCase): def get_files(d, ext=".bmp"):
def get_files(self, d, ext=".bmp"): return [
return [ os.path.join(base, d, f) for f in os.listdir(os.path.join(base, d)) if ext in f
os.path.join(base, d, f) ]
for f in os.listdir(os.path.join(base, d))
if ext in f
]
def test_bad(self):
""" These shouldn't crash/dos, but they shouldn't return anything
either """
for f in self.get_files("b"):
def open(f): def test_bad():
try: """ These shouldn't crash/dos, but they shouldn't return anything
with Image.open(f) as im: either """
im.load() for f in get_files("b"):
except Exception: # as msg:
pass
# Assert that there is no unclosed file warning def open(f):
pytest.warns(None, open, f)
def test_questionable(self):
""" These shouldn't crash/dos, but it's not well defined that these
are in spec """
supported = [
"pal8os2v2.bmp",
"rgb24prof.bmp",
"pal1p1.bmp",
"pal8offs.bmp",
"rgb24lprof.bmp",
"rgb32fakealpha.bmp",
"rgb24largepal.bmp",
"pal8os2sp.bmp",
"rgb32bf-xbgr.bmp",
]
for f in self.get_files("q"):
try: try:
with Image.open(f) as im: with Image.open(f) as im:
im.load() im.load()
if os.path.basename(f) not in supported:
print("Please add %s to the partially supported bmp specs." % f)
except Exception: # as msg: except Exception: # as msg:
if os.path.basename(f) in supported: pass
raise
def test_good(self): # Assert that there is no unclosed file warning
""" These should all work. There's a set of target files in the pytest.warns(None, open, f)
html directory that we can compare against. """
# Target files, if they're not just replacing the extension
file_map = {
"pal1wb.bmp": "pal1.png",
"pal4rle.bmp": "pal4.png",
"pal8-0.bmp": "pal8.png",
"pal8rle.bmp": "pal8.png",
"pal8topdown.bmp": "pal8.png",
"pal8nonsquare.bmp": "pal8nonsquare-v.png",
"pal8os2.bmp": "pal8.png",
"pal8os2sp.bmp": "pal8.png",
"pal8os2v2.bmp": "pal8.png",
"pal8os2v2-16.bmp": "pal8.png",
"pal8v4.bmp": "pal8.png",
"pal8v5.bmp": "pal8.png",
"rgb16-565pal.bmp": "rgb16-565.png",
"rgb24pal.bmp": "rgb24.png",
"rgb32.bmp": "rgb24.png",
"rgb32bf.bmp": "rgb24.png",
}
def get_compare(f): def test_questionable():
name = os.path.split(f)[1] """ These shouldn't crash/dos, but it's not well defined that these
if name in file_map: are in spec """
return os.path.join(base, "html", file_map[name]) supported = [
name = os.path.splitext(name)[0] "pal8os2v2.bmp",
return os.path.join(base, "html", "%s.png" % name) "rgb24prof.bmp",
"pal1p1.bmp",
"pal8offs.bmp",
"rgb24lprof.bmp",
"rgb32fakealpha.bmp",
"rgb24largepal.bmp",
"pal8os2sp.bmp",
"rgb32bf-xbgr.bmp",
]
for f in get_files("q"):
try:
with Image.open(f) as im:
im.load()
if os.path.basename(f) not in supported:
print("Please add %s to the partially supported bmp specs." % f)
except Exception: # as msg:
if os.path.basename(f) in supported:
raise
for f in self.get_files("g"):
try:
with Image.open(f) as im:
im.load()
with Image.open(get_compare(f)) as compare:
compare.load()
if im.mode == "P":
# assert image similar doesn't really work
# with paletized image, since the palette might
# be differently ordered for an equivalent image.
im = im.convert("RGBA")
compare = im.convert("RGBA")
assert_image_similar(im, compare, 5)
except Exception as msg: def test_good():
# there are three here that are unsupported: """ These should all work. There's a set of target files in the
unsupported = ( html directory that we can compare against. """
os.path.join(base, "g", "rgb32bf.bmp"),
os.path.join(base, "g", "pal8rle.bmp"), # Target files, if they're not just replacing the extension
os.path.join(base, "g", "pal4rle.bmp"), file_map = {
) "pal1wb.bmp": "pal1.png",
if f not in unsupported: "pal4rle.bmp": "pal4.png",
self.fail("Unsupported Image {}: {}".format(f, msg)) "pal8-0.bmp": "pal8.png",
"pal8rle.bmp": "pal8.png",
"pal8topdown.bmp": "pal8.png",
"pal8nonsquare.bmp": "pal8nonsquare-v.png",
"pal8os2.bmp": "pal8.png",
"pal8os2sp.bmp": "pal8.png",
"pal8os2v2.bmp": "pal8.png",
"pal8os2v2-16.bmp": "pal8.png",
"pal8v4.bmp": "pal8.png",
"pal8v5.bmp": "pal8.png",
"rgb16-565pal.bmp": "rgb16-565.png",
"rgb24pal.bmp": "rgb24.png",
"rgb32.bmp": "rgb24.png",
"rgb32bf.bmp": "rgb24.png",
}
def get_compare(f):
name = os.path.split(f)[1]
if name in file_map:
return os.path.join(base, "html", file_map[name])
name = os.path.splitext(name)[0]
return os.path.join(base, "html", "%s.png" % name)
for f in get_files("g"):
try:
with Image.open(f) as im:
im.load()
with Image.open(get_compare(f)) as compare:
compare.load()
if im.mode == "P":
# assert image similar doesn't really work
# with paletized image, since the palette might
# be differently ordered for an equivalent image.
im = im.convert("RGBA")
compare = im.convert("RGBA")
assert_image_similar(im, compare, 5)
except Exception as msg:
# there are three here that are unsupported:
unsupported = (
os.path.join(base, "g", "rgb32bf.bmp"),
os.path.join(base, "g", "pal8rle.bmp"),
os.path.join(base, "g", "pal4rle.bmp"),
)
assert f in unsupported, "Unsupported Image {}: {}".format(f, msg)

View File

@ -1,20 +1,21 @@
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal from .helper import assert_image_equal
class TestFileBlp(PillowTestCase): def test_load_blp2_raw():
def test_load_blp2_raw(self): with Image.open("Tests/images/blp/blp2_raw.blp") as im:
with Image.open("Tests/images/blp/blp2_raw.blp") as im: with Image.open("Tests/images/blp/blp2_raw.png") as target:
with Image.open("Tests/images/blp/blp2_raw.png") as target: assert_image_equal(im, target)
assert_image_equal(im, target)
def test_load_blp2_dxt1(self):
with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
with Image.open("Tests/images/blp/blp2_dxt1.png") as target:
assert_image_equal(im, target)
def test_load_blp2_dxt1a(self): def test_load_blp2_dxt1():
with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im: with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
with Image.open("Tests/images/blp/blp2_dxt1a.png") as target: with Image.open("Tests/images/blp/blp2_dxt1.png") as target:
assert_image_equal(im, target) assert_image_equal(im, target)
def test_load_blp2_dxt1a():
with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im:
with Image.open("Tests/images/blp/blp2_dxt1a.png") as target:
assert_image_equal(im, target)

View File

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

View File

@ -1,18 +1,15 @@
from PIL import Image from PIL import Image
from .helper import PillowTestCase
def test_load_raw():
with Image.open("Tests/images/hopper.pcd") as im:
im.load() # should not segfault.
class TestFilePcd(PillowTestCase): # Note that this image was created with a resized hopper
def test_load_raw(self): # image, which was then converted to pcd with imagemagick
with Image.open("Tests/images/hopper.pcd") as im: # and the colors are wonky in Pillow. It's unclear if this
im.load() # should not segfault. # is a pillow or a convert issue, as other images not generated
# from convert look find on pillow and not imagemagick.
# Note that this image was created with a resized hopper # target = hopper().resize((768,512))
# image, which was then converted to pcd with imagemagick # assert_image_similar(im, target, 10)
# and the colors are wonky in Pillow. It's unclear if this
# is a pillow or a convert issue, as other images not generated
# from convert look find on pillow and not imagemagick.
# target = hopper().resize((768,512))
# assert_image_similar(im, target, 10)

View File

@ -1,77 +1,82 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper from .helper import assert_image_equal, assert_image_similar, hopper
# sample ppm stream # sample ppm stream
test_file = "Tests/images/hopper.ppm" TEST_FILE = "Tests/images/hopper.ppm"
class TestFilePpm(PillowTestCase): def test_sanity():
def test_sanity(self): with Image.open(TEST_FILE) as im:
with Image.open(test_file) as im: im.load()
im.load() assert im.mode == "RGB"
assert im.mode == "RGB" assert im.size == (128, 128)
assert im.size == (128, 128) assert im.format, "PPM"
assert im.format, "PPM" assert im.get_format_mimetype() == "image/x-portable-pixmap"
assert im.get_format_mimetype() == "image/x-portable-pixmap"
def test_16bit_pgm(self):
with Image.open("Tests/images/16_bit_binary.pgm") as im:
im.load()
assert im.mode == "I"
assert im.size == (20, 100)
assert im.get_format_mimetype() == "image/x-portable-graymap"
with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt: def test_16bit_pgm():
assert_image_equal(im, tgt) with Image.open("Tests/images/16_bit_binary.pgm") as im:
im.load()
assert im.mode == "I"
assert im.size == (20, 100)
assert im.get_format_mimetype() == "image/x-portable-graymap"
def test_16bit_pgm_write(self): with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt:
with Image.open("Tests/images/16_bit_binary.pgm") as im: assert_image_equal(im, tgt)
im.load()
f = self.tempfile("temp.pgm")
im.save(f, "PPM")
with Image.open(f) as reloaded: def test_16bit_pgm_write(tmp_path):
assert_image_equal(im, reloaded) with Image.open("Tests/images/16_bit_binary.pgm") as im:
im.load()
def test_pnm(self): f = str(tmp_path / "temp.pgm")
with Image.open("Tests/images/hopper.pnm") as im: im.save(f, "PPM")
assert_image_similar(im, hopper(), 0.0001)
f = self.tempfile("temp.pnm") with Image.open(f) as reloaded:
im.save(f) assert_image_equal(im, reloaded)
with Image.open(f) as reloaded:
assert_image_equal(im, reloaded)
def test_truncated_file(self): def test_pnm(tmp_path):
path = self.tempfile("temp.pgm") with Image.open("Tests/images/hopper.pnm") as im:
with open(path, "w") as f: assert_image_similar(im, hopper(), 0.0001)
f.write("P6")
with pytest.raises(ValueError): f = str(tmp_path / "temp.pnm")
Image.open(path) im.save(f)
def test_neg_ppm(self): with Image.open(f) as reloaded:
# Storage.c accepted negative values for xsize, ysize. the assert_image_equal(im, reloaded)
# internal open_ppm function didn't check for sanity but it
# has been removed. The default opener doesn't accept negative
# sizes.
with pytest.raises(IOError):
Image.open("Tests/images/negative_size.ppm")
def test_mimetypes(self): def test_truncated_file(tmp_path):
path = self.tempfile("temp.pgm") path = str(tmp_path / "temp.pgm")
with open(path, "w") as f:
f.write("P6")
with open(path, "w") as f: with pytest.raises(ValueError):
f.write("P4\n128 128\n255") Image.open(path)
with Image.open(path) as im:
assert im.get_format_mimetype() == "image/x-portable-bitmap"
with open(path, "w") as f:
f.write("PyCMYK\n128 128\n255") def test_neg_ppm():
with Image.open(path) as im: # Storage.c accepted negative values for xsize, ysize. the
assert im.get_format_mimetype() == "image/x-portable-anymap" # internal open_ppm function didn't check for sanity but it
# has been removed. The default opener doesn't accept negative
# sizes.
with pytest.raises(IOError):
Image.open("Tests/images/negative_size.ppm")
def test_mimetypes(tmp_path):
path = str(tmp_path / "temp.pgm")
with open(path, "w") as f:
f.write("P4\n128 128\n255")
with Image.open(path) as im:
assert im.get_format_mimetype() == "image/x-portable-bitmap"
with open(path, "w") as f:
f.write("PyCMYK\n128 128\n255")
with Image.open(path) as im:
assert im.get_format_mimetype() == "image/x-portable-anymap"

View File

@ -1,92 +1,100 @@
import pytest import pytest
from PIL import Image, SgiImagePlugin from PIL import Image, SgiImagePlugin
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper from .helper import assert_image_equal, assert_image_similar, hopper
class TestFileSgi(PillowTestCase): def test_rgb():
def test_rgb(self): # Created with ImageMagick then renamed:
# Created with ImageMagick then renamed: # convert hopper.ppm -compress None sgi:hopper.rgb
# convert hopper.ppm -compress None sgi:hopper.rgb test_file = "Tests/images/hopper.rgb"
test_file = "Tests/images/hopper.rgb"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert_image_equal(im, hopper()) assert_image_equal(im, hopper())
assert im.get_format_mimetype() == "image/rgb" assert im.get_format_mimetype() == "image/rgb"
def test_rgb16(self):
test_file = "Tests/images/hopper16.rgb"
with Image.open(test_file) as im: def test_rgb16():
assert_image_equal(im, hopper()) test_file = "Tests/images/hopper16.rgb"
def test_l(self): with Image.open(test_file) as im:
# Created with ImageMagick assert_image_equal(im, hopper())
# convert hopper.ppm -monochrome -compress None sgi:hopper.bw
test_file = "Tests/images/hopper.bw"
with Image.open(test_file) as im:
assert_image_similar(im, hopper("L"), 2)
assert im.get_format_mimetype() == "image/sgi"
def test_rgba(self): def test_l():
# Created with ImageMagick: # Created with ImageMagick
# convert transparent.png -compress None transparent.sgi # convert hopper.ppm -monochrome -compress None sgi:hopper.bw
test_file = "Tests/images/transparent.sgi" test_file = "Tests/images/hopper.bw"
with Image.open(test_file) as im: with Image.open(test_file) as im:
with Image.open("Tests/images/transparent.png") as target: assert_image_similar(im, hopper("L"), 2)
assert_image_equal(im, target) assert im.get_format_mimetype() == "image/sgi"
assert im.get_format_mimetype() == "image/sgi"
def test_rle(self):
# Created with ImageMagick:
# convert hopper.ppm hopper.sgi
test_file = "Tests/images/hopper.sgi"
with Image.open(test_file) as im: def test_rgba():
with Image.open("Tests/images/hopper.rgb") as target: # Created with ImageMagick:
assert_image_equal(im, target) # convert transparent.png -compress None transparent.sgi
test_file = "Tests/images/transparent.sgi"
def test_rle16(self): with Image.open(test_file) as im:
test_file = "Tests/images/tv16.sgi" with Image.open("Tests/images/transparent.png") as target:
assert_image_equal(im, target)
assert im.get_format_mimetype() == "image/sgi"
with Image.open(test_file) as im:
with Image.open("Tests/images/tv.rgb") as target:
assert_image_equal(im, target)
def test_invalid_file(self): def test_rle():
invalid_file = "Tests/images/flower.jpg" # Created with ImageMagick:
# convert hopper.ppm hopper.sgi
test_file = "Tests/images/hopper.sgi"
with pytest.raises(ValueError): with Image.open(test_file) as im:
SgiImagePlugin.SgiImageFile(invalid_file) with Image.open("Tests/images/hopper.rgb") as target:
assert_image_equal(im, target)
def test_write(self):
def roundtrip(img):
out = self.tempfile("temp.sgi")
img.save(out, format="sgi")
with Image.open(out) as reloaded:
assert_image_equal(img, reloaded)
for mode in ("L", "RGB", "RGBA"): def test_rle16():
roundtrip(hopper(mode)) test_file = "Tests/images/tv16.sgi"
# Test 1 dimension for an L mode image with Image.open(test_file) as im:
roundtrip(Image.new("L", (10, 1))) with Image.open("Tests/images/tv.rgb") as target:
assert_image_equal(im, target)
def test_write16(self):
test_file = "Tests/images/hopper16.rgb"
with Image.open(test_file) as im: def test_invalid_file():
out = self.tempfile("temp.sgi") invalid_file = "Tests/images/flower.jpg"
im.save(out, format="sgi", bpc=2)
with Image.open(out) as reloaded: with pytest.raises(ValueError):
assert_image_equal(im, reloaded) SgiImagePlugin.SgiImageFile(invalid_file)
def test_unsupported_mode(self):
im = hopper("LA")
out = self.tempfile("temp.sgi")
with pytest.raises(ValueError): def test_write(tmp_path):
im.save(out, format="sgi") def roundtrip(img):
out = str(tmp_path / "temp.sgi")
img.save(out, format="sgi")
with Image.open(out) as reloaded:
assert_image_equal(img, reloaded)
for mode in ("L", "RGB", "RGBA"):
roundtrip(hopper(mode))
# Test 1 dimension for an L mode image
roundtrip(Image.new("L", (10, 1)))
def test_write16(tmp_path):
test_file = "Tests/images/hopper16.rgb"
with Image.open(test_file) as im:
out = str(tmp_path / "temp.sgi")
im.save(out, format="sgi", bpc=2)
with Image.open(out) as reloaded:
assert_image_equal(im, reloaded)
def test_unsupported_mode(tmp_path):
im = hopper("LA")
out = str(tmp_path / "temp.sgi")
with pytest.raises(ValueError):
im.save(out, format="sgi")

View File

@ -5,321 +5,335 @@ import pytest
from PIL import Image, TiffImagePlugin, TiffTags from PIL import Image, TiffImagePlugin, TiffTags
from PIL.TiffImagePlugin import IFDRational from PIL.TiffImagePlugin import IFDRational
from .helper import PillowTestCase, assert_deep_equal, hopper from .helper import assert_deep_equal, hopper
tag_ids = {info.name: info.value for info in TiffTags.TAGS_V2.values()} TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
class TestFileTiffMetadata(PillowTestCase): def test_rt_metadata(tmp_path):
def test_rt_metadata(self): """ Test writing arbitrary metadata into the tiff image directory
""" Test writing arbitrary metadata into the tiff image directory Use case is ImageJ private tags, one numeric, one arbitrary
Use case is ImageJ private tags, one numeric, one arbitrary data. https://github.com/python-pillow/Pillow/issues/291
data. https://github.com/python-pillow/Pillow/issues/291 """
"""
img = hopper()
img = hopper()
# Behaviour change: re #1416
# Behaviour change: re #1416 # Pre ifd rewrite, ImageJMetaData was being written as a string(2),
# Pre ifd rewrite, ImageJMetaData was being written as a string(2), # Post ifd rewrite, it's defined as arbitrary bytes(7). It should
# Post ifd rewrite, it's defined as arbitrary bytes(7). It should # roundtrip with the actual bytes, rather than stripped text
# roundtrip with the actual bytes, rather than stripped text # of the premerge tests.
# of the premerge tests. #
# # For text items, we still have to decode('ascii','replace') because
# For text items, we still have to decode('ascii','replace') because # the tiff file format can't take 8 bit bytes in that field.
# the tiff file format can't take 8 bit bytes in that field.
basetextdata = "This is some arbitrary metadata for a text field"
basetextdata = "This is some arbitrary metadata for a text field" bindata = basetextdata.encode("ascii") + b" \xff"
bindata = basetextdata.encode("ascii") + b" \xff" textdata = basetextdata + " " + chr(255)
textdata = basetextdata + " " + chr(255) reloaded_textdata = basetextdata + " ?"
reloaded_textdata = basetextdata + " ?" floatdata = 12.345
floatdata = 12.345 doubledata = 67.89
doubledata = 67.89 info = TiffImagePlugin.ImageFileDirectory()
info = TiffImagePlugin.ImageFileDirectory()
ImageJMetaData = TAG_IDS["ImageJMetaData"]
ImageJMetaData = tag_ids["ImageJMetaData"] ImageJMetaDataByteCounts = TAG_IDS["ImageJMetaDataByteCounts"]
ImageJMetaDataByteCounts = tag_ids["ImageJMetaDataByteCounts"] ImageDescription = TAG_IDS["ImageDescription"]
ImageDescription = tag_ids["ImageDescription"]
info[ImageJMetaDataByteCounts] = len(bindata)
info[ImageJMetaDataByteCounts] = len(bindata) info[ImageJMetaData] = bindata
info[ImageJMetaData] = bindata info[TAG_IDS["RollAngle"]] = floatdata
info[tag_ids["RollAngle"]] = floatdata info.tagtype[TAG_IDS["RollAngle"]] = 11
info.tagtype[tag_ids["RollAngle"]] = 11 info[TAG_IDS["YawAngle"]] = doubledata
info[tag_ids["YawAngle"]] = doubledata info.tagtype[TAG_IDS["YawAngle"]] = 12
info.tagtype[tag_ids["YawAngle"]] = 12
info[ImageDescription] = textdata
info[ImageDescription] = textdata
f = str(tmp_path / "temp.tif")
f = self.tempfile("temp.tif")
img.save(f, tiffinfo=info)
img.save(f, tiffinfo=info)
with Image.open(f) as loaded:
with Image.open(f) as loaded:
assert loaded.tag[ImageJMetaDataByteCounts] == (len(bindata),)
assert loaded.tag[ImageJMetaDataByteCounts] == (len(bindata),) assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bindata),)
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bindata),)
assert loaded.tag[ImageJMetaData] == bindata
assert loaded.tag[ImageJMetaData] == bindata assert loaded.tag_v2[ImageJMetaData] == bindata
assert loaded.tag_v2[ImageJMetaData] == bindata
assert loaded.tag[ImageDescription] == (reloaded_textdata,)
assert loaded.tag[ImageDescription] == (reloaded_textdata,) assert loaded.tag_v2[ImageDescription] == reloaded_textdata
assert loaded.tag_v2[ImageDescription] == reloaded_textdata
loaded_float = loaded.tag[TAG_IDS["RollAngle"]][0]
loaded_float = loaded.tag[tag_ids["RollAngle"]][0] assert round(abs(loaded_float - floatdata), 5) == 0
assert round(abs(loaded_float - floatdata), 5) == 0 loaded_double = loaded.tag[TAG_IDS["YawAngle"]][0]
loaded_double = loaded.tag[tag_ids["YawAngle"]][0] assert round(abs(loaded_double - doubledata), 7) == 0
assert round(abs(loaded_double - doubledata), 7) == 0
# check with 2 element ImageJMetaDataByteCounts, issue #2006
# check with 2 element ImageJMetaDataByteCounts, issue #2006
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8) img.save(f, tiffinfo=info)
img.save(f, tiffinfo=info) with Image.open(f) as loaded:
with Image.open(f) as loaded:
assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8) assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
def test_read_metadata(self): def test_read_metadata():
with Image.open("Tests/images/hopper_g4.tif") as img: with Image.open("Tests/images/hopper_g4.tif") as img:
assert { assert {
"YResolution": IFDRational(4294967295, 113653537), "YResolution": IFDRational(4294967295, 113653537),
"PlanarConfiguration": 1, "PlanarConfiguration": 1,
"BitsPerSample": (1,), "BitsPerSample": (1,),
"ImageLength": 128, "ImageLength": 128,
"Compression": 4, "Compression": 4,
"FillOrder": 1, "FillOrder": 1,
"RowsPerStrip": 128, "RowsPerStrip": 128,
"ResolutionUnit": 3, "ResolutionUnit": 3,
"PhotometricInterpretation": 0, "PhotometricInterpretation": 0,
"PageNumber": (0, 1), "PageNumber": (0, 1),
"XResolution": IFDRational(4294967295, 113653537), "XResolution": IFDRational(4294967295, 113653537),
"ImageWidth": 128, "ImageWidth": 128,
"Orientation": 1, "Orientation": 1,
"StripByteCounts": (1968,), "StripByteCounts": (1968,),
"SamplesPerPixel": 1, "SamplesPerPixel": 1,
"StripOffsets": (8,), "StripOffsets": (8,),
} == img.tag_v2.named() } == img.tag_v2.named()
assert { assert {
"YResolution": ((4294967295, 113653537),), "YResolution": ((4294967295, 113653537),),
"PlanarConfiguration": (1,), "PlanarConfiguration": (1,),
"BitsPerSample": (1,), "BitsPerSample": (1,),
"ImageLength": (128,), "ImageLength": (128,),
"Compression": (4,), "Compression": (4,),
"FillOrder": (1,), "FillOrder": (1,),
"RowsPerStrip": (128,), "RowsPerStrip": (128,),
"ResolutionUnit": (3,), "ResolutionUnit": (3,),
"PhotometricInterpretation": (0,), "PhotometricInterpretation": (0,),
"PageNumber": (0, 1), "PageNumber": (0, 1),
"XResolution": ((4294967295, 113653537),), "XResolution": ((4294967295, 113653537),),
"ImageWidth": (128,), "ImageWidth": (128,),
"Orientation": (1,), "Orientation": (1,),
"StripByteCounts": (1968,), "StripByteCounts": (1968,),
"SamplesPerPixel": (1,), "SamplesPerPixel": (1,),
"StripOffsets": (8,), "StripOffsets": (8,),
} == img.tag.named() } == img.tag.named()
def test_write_metadata(self):
""" Test metadata writing through the python code """ def test_write_metadata(tmp_path):
with Image.open("Tests/images/hopper.tif") as img: """ Test metadata writing through the python code """
f = self.tempfile("temp.tiff") with Image.open("Tests/images/hopper.tif") as img:
img.save(f, tiffinfo=img.tag) f = str(tmp_path / "temp.tiff")
img.save(f, tiffinfo=img.tag)
original = img.tag_v2.named()
original = img.tag_v2.named()
with Image.open(f) as loaded:
reloaded = loaded.tag_v2.named() with Image.open(f) as loaded:
reloaded = loaded.tag_v2.named()
ignored = ["StripByteCounts", "RowsPerStrip", "PageNumber", "StripOffsets"]
ignored = ["StripByteCounts", "RowsPerStrip", "PageNumber", "StripOffsets"]
for tag, value in reloaded.items():
if tag in ignored:
continue
if isinstance(original[tag], tuple) and isinstance(
original[tag][0], IFDRational
):
# Need to compare element by element in the tuple,
# not comparing tuples of object references
assert_deep_equal(
original[tag],
value,
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
)
else:
assert original[tag] == value, "{} didn't roundtrip, {}, {}".format(
tag, original[tag], value
)
for tag, value in original.items():
if tag not in ignored:
assert value == reloaded[tag], "%s didn't roundtrip" % tag
def test_no_duplicate_50741_tag(self):
assert tag_ids["MakerNoteSafety"] == 50741
assert tag_ids["BestQualityScale"] == 50780
def test_empty_metadata(self):
f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
head = f.read(8)
info = TiffImagePlugin.ImageFileDirectory(head)
# Should not raise struct.error.
pytest.warns(UserWarning, info.load, f)
def test_iccprofile(self):
# https://github.com/python-pillow/Pillow/issues/1462
out = self.tempfile("temp.tiff")
with Image.open("Tests/images/hopper.iccprofile.tif") as im:
im.save(out)
with Image.open(out) as reloaded:
assert not isinstance(im.info["icc_profile"], tuple)
assert im.info["icc_profile"] == reloaded.info["icc_profile"]
def test_iccprofile_binary(self):
# https://github.com/python-pillow/Pillow/issues/1526
# We should be able to load this,
# but probably won't be able to save it.
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
assert im.tag_v2.tagtype[34675] == 1
assert im.info["icc_profile"]
def test_iccprofile_save_png(self):
with Image.open("Tests/images/hopper.iccprofile.tif") as im:
outfile = self.tempfile("temp.png")
im.save(outfile)
def test_iccprofile_binary_save_png(self):
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
outfile = self.tempfile("temp.png")
im.save(outfile)
def test_exif_div_zero(self):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
info[41988] = TiffImagePlugin.IFDRational(0, 0)
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert 0 == reloaded.tag_v2[41988].numerator
assert 0 == reloaded.tag_v2[41988].denominator
def test_ifd_unsigned_rational(self):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
max_long = 2 ** 32 - 1
# 4 bytes unsigned long
numerator = max_long
info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert max_long == reloaded.tag_v2[41493].numerator
assert 1 == reloaded.tag_v2[41493].denominator
# out of bounds of 4 byte unsigned long
numerator = max_long + 1
info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert max_long == reloaded.tag_v2[41493].numerator
assert 1 == reloaded.tag_v2[41493].denominator
def test_ifd_signed_rational(self):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
# pair of 4 byte signed longs
numerator = 2 ** 31 - 1
denominator = -(2 ** 31)
info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
out = self.tempfile("temp.tiff") for tag, value in reloaded.items():
im.save(out, tiffinfo=info, compression="raw") if tag in ignored:
continue
if isinstance(original[tag], tuple) and isinstance(
original[tag][0], IFDRational
):
# Need to compare element by element in the tuple,
# not comparing tuples of object references
assert_deep_equal(
original[tag],
value,
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
)
else:
assert original[tag] == value, "{} didn't roundtrip, {}, {}".format(
tag, original[tag], value
)
with Image.open(out) as reloaded: for tag, value in original.items():
assert numerator == reloaded.tag_v2[37380].numerator if tag not in ignored:
assert denominator == reloaded.tag_v2[37380].denominator assert value == reloaded[tag], "%s didn't roundtrip" % tag
numerator = -(2 ** 31)
denominator = 2 ** 31 - 1
info[37380] = TiffImagePlugin.IFDRational(numerator, denominator) def test_no_duplicate_50741_tag():
assert TAG_IDS["MakerNoteSafety"] == 50741
assert TAG_IDS["BestQualityScale"] == 50780
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded: def test_empty_metadata():
assert numerator == reloaded.tag_v2[37380].numerator f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
assert denominator == reloaded.tag_v2[37380].denominator head = f.read(8)
info = TiffImagePlugin.ImageFileDirectory(head)
# Should not raise struct.error.
pytest.warns(UserWarning, info.load, f)
# out of bounds of 4 byte signed long
numerator = -(2 ** 31) - 1
denominator = 1
info[37380] = TiffImagePlugin.IFDRational(numerator, denominator) def test_iccprofile(tmp_path):
# https://github.com/python-pillow/Pillow/issues/1462
out = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper.iccprofile.tif") as im:
im.save(out)
out = self.tempfile("temp.tiff") with Image.open(out) as reloaded:
im.save(out, tiffinfo=info, compression="raw") assert not isinstance(im.info["icc_profile"], tuple)
assert im.info["icc_profile"] == reloaded.info["icc_profile"]
with Image.open(out) as reloaded:
assert 2 ** 31 - 1 == reloaded.tag_v2[37380].numerator
assert -1 == reloaded.tag_v2[37380].denominator
def test_ifd_signed_long(self): def test_iccprofile_binary():
im = hopper() # https://github.com/python-pillow/Pillow/issues/1526
info = TiffImagePlugin.ImageFileDirectory_v2() # We should be able to load this,
# but probably won't be able to save it.
info[37000] = -60000 with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
assert im.tag_v2.tagtype[34675] == 1
assert im.info["icc_profile"]
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded: def test_iccprofile_save_png(tmp_path):
assert reloaded.tag_v2[37000] == -60000 with Image.open("Tests/images/hopper.iccprofile.tif") as im:
outfile = str(tmp_path / "temp.png")
im.save(outfile)
def test_empty_values(self):
data = io.BytesIO(
b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
b"\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a "
b"text\x00\x00"
)
head = data.read(8)
info = TiffImagePlugin.ImageFileDirectory_v2(head)
info.load(data)
# Should not raise ValueError.
info = dict(info)
assert 33432 in info
def test_PhotoshopInfo(self): def test_iccprofile_binary_save_png(tmp_path):
with Image.open("Tests/images/issue_2278.tif") as im: with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
assert len(im.tag_v2[34377]) == 1 outfile = str(tmp_path / "temp.png")
assert isinstance(im.tag_v2[34377][0], bytes) im.save(outfile)
out = self.tempfile("temp.tiff")
im.save(out)
with Image.open(out) as reloaded:
assert len(reloaded.tag_v2[34377]) == 1
assert isinstance(reloaded.tag_v2[34377][0], bytes)
def test_too_many_entries(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()
# 277: ("SamplesPerPixel", SHORT, 1), def test_exif_div_zero(tmp_path):
ifd._tagdata[277] = struct.pack("hh", 4, 4) im = hopper()
ifd.tagtype[277] = TiffTags.SHORT info = TiffImagePlugin.ImageFileDirectory_v2()
info[41988] = TiffImagePlugin.IFDRational(0, 0)
# Should not raise ValueError. out = str(tmp_path / "temp.tiff")
pytest.warns(UserWarning, lambda: ifd[277]) im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert 0 == reloaded.tag_v2[41988].numerator
assert 0 == reloaded.tag_v2[41988].denominator
def test_ifd_unsigned_rational(tmp_path):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
max_long = 2 ** 32 - 1
# 4 bytes unsigned long
numerator = max_long
info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert max_long == reloaded.tag_v2[41493].numerator
assert 1 == reloaded.tag_v2[41493].denominator
# out of bounds of 4 byte unsigned long
numerator = max_long + 1
info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert max_long == reloaded.tag_v2[41493].numerator
assert 1 == reloaded.tag_v2[41493].denominator
def test_ifd_signed_rational(tmp_path):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
# pair of 4 byte signed longs
numerator = 2 ** 31 - 1
denominator = -(2 ** 31)
info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert numerator == reloaded.tag_v2[37380].numerator
assert denominator == reloaded.tag_v2[37380].denominator
numerator = -(2 ** 31)
denominator = 2 ** 31 - 1
info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert numerator == reloaded.tag_v2[37380].numerator
assert denominator == reloaded.tag_v2[37380].denominator
# out of bounds of 4 byte signed long
numerator = -(2 ** 31) - 1
denominator = 1
info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert 2 ** 31 - 1 == reloaded.tag_v2[37380].numerator
assert -1 == reloaded.tag_v2[37380].denominator
def test_ifd_signed_long(tmp_path):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
info[37000] = -60000
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
with Image.open(out) as reloaded:
assert reloaded.tag_v2[37000] == -60000
def test_empty_values():
data = io.BytesIO(
b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
b"\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a "
b"text\x00\x00"
)
head = data.read(8)
info = TiffImagePlugin.ImageFileDirectory_v2(head)
info.load(data)
# Should not raise ValueError.
info = dict(info)
assert 33432 in info
def test_PhotoshopInfo(tmp_path):
with Image.open("Tests/images/issue_2278.tif") as im:
assert len(im.tag_v2[34377]) == 1
assert isinstance(im.tag_v2[34377][0], bytes)
out = str(tmp_path / "temp.tiff")
im.save(out)
with Image.open(out) as reloaded:
assert len(reloaded.tag_v2[34377]) == 1
assert isinstance(reloaded.tag_v2[34377][0], bytes)
def test_too_many_entries():
ifd = TiffImagePlugin.ImageFileDirectory_v2()
# 277: ("SamplesPerPixel", SHORT, 1),
ifd._tagdata[277] = struct.pack("hh", 4, 4)
ifd.tagtype[277] = TiffTags.SHORT
# Should not raise ValueError.
pytest.warns(UserWarning, lambda: ifd[277])

View File

@ -3,142 +3,134 @@ import itertools
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_similar, hopper from .helper import assert_image_similar, hopper
class TestFormatHSV(PillowTestCase): def int_to_float(i):
def int_to_float(self, i): return i / 255
return i / 255
def str_to_float(self, i):
return ord(i) / 255
def tuple_to_ints(self, tp): def str_to_float(i):
x, y, z = tp return ord(i) / 255
return int(x * 255.0), int(y * 255.0), int(z * 255.0)
def test_sanity(self):
Image.new("HSV", (100, 100))
def wedge(self): def tuple_to_ints(tp):
w = Image._wedge() x, y, z = tp
w90 = w.rotate(90) return int(x * 255.0), int(y * 255.0), int(z * 255.0)
(px, h) = w.size
r = Image.new("L", (px * 3, h)) def test_sanity():
g = r.copy() Image.new("HSV", (100, 100))
b = r.copy()
r.paste(w, (0, 0))
r.paste(w90, (px, 0))
g.paste(w90, (0, 0)) def wedge():
g.paste(w, (2 * px, 0)) w = Image._wedge()
w90 = w.rotate(90)
b.paste(w, (px, 0)) (px, h) = w.size
b.paste(w90, (2 * px, 0))
img = Image.merge("RGB", (r, g, b)) r = Image.new("L", (px * 3, h))
g = r.copy()
b = r.copy()
return img r.paste(w, (0, 0))
r.paste(w90, (px, 0))
def to_xxx_colorsys(self, im, func, mode): g.paste(w90, (0, 0))
# convert the hard way using the library colorsys routines. g.paste(w, (2 * px, 0))
(r, g, b) = im.split() b.paste(w, (px, 0))
b.paste(w90, (2 * px, 0))
conv_func = self.int_to_float img = Image.merge("RGB", (r, g, b))
converted = [ return img
self.tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
for (_r, _g, _b) in itertools.zip_longest(
r.tobytes(), g.tobytes(), b.tobytes()
)
]
new_bytes = b"".join(
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
)
hsv = Image.frombytes(mode, r.size, new_bytes) def to_xxx_colorsys(im, func, mode):
# convert the hard way using the library colorsys routines.
return hsv (r, g, b) = im.split()
def to_hsv_colorsys(self, im): conv_func = int_to_float
return self.to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
def to_rgb_colorsys(self, im): converted = [
return self.to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB") tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
for (_r, _g, _b) in itertools.zip_longest(r.tobytes(), g.tobytes(), b.tobytes())
]
def test_wedge(self): new_bytes = b"".join(
src = self.wedge().resize((3 * 32, 32), Image.BILINEAR) bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
im = src.convert("HSV") )
comparable = self.to_hsv_colorsys(src)
assert_image_similar( hsv = Image.frombytes(mode, r.size, new_bytes)
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
im.getchannel(1),
comparable.getchannel(1),
1,
"Saturation conversion is wrong",
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
)
comparable = src return hsv
im = im.convert("RGB")
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong"
)
assert_image_similar(
im.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong"
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong"
)
def test_convert(self): def to_hsv_colorsys(im):
im = hopper("RGB").convert("HSV") return to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
comparable = self.to_hsv_colorsys(hopper("RGB"))
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
im.getchannel(1),
comparable.getchannel(1),
1,
"Saturation conversion is wrong",
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
)
def test_hsv_to_rgb(self): def to_rgb_colorsys(im):
comparable = self.to_hsv_colorsys(hopper("RGB")) return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
converted = comparable.convert("RGB")
comparable = self.to_rgb_colorsys(comparable)
assert_image_similar(
converted.getchannel(0), def test_wedge():
comparable.getchannel(0), src = wedge().resize((3 * 32, 32), Image.BILINEAR)
3, im = src.convert("HSV")
"R conversion is wrong", comparable = to_hsv_colorsys(src)
)
assert_image_similar( assert_image_similar(
converted.getchannel(1), im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
comparable.getchannel(1), )
3, assert_image_similar(
"G conversion is wrong", im.getchannel(1), comparable.getchannel(1), 1, "Saturation conversion is wrong",
) )
assert_image_similar( assert_image_similar(
converted.getchannel(2), im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
comparable.getchannel(2), )
3,
"B conversion is wrong", comparable = src
) im = im.convert("RGB")
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong"
)
assert_image_similar(
im.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong"
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong"
)
def test_convert():
im = hopper("RGB").convert("HSV")
comparable = to_hsv_colorsys(hopper("RGB"))
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
im.getchannel(1), comparable.getchannel(1), 1, "Saturation conversion is wrong",
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
)
def test_hsv_to_rgb():
comparable = to_hsv_colorsys(hopper("RGB"))
converted = comparable.convert("RGB")
comparable = to_rgb_colorsys(comparable)
assert_image_similar(
converted.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong",
)
assert_image_similar(
converted.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong",
)
assert_image_similar(
converted.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong",
)

View File

@ -1,250 +1,261 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import ( from .helper import assert_image, assert_image_equal, assert_image_similar, hopper
PillowTestCase,
assert_image,
assert_image_equal,
assert_image_similar,
hopper,
)
class TestImageConvert(PillowTestCase): def test_sanity():
def test_sanity(self): def convert(im, mode):
def convert(im, mode): out = im.convert(mode)
out = im.convert(mode) assert out.mode == mode
assert out.mode == mode assert out.size == im.size
assert out.size == im.size
modes = ( modes = (
"1", "1",
"L", "L",
"LA", "LA",
"P", "P",
"PA", "PA",
"I", "I",
"F", "F",
"RGB", "RGB",
"RGBA", "RGBA",
"RGBX", "RGBX",
"CMYK", "CMYK",
"YCbCr", "YCbCr",
"HSV", "HSV",
) )
for mode in modes:
im = hopper(mode)
for mode in modes: for mode in modes:
im = hopper(mode) convert(im, mode)
for mode in modes:
convert(im, mode)
# Check 0 # Check 0
im = Image.new(mode, (0, 0)) im = Image.new(mode, (0, 0))
for mode in modes: for mode in modes:
convert(im, mode) convert(im, mode)
def test_default(self):
im = hopper("P") def test_default():
assert_image(im, "P", im.size)
im = im.convert()
assert_image(im, "RGB", im.size)
im = im.convert()
assert_image(im, "RGB", im.size)
# ref https://github.com/python-pillow/Pillow/issues/274 im = hopper("P")
assert_image(im, "P", im.size)
im = im.convert()
assert_image(im, "RGB", im.size)
im = im.convert()
assert_image(im, "RGB", im.size)
def _test_float_conversion(self, im):
orig = im.getpixel((5, 5))
converted = im.convert("F").getpixel((5, 5))
assert orig == converted
def test_8bit(self): # ref https://github.com/python-pillow/Pillow/issues/274
with Image.open("Tests/images/hopper.jpg") as im:
self._test_float_conversion(im.convert("L"))
def test_16bit(self):
with Image.open("Tests/images/16bit.cropped.tif") as im:
self._test_float_conversion(im)
def test_16bit_workaround(self): def _test_float_conversion(im):
with Image.open("Tests/images/16bit.cropped.tif") as im: orig = im.getpixel((5, 5))
self._test_float_conversion(im.convert("I")) converted = im.convert("F").getpixel((5, 5))
assert orig == converted
def test_rgba_p(self):
im = hopper("RGBA")
im.putalpha(hopper("L"))
converted = im.convert("P") def test_8bit():
comparable = converted.convert("RGBA") with Image.open("Tests/images/hopper.jpg") as im:
_test_float_conversion(im.convert("L"))
assert_image_similar(im, comparable, 20)
def test_trns_p(self): def test_16bit():
im = hopper("P") with Image.open("Tests/images/16bit.cropped.tif") as im:
im.info["transparency"] = 0 _test_float_conversion(im)
f = self.tempfile("temp.png")
im_l = im.convert("L") def test_16bit_workaround():
assert im_l.info["transparency"] == 0 # undone with Image.open("Tests/images/16bit.cropped.tif") as im:
im_l.save(f) _test_float_conversion(im.convert("I"))
im_rgb = im.convert("RGB")
assert im_rgb.info["transparency"] == (0, 0, 0) # undone
im_rgb.save(f)
# ref https://github.com/python-pillow/Pillow/issues/664 def test_rgba_p():
im = hopper("RGBA")
im.putalpha(hopper("L"))
def test_trns_p_rgba(self): converted = im.convert("P")
# Arrange comparable = converted.convert("RGBA")
im = hopper("P")
im.info["transparency"] = 128
# Act assert_image_similar(im, comparable, 20)
im_rgba = im.convert("RGBA")
# Assert
assert "transparency" not in im_rgba.info
# https://github.com/python-pillow/Pillow/issues/2702
assert im_rgba.palette is None
def test_trns_l(self): def test_trns_p(tmp_path):
im = hopper("L") im = hopper("P")
im.info["transparency"] = 128 im.info["transparency"] = 0
f = self.tempfile("temp.png") f = str(tmp_path / "temp.png")
im_rgb = im.convert("RGB") im_l = im.convert("L")
assert im_rgb.info["transparency"] == (128, 128, 128) # undone assert im_l.info["transparency"] == 0 # undone
im_rgb.save(f) im_l.save(f)
im_rgb = im.convert("RGB")
assert im_rgb.info["transparency"] == (0, 0, 0) # undone
im_rgb.save(f)
# ref https://github.com/python-pillow/Pillow/issues/664
def test_trns_p_rgba():
# Arrange
im = hopper("P")
im.info["transparency"] = 128
# Act
im_rgba = im.convert("RGBA")
# Assert
assert "transparency" not in im_rgba.info
# https://github.com/python-pillow/Pillow/issues/2702
assert im_rgba.palette is None
def test_trns_l(tmp_path):
im = hopper("L")
im.info["transparency"] = 128
f = str(tmp_path / "temp.png")
im_rgb = im.convert("RGB")
assert im_rgb.info["transparency"] == (128, 128, 128) # undone
im_rgb.save(f)
im_p = im.convert("P")
assert "transparency" in im_p.info
im_p.save(f)
im_p = pytest.warns(UserWarning, im.convert, "P", palette=Image.ADAPTIVE)
assert "transparency" not in im_p.info
im_p.save(f)
def test_trns_RGB(tmp_path):
im = hopper("RGB")
im.info["transparency"] = im.getpixel((0, 0))
f = str(tmp_path / "temp.png")
im_l = im.convert("L")
assert im_l.info["transparency"] == im_l.getpixel((0, 0)) # undone
im_l.save(f)
im_p = im.convert("P")
assert "transparency" in im_p.info
im_p.save(f)
im_rgba = im.convert("RGBA")
assert "transparency" not in im_rgba.info
im_rgba.save(f)
im_p = pytest.warns(UserWarning, im.convert, "P", palette=Image.ADAPTIVE)
assert "transparency" not in im_p.info
im_p.save(f)
def test_gif_with_rgba_palette_to_p():
# See https://github.com/python-pillow/Pillow/issues/2433
with Image.open("Tests/images/hopper.gif") as im:
im.info["transparency"] = 255
im.load()
assert im.palette.mode == "RGBA"
im_p = im.convert("P") im_p = im.convert("P")
assert "transparency" in im_p.info
im_p.save(f)
im_p = pytest.warns(UserWarning, im.convert, "P", palette=Image.ADAPTIVE) # Should not raise ValueError: unrecognized raw mode
assert "transparency" not in im_p.info im_p.load()
im_p.save(f)
def test_trns_RGB(self):
def test_p_la():
im = hopper("RGBA")
alpha = hopper("L")
im.putalpha(alpha)
comparable = im.convert("P").convert("LA").getchannel("A")
assert_image_similar(alpha, comparable, 5)
def test_matrix_illegal_conversion():
# Arrange
im = hopper("CMYK")
# fmt: off
matrix = (
0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0)
# fmt: on
assert im.mode != "RGB"
# Act / Assert
with pytest.raises(ValueError):
im.convert(mode="CMYK", matrix=matrix)
def test_matrix_wrong_mode():
# Arrange
im = hopper("L")
# fmt: off
matrix = (
0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0)
# fmt: on
assert im.mode == "L"
# Act / Assert
with pytest.raises(ValueError):
im.convert(mode="L", matrix=matrix)
def test_matrix_xyz():
def matrix_convert(mode):
# Arrange
im = hopper("RGB") im = hopper("RGB")
im.info["transparency"] = im.getpixel((0, 0)) im.info["transparency"] = (255, 0, 0)
f = self.tempfile("temp.png")
im_l = im.convert("L")
assert im_l.info["transparency"] == im_l.getpixel((0, 0)) # undone
im_l.save(f)
im_p = im.convert("P")
assert "transparency" in im_p.info
im_p.save(f)
im_rgba = im.convert("RGBA")
assert "transparency" not in im_rgba.info
im_rgba.save(f)
im_p = pytest.warns(UserWarning, im.convert, "P", palette=Image.ADAPTIVE)
assert "transparency" not in im_p.info
im_p.save(f)
def test_gif_with_rgba_palette_to_p(self):
# See https://github.com/python-pillow/Pillow/issues/2433
with Image.open("Tests/images/hopper.gif") as im:
im.info["transparency"] = 255
im.load()
assert im.palette.mode == "RGBA"
im_p = im.convert("P")
# Should not raise ValueError: unrecognized raw mode
im_p.load()
def test_p_la(self):
im = hopper("RGBA")
alpha = hopper("L")
im.putalpha(alpha)
comparable = im.convert("P").convert("LA").getchannel("A")
assert_image_similar(alpha, comparable, 5)
def test_matrix_illegal_conversion(self):
# Arrange
im = hopper("CMYK")
# fmt: off # fmt: off
matrix = ( matrix = (
0.412453, 0.357580, 0.180423, 0, 0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0, 0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0) 0.019334, 0.119193, 0.950227, 0)
# fmt: on # fmt: on
assert im.mode != "RGB"
# Act / Assert
with pytest.raises(ValueError):
im.convert(mode="CMYK", matrix=matrix)
def test_matrix_wrong_mode(self):
# Arrange
im = hopper("L")
# fmt: off
matrix = (
0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0)
# fmt: on
assert im.mode == "L"
# Act / Assert
with pytest.raises(ValueError):
im.convert(mode="L", matrix=matrix)
def test_matrix_xyz(self):
def matrix_convert(mode):
# Arrange
im = hopper("RGB")
im.info["transparency"] = (255, 0, 0)
# fmt: off
matrix = (
0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0)
# fmt: on
assert im.mode == "RGB"
# Act
# Convert an RGB image to the CIE XYZ colour space
converted_im = im.convert(mode=mode, matrix=matrix)
# Assert
assert converted_im.mode == mode
assert converted_im.size == im.size
with Image.open("Tests/images/hopper-XYZ.png") as target:
if converted_im.mode == "RGB":
assert_image_similar(converted_im, target, 3)
assert converted_im.info["transparency"] == (105, 54, 4)
else:
assert_image_similar(converted_im, target.getchannel(0), 1)
assert converted_im.info["transparency"] == 105
matrix_convert("RGB")
matrix_convert("L")
def test_matrix_identity(self):
# Arrange
im = hopper("RGB")
# fmt: off
identity_matrix = (
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0)
# fmt: on
assert im.mode == "RGB" assert im.mode == "RGB"
# Act # Act
# Convert with an identity matrix # Convert an RGB image to the CIE XYZ colour space
converted_im = im.convert(mode="RGB", matrix=identity_matrix) converted_im = im.convert(mode=mode, matrix=matrix)
# Assert # Assert
# No change assert converted_im.mode == mode
assert_image_equal(converted_im, im) assert converted_im.size == im.size
with Image.open("Tests/images/hopper-XYZ.png") as target:
if converted_im.mode == "RGB":
assert_image_similar(converted_im, target, 3)
assert converted_im.info["transparency"] == (105, 54, 4)
else:
assert_image_similar(converted_im, target.getchannel(0), 1)
assert converted_im.info["transparency"] == 105
matrix_convert("RGB")
matrix_convert("L")
def test_matrix_identity():
# Arrange
im = hopper("RGB")
# fmt: off
identity_matrix = (
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0)
# fmt: on
assert im.mode == "RGB"
# Act
# Convert with an identity matrix
converted_im = im.convert(mode="RGB", matrix=identity_matrix)
# Assert
# No change
assert_image_equal(converted_im, im)

View File

@ -1,62 +1,63 @@
from PIL import Image, features from PIL import Image, features
from .helper import PillowTestCase, assert_image_equal, hopper from .helper import assert_image_equal, hopper
class TestImageSplit(PillowTestCase): def test_split():
def test_split(self): def split(mode):
def split(mode): layers = hopper(mode).split()
layers = hopper(mode).split() return [(i.mode, i.size[0], i.size[1]) for i in layers]
return [(i.mode, i.size[0], i.size[1]) for i in layers]
assert split("1") == [("1", 128, 128)] assert split("1") == [("1", 128, 128)]
assert split("L") == [("L", 128, 128)] assert split("L") == [("L", 128, 128)]
assert split("I") == [("I", 128, 128)] assert split("I") == [("I", 128, 128)]
assert split("F") == [("F", 128, 128)] assert split("F") == [("F", 128, 128)]
assert split("P") == [("P", 128, 128)] assert split("P") == [("P", 128, 128)]
assert split("RGB") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)] assert split("RGB") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)]
assert split("RGBA") == [ assert split("RGBA") == [
("L", 128, 128), ("L", 128, 128),
("L", 128, 128), ("L", 128, 128),
("L", 128, 128), ("L", 128, 128),
("L", 128, 128), ("L", 128, 128),
] ]
assert split("CMYK") == [ assert split("CMYK") == [
("L", 128, 128), ("L", 128, 128),
("L", 128, 128), ("L", 128, 128),
("L", 128, 128), ("L", 128, 128),
("L", 128, 128), ("L", 128, 128),
] ]
assert split("YCbCr") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)] assert split("YCbCr") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)]
def test_split_merge(self):
def split_merge(mode):
return Image.merge(mode, hopper(mode).split())
assert_image_equal(hopper("1"), split_merge("1")) def test_split_merge():
assert_image_equal(hopper("L"), split_merge("L")) def split_merge(mode):
assert_image_equal(hopper("I"), split_merge("I")) return Image.merge(mode, hopper(mode).split())
assert_image_equal(hopper("F"), split_merge("F"))
assert_image_equal(hopper("P"), split_merge("P"))
assert_image_equal(hopper("RGB"), split_merge("RGB"))
assert_image_equal(hopper("RGBA"), split_merge("RGBA"))
assert_image_equal(hopper("CMYK"), split_merge("CMYK"))
assert_image_equal(hopper("YCbCr"), split_merge("YCbCr"))
def test_split_open(self): assert_image_equal(hopper("1"), split_merge("1"))
if features.check("zlib"): assert_image_equal(hopper("L"), split_merge("L"))
test_file = self.tempfile("temp.png") assert_image_equal(hopper("I"), split_merge("I"))
else: assert_image_equal(hopper("F"), split_merge("F"))
test_file = self.tempfile("temp.pcx") assert_image_equal(hopper("P"), split_merge("P"))
assert_image_equal(hopper("RGB"), split_merge("RGB"))
assert_image_equal(hopper("RGBA"), split_merge("RGBA"))
assert_image_equal(hopper("CMYK"), split_merge("CMYK"))
assert_image_equal(hopper("YCbCr"), split_merge("YCbCr"))
def split_open(mode):
hopper(mode).save(test_file)
with Image.open(test_file) as im:
return len(im.split())
assert split_open("1") == 1 def test_split_open(tmp_path):
assert split_open("L") == 1 if features.check("zlib"):
assert split_open("P") == 1 test_file = str(tmp_path / "temp.png")
assert split_open("RGB") == 3 else:
if features.check("zlib"): test_file = str(tmp_path / "temp.pcx")
assert split_open("RGBA") == 4
def split_open(mode):
hopper(mode).save(test_file)
with Image.open(test_file) as im:
return len(im.split())
assert split_open("1") == 1
assert split_open("L") == 1
assert split_open("P") == 1
assert split_open("RGB") == 3
if features.check("zlib"):
assert split_open("RGBA") == 4

View File

@ -1,140 +1,149 @@
import pytest import pytest
from PIL import Image, ImagePalette from PIL import Image, ImagePalette
from .helper import PillowTestCase, assert_image_equal from .helper import assert_image_equal
class TestImagePalette(PillowTestCase): def test_sanity():
def test_sanity(self):
ImagePalette.ImagePalette("RGB", list(range(256)) * 3) ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
with pytest.raises(ValueError): with pytest.raises(ValueError):
ImagePalette.ImagePalette("RGB", list(range(256)) * 2) ImagePalette.ImagePalette("RGB", list(range(256)) * 2)
def test_getcolor(self):
palette = ImagePalette.ImagePalette() def test_getcolor():
test_map = {} palette = ImagePalette.ImagePalette()
for i in range(256):
test_map[palette.getcolor((i, i, i))] = i
assert len(test_map) == 256 test_map = {}
with pytest.raises(ValueError): for i in range(256):
palette.getcolor((1, 2, 3)) test_map[palette.getcolor((i, i, i))] = i
# Test unknown color specifier assert len(test_map) == 256
with pytest.raises(ValueError): with pytest.raises(ValueError):
palette.getcolor("unknown") palette.getcolor((1, 2, 3))
def test_file(self): # Test unknown color specifier
with pytest.raises(ValueError):
palette.getcolor("unknown")
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
f = self.tempfile("temp.lut") def test_file(tmp_path):
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
f = str(tmp_path / "temp.lut")
palette.save(f)
p = ImagePalette.load(f)
# load returns raw palette information
assert len(p[0]) == 768
assert p[1] == "RGB"
p = ImagePalette.raw(p[1], p[0])
assert isinstance(p, ImagePalette.ImagePalette)
assert p.palette == palette.tobytes()
def test_make_linear_lut():
# Arrange
black = 0
white = 255
# Act
lut = ImagePalette.make_linear_lut(black, white)
# Assert
assert isinstance(lut, list)
assert len(lut) == 256
# Check values
for i in range(0, len(lut)):
assert lut[i] == i
def test_make_linear_lut_not_yet_implemented():
# Update after FIXME
# Arrange
black = 1
white = 255
# Act
with pytest.raises(NotImplementedError):
ImagePalette.make_linear_lut(black, white)
def test_make_gamma_lut():
# Arrange
exp = 5
# Act
lut = ImagePalette.make_gamma_lut(exp)
# Assert
assert isinstance(lut, list)
assert len(lut) == 256
# Check a few values
assert lut[0] == 0
assert lut[63] == 0
assert lut[127] == 8
assert lut[191] == 60
assert lut[255] == 255
def test_rawmode_valueerrors(tmp_path):
# Arrange
palette = ImagePalette.raw("RGB", list(range(256)) * 3)
# Act / Assert
with pytest.raises(ValueError):
palette.tobytes()
with pytest.raises(ValueError):
palette.getcolor((1, 2, 3))
f = str(tmp_path / "temp.lut")
with pytest.raises(ValueError):
palette.save(f) palette.save(f)
p = ImagePalette.load(f)
# load returns raw palette information def test_getdata():
assert len(p[0]) == 768 # Arrange
assert p[1] == "RGB" data_in = list(range(256)) * 3
palette = ImagePalette.ImagePalette("RGB", data_in)
p = ImagePalette.raw(p[1], p[0]) # Act
assert isinstance(p, ImagePalette.ImagePalette) mode, data_out = palette.getdata()
assert p.palette == palette.tobytes()
def test_make_linear_lut(self): # Assert
# Arrange assert mode == "RGB;L"
black = 0
white = 255
# Act
lut = ImagePalette.make_linear_lut(black, white)
# Assert def test_rawmode_getdata():
assert isinstance(lut, list) # Arrange
assert len(lut) == 256 data_in = list(range(256)) * 3
# Check values palette = ImagePalette.raw("RGB", data_in)
for i in range(0, len(lut)):
assert lut[i] == i
def test_make_linear_lut_not_yet_implemented(self): # Act
# Update after FIXME rawmode, data_out = palette.getdata()
# Arrange
black = 1
white = 255
# Act # Assert
with pytest.raises(NotImplementedError): assert rawmode == "RGB"
ImagePalette.make_linear_lut(black, white) assert data_in == data_out
def test_make_gamma_lut(self):
# Arrange
exp = 5
# Act def test_2bit_palette(tmp_path):
lut = ImagePalette.make_gamma_lut(exp) # issue #2258, 2 bit palettes are corrupted.
outfile = str(tmp_path / "temp.png")
# Assert rgb = b"\x00" * 2 + b"\x01" * 2 + b"\x02" * 2
assert isinstance(lut, list) img = Image.frombytes("P", (6, 1), rgb)
assert len(lut) == 256 img.putpalette(b"\xFF\x00\x00\x00\xFF\x00\x00\x00\xFF") # RGB
# Check a few values img.save(outfile, format="PNG")
assert lut[0] == 0
assert lut[63] == 0
assert lut[127] == 8
assert lut[191] == 60
assert lut[255] == 255
def test_rawmode_valueerrors(self): with Image.open(outfile) as reloaded:
# Arrange assert_image_equal(img, reloaded)
palette = ImagePalette.raw("RGB", list(range(256)) * 3)
# Act / Assert
with pytest.raises(ValueError):
palette.tobytes()
with pytest.raises(ValueError):
palette.getcolor((1, 2, 3))
f = self.tempfile("temp.lut")
with pytest.raises(ValueError):
palette.save(f)
def test_getdata(self): def test_invalid_palette():
# Arrange with pytest.raises(IOError):
data_in = list(range(256)) * 3 ImagePalette.load("Tests/images/hopper.jpg")
palette = ImagePalette.ImagePalette("RGB", data_in)
# Act
mode, data_out = palette.getdata()
# Assert
assert mode == "RGB;L"
def test_rawmode_getdata(self):
# Arrange
data_in = list(range(256)) * 3
palette = ImagePalette.raw("RGB", data_in)
# Act
rawmode, data_out = palette.getdata()
# Assert
assert rawmode == "RGB"
assert data_in == data_out
def test_2bit_palette(self):
# issue #2258, 2 bit palettes are corrupted.
outfile = self.tempfile("temp.png")
rgb = b"\x00" * 2 + b"\x01" * 2 + b"\x02" * 2
img = Image.frombytes("P", (6, 1), rgb)
img.putpalette(b"\xFF\x00\x00\x00\xFF\x00\x00\x00\xFF") # RGB
img.save(outfile, format="PNG")
with Image.open(outfile) as reloaded:
assert_image_equal(img, reloaded)
def test_invalid_palette(self):
with pytest.raises(IOError):
ImagePalette.load("Tests/images/hopper.jpg")

View File

@ -1,98 +1,105 @@
import pytest import pytest
from PIL import Image, ImageSequence, TiffImagePlugin from PIL import Image, ImageSequence, TiffImagePlugin
from .helper import PillowTestCase, assert_image_equal, hopper, skip_unless_feature from .helper import assert_image_equal, hopper, skip_unless_feature
class TestImageSequence(PillowTestCase): def test_sanity(tmp_path):
def test_sanity(self):
test_file = self.tempfile("temp.im") test_file = str(tmp_path / "temp.im")
im = hopper("RGB") im = hopper("RGB")
im.save(test_file) im.save(test_file)
seq = ImageSequence.Iterator(im) seq = ImageSequence.Iterator(im)
index = 0 index = 0
for frame in seq: for frame in seq:
assert_image_equal(im, frame) assert_image_equal(im, frame)
assert im.tell() == index assert im.tell() == index
index += 1 index += 1
assert index == 1 assert index == 1
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
ImageSequence.Iterator(0) ImageSequence.Iterator(0)
def test_iterator(self):
with Image.open("Tests/images/multipage.tiff") as im:
i = ImageSequence.Iterator(im)
for index in range(0, im.n_frames):
assert i[index] == next(i)
with pytest.raises(IndexError):
i[index + 1]
with pytest.raises(StopIteration):
next(i)
def test_iterator_min_frame(self): def test_iterator():
with Image.open("Tests/images/hopper.psd") as im: with Image.open("Tests/images/multipage.tiff") as im:
i = ImageSequence.Iterator(im) i = ImageSequence.Iterator(im)
for index in range(1, im.n_frames): for index in range(0, im.n_frames):
assert i[index] == next(i) assert i[index] == next(i)
with pytest.raises(IndexError):
i[index + 1]
with pytest.raises(StopIteration):
next(i)
def _test_multipage_tiff(self):
with Image.open("Tests/images/multipage.tiff") as im:
for index, frame in enumerate(ImageSequence.Iterator(im)):
frame.load()
assert index == im.tell()
frame.convert("RGB")
def test_tiff(self): def test_iterator_min_frame():
self._test_multipage_tiff() with Image.open("Tests/images/hopper.psd") as im:
i = ImageSequence.Iterator(im)
for index in range(1, im.n_frames):
assert i[index] == next(i)
@skip_unless_feature("libtiff")
def test_libtiff(self):
TiffImagePlugin.READ_LIBTIFF = True
self._test_multipage_tiff()
TiffImagePlugin.READ_LIBTIFF = False
def test_consecutive(self): def _test_multipage_tiff():
with Image.open("Tests/images/multipage.tiff") as im: with Image.open("Tests/images/multipage.tiff") as im:
firstFrame = None for index, frame in enumerate(ImageSequence.Iterator(im)):
for frame in ImageSequence.Iterator(im): frame.load()
if firstFrame is None: assert index == im.tell()
firstFrame = frame.copy() frame.convert("RGB")
for frame in ImageSequence.Iterator(im):
assert_image_equal(frame, firstFrame)
break
def test_palette_mmap(self):
# Using mmap in ImageFile can require to reload the palette.
with Image.open("Tests/images/multipage-mmap.tiff") as im:
color1 = im.getpalette()[0:3]
im.seek(0)
color2 = im.getpalette()[0:3]
assert color1 == color2
def test_all_frames(self): def test_tiff():
# Test a single image _test_multipage_tiff()
with Image.open("Tests/images/iss634.gif") as im:
ims = ImageSequence.all_frames(im)
assert len(ims) == 42
for i, im_frame in enumerate(ims):
assert im_frame is not im
im.seek(i) @skip_unless_feature("libtiff")
assert_image_equal(im, im_frame) def test_libtiff():
TiffImagePlugin.READ_LIBTIFF = True
_test_multipage_tiff()
TiffImagePlugin.READ_LIBTIFF = False
# Test a series of images
ims = ImageSequence.all_frames([im, hopper(), im])
assert len(ims) == 85
# Test an operation def test_consecutive():
ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90)) with Image.open("Tests/images/multipage.tiff") as im:
for i, im_frame in enumerate(ims): firstFrame = None
im.seek(i) for frame in ImageSequence.Iterator(im):
assert_image_equal(im.rotate(90), im_frame) if firstFrame is None:
firstFrame = frame.copy()
for frame in ImageSequence.Iterator(im):
assert_image_equal(frame, firstFrame)
break
def test_palette_mmap():
# Using mmap in ImageFile can require to reload the palette.
with Image.open("Tests/images/multipage-mmap.tiff") as im:
color1 = im.getpalette()[0:3]
im.seek(0)
color2 = im.getpalette()[0:3]
assert color1 == color2
def test_all_frames():
# Test a single image
with Image.open("Tests/images/iss634.gif") as im:
ims = ImageSequence.all_frames(im)
assert len(ims) == 42
for i, im_frame in enumerate(ims):
assert im_frame is not im
im.seek(i)
assert_image_equal(im, im_frame)
# Test a series of images
ims = ImageSequence.all_frames([im, hopper(), im])
assert len(ims) == 85
# Test an operation
ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90))
for i, im_frame in enumerate(ims):
im.seek(i)
assert_image_equal(im.rotate(90), im_frame)

View File

@ -3,56 +3,58 @@ from fractions import Fraction
from PIL import Image, TiffImagePlugin, features from PIL import Image, TiffImagePlugin, features
from PIL.TiffImagePlugin import IFDRational from PIL.TiffImagePlugin import IFDRational
from .helper import PillowTestCase, hopper from .helper import hopper
class Test_IFDRational(PillowTestCase): def _test_equal(num, denom, target):
def _test_equal(self, num, denom, target):
t = IFDRational(num, denom) t = IFDRational(num, denom)
assert target == t assert target == t
assert t == target assert t == target
def test_sanity(self):
self._test_equal(1, 1, 1) def test_sanity():
self._test_equal(1, 1, Fraction(1, 1))
self._test_equal(2, 2, 1) _test_equal(1, 1, 1)
self._test_equal(1.0, 1, Fraction(1, 1)) _test_equal(1, 1, Fraction(1, 1))
self._test_equal(Fraction(1, 1), 1, Fraction(1, 1)) _test_equal(2, 2, 1)
self._test_equal(IFDRational(1, 1), 1, 1) _test_equal(1.0, 1, Fraction(1, 1))
self._test_equal(1, 2, Fraction(1, 2)) _test_equal(Fraction(1, 1), 1, Fraction(1, 1))
self._test_equal(1, 2, IFDRational(1, 2)) _test_equal(IFDRational(1, 1), 1, 1)
def test_nonetype(self): _test_equal(1, 2, Fraction(1, 2))
# Fails if the _delegate function doesn't return a valid function _test_equal(1, 2, IFDRational(1, 2))
xres = IFDRational(72)
yres = IFDRational(72)
assert xres._val is not None
assert xres.numerator is not None
assert xres.denominator is not None
assert yres._val is not None
assert xres and 1 def test_nonetype():
assert xres and yres # Fails if the _delegate function doesn't return a valid function
def test_ifd_rational_save(self): xres = IFDRational(72)
methods = (True, False) yres = IFDRational(72)
if not features.check("libtiff"): assert xres._val is not None
methods = (False,) assert xres.numerator is not None
assert xres.denominator is not None
assert yres._val is not None
for libtiff in methods: assert xres and 1
TiffImagePlugin.WRITE_LIBTIFF = libtiff assert xres and yres
im = hopper()
out = self.tempfile("temp.tiff")
res = IFDRational(301, 1)
im.save(out, dpi=(res, res), compression="raw")
with Image.open(out) as reloaded: def test_ifd_rational_save(tmp_path):
assert float(IFDRational(301, 1)) == float(reloaded.tag_v2[282]) methods = (True, False)
if not features.check("libtiff"):
methods = (False,)
for libtiff in methods:
TiffImagePlugin.WRITE_LIBTIFF = libtiff
im = hopper()
out = str(tmp_path / "temp.tiff")
res = IFDRational(301, 1)
im.save(out, dpi=(res, res), compression="raw")
with Image.open(out) as reloaded:
assert float(IFDRational(301, 1)) == float(reloaded.tag_v2[282])

View File

@ -1,13 +1,13 @@
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper from .helper import assert_image_equal, assert_image_similar, hopper
class TestUploader(PillowTestCase): def check_upload_equal():
def check_upload_equal(self): result = hopper("P").convert("RGB")
result = hopper("P").convert("RGB") target = hopper("RGB")
target = hopper("RGB") assert_image_equal(result, target)
assert_image_equal(result, target)
def check_upload_similar(self):
result = hopper("P").convert("RGB") def check_upload_similar():
target = hopper("RGB") result = hopper("P").convert("RGB")
assert_image_similar(result, target, 0) target = hopper("RGB")
assert_image_similar(result, target, 0)