mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Converted to pytest
This commit is contained in:
parent
80994bc0e5
commit
09b9198176
|
@ -3,109 +3,108 @@ import os
|
|||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, assert_image_similar
|
||||
from .helper import assert_image_similar
|
||||
|
||||
base = os.path.join("Tests", "images", "bmp")
|
||||
|
||||
|
||||
class TestBmpReference(PillowTestCase):
|
||||
def get_files(self, d, ext=".bmp"):
|
||||
return [
|
||||
os.path.join(base, d, f)
|
||||
for f in os.listdir(os.path.join(base, d))
|
||||
if ext in f
|
||||
]
|
||||
def get_files(d, ext=".bmp"):
|
||||
return [
|
||||
os.path.join(base, d, f) for f in os.listdir(os.path.join(base, d)) if ext in f
|
||||
]
|
||||
|
||||
def test_bad(self):
|
||||
""" These shouldn't crash/dos, but they shouldn't return anything
|
||||
either """
|
||||
for f in self.get_files("b"):
|
||||
|
||||
def open(f):
|
||||
try:
|
||||
with Image.open(f) as im:
|
||||
im.load()
|
||||
except Exception: # as msg:
|
||||
pass
|
||||
def test_bad():
|
||||
""" These shouldn't crash/dos, but they shouldn't return anything
|
||||
either """
|
||||
for f in get_files("b"):
|
||||
|
||||
# Assert that there is no unclosed file warning
|
||||
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"):
|
||||
def open(f):
|
||||
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
|
||||
pass
|
||||
|
||||
def test_good(self):
|
||||
""" These should all work. There's a set of target files in the
|
||||
html directory that we can compare against. """
|
||||
# Assert that there is no unclosed file warning
|
||||
pytest.warns(None, open, f)
|
||||
|
||||
# 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):
|
||||
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)
|
||||
def test_questionable():
|
||||
""" 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 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:
|
||||
# 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"),
|
||||
)
|
||||
if f not in unsupported:
|
||||
self.fail("Unsupported Image {}: {}".format(f, msg))
|
||||
def test_good():
|
||||
""" These should all work. There's a set of target files in the
|
||||
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):
|
||||
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)
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
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(self):
|
||||
with Image.open("Tests/images/blp/blp2_raw.blp") as im:
|
||||
with Image.open("Tests/images/blp/blp2_raw.png") as target:
|
||||
assert_image_equal(im, target)
|
||||
def test_load_blp2_raw():
|
||||
with Image.open("Tests/images/blp/blp2_raw.blp") as im:
|
||||
with Image.open("Tests/images/blp/blp2_raw.png") as 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):
|
||||
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)
|
||||
def test_load_blp2_dxt1():
|
||||
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():
|
||||
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)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
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(self):
|
||||
with Image.open("Tests/images/ftex_uncompressed.ftu") as im:
|
||||
with Image.open("Tests/images/ftex_uncompressed.png") as target:
|
||||
assert_image_equal(im, target)
|
||||
def test_load_raw():
|
||||
with Image.open("Tests/images/ftex_uncompressed.ftu") as im:
|
||||
with Image.open("Tests/images/ftex_uncompressed.png") as target:
|
||||
assert_image_equal(im, target)
|
||||
|
||||
def test_load_dxt1(self):
|
||||
with Image.open("Tests/images/ftex_dxt1.ftc") as im:
|
||||
with Image.open("Tests/images/ftex_dxt1.png") as target:
|
||||
assert_image_similar(im, target.convert("RGBA"), 15)
|
||||
|
||||
def test_load_dxt1():
|
||||
with Image.open("Tests/images/ftex_dxt1.ftc") as im:
|
||||
with Image.open("Tests/images/ftex_dxt1.png") as target:
|
||||
assert_image_similar(im, target.convert("RGBA"), 15)
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
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):
|
||||
def test_load_raw(self):
|
||||
with Image.open("Tests/images/hopper.pcd") as im:
|
||||
im.load() # should not segfault.
|
||||
# Note that this image was created with a resized hopper
|
||||
# image, which was then converted to pcd with imagemagick
|
||||
# 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.
|
||||
|
||||
# Note that this image was created with a resized hopper
|
||||
# image, which was then converted to pcd with imagemagick
|
||||
# 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)
|
||||
# target = hopper().resize((768,512))
|
||||
# assert_image_similar(im, target, 10)
|
||||
|
|
|
@ -1,77 +1,82 @@
|
|||
import pytest
|
||||
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
|
||||
test_file = "Tests/images/hopper.ppm"
|
||||
TEST_FILE = "Tests/images/hopper.ppm"
|
||||
|
||||
|
||||
class TestFilePpm(PillowTestCase):
|
||||
def test_sanity(self):
|
||||
with Image.open(test_file) as im:
|
||||
im.load()
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
assert im.format, "PPM"
|
||||
assert im.get_format_mimetype() == "image/x-portable-pixmap"
|
||||
def test_sanity():
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.load()
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
assert im.format, "PPM"
|
||||
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:
|
||||
assert_image_equal(im, tgt)
|
||||
def test_16bit_pgm():
|
||||
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") as im:
|
||||
im.load()
|
||||
with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt:
|
||||
assert_image_equal(im, tgt)
|
||||
|
||||
f = self.tempfile("temp.pgm")
|
||||
im.save(f, "PPM")
|
||||
|
||||
with Image.open(f) as reloaded:
|
||||
assert_image_equal(im, reloaded)
|
||||
def test_16bit_pgm_write(tmp_path):
|
||||
with Image.open("Tests/images/16_bit_binary.pgm") as im:
|
||||
im.load()
|
||||
|
||||
def test_pnm(self):
|
||||
with Image.open("Tests/images/hopper.pnm") as im:
|
||||
assert_image_similar(im, hopper(), 0.0001)
|
||||
f = str(tmp_path / "temp.pgm")
|
||||
im.save(f, "PPM")
|
||||
|
||||
f = self.tempfile("temp.pnm")
|
||||
im.save(f)
|
||||
with Image.open(f) as reloaded:
|
||||
assert_image_equal(im, reloaded)
|
||||
|
||||
with Image.open(f) as reloaded:
|
||||
assert_image_equal(im, reloaded)
|
||||
|
||||
def test_truncated_file(self):
|
||||
path = self.tempfile("temp.pgm")
|
||||
with open(path, "w") as f:
|
||||
f.write("P6")
|
||||
def test_pnm(tmp_path):
|
||||
with Image.open("Tests/images/hopper.pnm") as im:
|
||||
assert_image_similar(im, hopper(), 0.0001)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
Image.open(path)
|
||||
f = str(tmp_path / "temp.pnm")
|
||||
im.save(f)
|
||||
|
||||
def test_neg_ppm(self):
|
||||
# Storage.c accepted negative values for xsize, ysize. the
|
||||
# internal open_ppm function didn't check for sanity but it
|
||||
# has been removed. The default opener doesn't accept negative
|
||||
# sizes.
|
||||
with Image.open(f) as reloaded:
|
||||
assert_image_equal(im, reloaded)
|
||||
|
||||
with pytest.raises(IOError):
|
||||
Image.open("Tests/images/negative_size.ppm")
|
||||
|
||||
def test_mimetypes(self):
|
||||
path = self.tempfile("temp.pgm")
|
||||
def test_truncated_file(tmp_path):
|
||||
path = str(tmp_path / "temp.pgm")
|
||||
with open(path, "w") as f:
|
||||
f.write("P6")
|
||||
|
||||
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 pytest.raises(ValueError):
|
||||
Image.open(path)
|
||||
|
||||
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"
|
||||
|
||||
def test_neg_ppm():
|
||||
# Storage.c accepted negative values for xsize, ysize. the
|
||||
# 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"
|
||||
|
|
|
@ -1,92 +1,100 @@
|
|||
import pytest
|
||||
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(self):
|
||||
# Created with ImageMagick then renamed:
|
||||
# convert hopper.ppm -compress None sgi:hopper.rgb
|
||||
test_file = "Tests/images/hopper.rgb"
|
||||
def test_rgb():
|
||||
# Created with ImageMagick then renamed:
|
||||
# convert hopper.ppm -compress None sgi:hopper.rgb
|
||||
test_file = "Tests/images/hopper.rgb"
|
||||
|
||||
with Image.open(test_file) as im:
|
||||
assert_image_equal(im, hopper())
|
||||
assert im.get_format_mimetype() == "image/rgb"
|
||||
with Image.open(test_file) as im:
|
||||
assert_image_equal(im, hopper())
|
||||
assert im.get_format_mimetype() == "image/rgb"
|
||||
|
||||
def test_rgb16(self):
|
||||
test_file = "Tests/images/hopper16.rgb"
|
||||
|
||||
with Image.open(test_file) as im:
|
||||
assert_image_equal(im, hopper())
|
||||
def test_rgb16():
|
||||
test_file = "Tests/images/hopper16.rgb"
|
||||
|
||||
def test_l(self):
|
||||
# Created with ImageMagick
|
||||
# convert hopper.ppm -monochrome -compress None sgi:hopper.bw
|
||||
test_file = "Tests/images/hopper.bw"
|
||||
with Image.open(test_file) as im:
|
||||
assert_image_equal(im, hopper())
|
||||
|
||||
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):
|
||||
# Created with ImageMagick:
|
||||
# convert transparent.png -compress None transparent.sgi
|
||||
test_file = "Tests/images/transparent.sgi"
|
||||
def test_l():
|
||||
# Created with ImageMagick
|
||||
# convert hopper.ppm -monochrome -compress None sgi:hopper.bw
|
||||
test_file = "Tests/images/hopper.bw"
|
||||
|
||||
with Image.open(test_file) as im:
|
||||
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:
|
||||
assert_image_similar(im, hopper("L"), 2)
|
||||
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:
|
||||
with Image.open("Tests/images/hopper.rgb") as target:
|
||||
assert_image_equal(im, target)
|
||||
def test_rgba():
|
||||
# Created with ImageMagick:
|
||||
# convert transparent.png -compress None transparent.sgi
|
||||
test_file = "Tests/images/transparent.sgi"
|
||||
|
||||
def test_rle16(self):
|
||||
test_file = "Tests/images/tv16.sgi"
|
||||
with Image.open(test_file) as im:
|
||||
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):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
def test_rle():
|
||||
# Created with ImageMagick:
|
||||
# convert hopper.ppm hopper.sgi
|
||||
test_file = "Tests/images/hopper.sgi"
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
SgiImagePlugin.SgiImageFile(invalid_file)
|
||||
with Image.open(test_file) as im:
|
||||
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"):
|
||||
roundtrip(hopper(mode))
|
||||
def test_rle16():
|
||||
test_file = "Tests/images/tv16.sgi"
|
||||
|
||||
# Test 1 dimension for an L mode image
|
||||
roundtrip(Image.new("L", (10, 1)))
|
||||
with Image.open(test_file) as im:
|
||||
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:
|
||||
out = self.tempfile("temp.sgi")
|
||||
im.save(out, format="sgi", bpc=2)
|
||||
def test_invalid_file():
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
assert_image_equal(im, reloaded)
|
||||
with pytest.raises(ValueError):
|
||||
SgiImagePlugin.SgiImageFile(invalid_file)
|
||||
|
||||
def test_unsupported_mode(self):
|
||||
im = hopper("LA")
|
||||
out = self.tempfile("temp.sgi")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
im.save(out, format="sgi")
|
||||
def test_write(tmp_path):
|
||||
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")
|
||||
|
|
|
@ -5,321 +5,335 @@ import pytest
|
|||
from PIL import Image, TiffImagePlugin, TiffTags
|
||||
from PIL.TiffImagePlugin import IFDRational
|
||||
|
||||
from .helper import PillowTestCase, assert_deep_equal, hopper
|
||||
|
||||
tag_ids = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
|
||||
|
||||
|
||||
class TestFileTiffMetadata(PillowTestCase):
|
||||
def test_rt_metadata(self):
|
||||
""" Test writing arbitrary metadata into the tiff image directory
|
||||
Use case is ImageJ private tags, one numeric, one arbitrary
|
||||
data. https://github.com/python-pillow/Pillow/issues/291
|
||||
"""
|
||||
|
||||
img = hopper()
|
||||
|
||||
# Behaviour change: re #1416
|
||||
# Pre ifd rewrite, ImageJMetaData was being written as a string(2),
|
||||
# Post ifd rewrite, it's defined as arbitrary bytes(7). It should
|
||||
# roundtrip with the actual bytes, rather than stripped text
|
||||
# of the premerge tests.
|
||||
#
|
||||
# For text items, we still have to decode('ascii','replace') because
|
||||
# the tiff file format can't take 8 bit bytes in that field.
|
||||
|
||||
basetextdata = "This is some arbitrary metadata for a text field"
|
||||
bindata = basetextdata.encode("ascii") + b" \xff"
|
||||
textdata = basetextdata + " " + chr(255)
|
||||
reloaded_textdata = basetextdata + " ?"
|
||||
floatdata = 12.345
|
||||
doubledata = 67.89
|
||||
info = TiffImagePlugin.ImageFileDirectory()
|
||||
|
||||
ImageJMetaData = tag_ids["ImageJMetaData"]
|
||||
ImageJMetaDataByteCounts = tag_ids["ImageJMetaDataByteCounts"]
|
||||
ImageDescription = tag_ids["ImageDescription"]
|
||||
|
||||
info[ImageJMetaDataByteCounts] = len(bindata)
|
||||
info[ImageJMetaData] = bindata
|
||||
info[tag_ids["RollAngle"]] = floatdata
|
||||
info.tagtype[tag_ids["RollAngle"]] = 11
|
||||
info[tag_ids["YawAngle"]] = doubledata
|
||||
info.tagtype[tag_ids["YawAngle"]] = 12
|
||||
|
||||
info[ImageDescription] = textdata
|
||||
|
||||
f = self.tempfile("temp.tif")
|
||||
|
||||
img.save(f, tiffinfo=info)
|
||||
|
||||
with Image.open(f) as loaded:
|
||||
|
||||
assert loaded.tag[ImageJMetaDataByteCounts] == (len(bindata),)
|
||||
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bindata),)
|
||||
|
||||
assert loaded.tag[ImageJMetaData] == bindata
|
||||
assert loaded.tag_v2[ImageJMetaData] == bindata
|
||||
|
||||
assert loaded.tag[ImageDescription] == (reloaded_textdata,)
|
||||
assert loaded.tag_v2[ImageDescription] == reloaded_textdata
|
||||
|
||||
loaded_float = loaded.tag[tag_ids["RollAngle"]][0]
|
||||
assert round(abs(loaded_float - floatdata), 5) == 0
|
||||
loaded_double = loaded.tag[tag_ids["YawAngle"]][0]
|
||||
assert round(abs(loaded_double - doubledata), 7) == 0
|
||||
|
||||
# check with 2 element ImageJMetaDataByteCounts, issue #2006
|
||||
|
||||
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
|
||||
img.save(f, tiffinfo=info)
|
||||
with Image.open(f) as loaded:
|
||||
|
||||
assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
|
||||
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
|
||||
|
||||
def test_read_metadata(self):
|
||||
with Image.open("Tests/images/hopper_g4.tif") as img:
|
||||
|
||||
assert {
|
||||
"YResolution": IFDRational(4294967295, 113653537),
|
||||
"PlanarConfiguration": 1,
|
||||
"BitsPerSample": (1,),
|
||||
"ImageLength": 128,
|
||||
"Compression": 4,
|
||||
"FillOrder": 1,
|
||||
"RowsPerStrip": 128,
|
||||
"ResolutionUnit": 3,
|
||||
"PhotometricInterpretation": 0,
|
||||
"PageNumber": (0, 1),
|
||||
"XResolution": IFDRational(4294967295, 113653537),
|
||||
"ImageWidth": 128,
|
||||
"Orientation": 1,
|
||||
"StripByteCounts": (1968,),
|
||||
"SamplesPerPixel": 1,
|
||||
"StripOffsets": (8,),
|
||||
} == img.tag_v2.named()
|
||||
|
||||
assert {
|
||||
"YResolution": ((4294967295, 113653537),),
|
||||
"PlanarConfiguration": (1,),
|
||||
"BitsPerSample": (1,),
|
||||
"ImageLength": (128,),
|
||||
"Compression": (4,),
|
||||
"FillOrder": (1,),
|
||||
"RowsPerStrip": (128,),
|
||||
"ResolutionUnit": (3,),
|
||||
"PhotometricInterpretation": (0,),
|
||||
"PageNumber": (0, 1),
|
||||
"XResolution": ((4294967295, 113653537),),
|
||||
"ImageWidth": (128,),
|
||||
"Orientation": (1,),
|
||||
"StripByteCounts": (1968,),
|
||||
"SamplesPerPixel": (1,),
|
||||
"StripOffsets": (8,),
|
||||
} == img.tag.named()
|
||||
|
||||
def test_write_metadata(self):
|
||||
""" Test metadata writing through the python code """
|
||||
with Image.open("Tests/images/hopper.tif") as img:
|
||||
f = self.tempfile("temp.tiff")
|
||||
img.save(f, tiffinfo=img.tag)
|
||||
|
||||
original = img.tag_v2.named()
|
||||
|
||||
with Image.open(f) as loaded:
|
||||
reloaded = loaded.tag_v2.named()
|
||||
|
||||
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)
|
||||
from .helper import assert_deep_equal, hopper
|
||||
|
||||
TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
|
||||
|
||||
|
||||
def test_rt_metadata(tmp_path):
|
||||
""" Test writing arbitrary metadata into the tiff image directory
|
||||
Use case is ImageJ private tags, one numeric, one arbitrary
|
||||
data. https://github.com/python-pillow/Pillow/issues/291
|
||||
"""
|
||||
|
||||
img = hopper()
|
||||
|
||||
# Behaviour change: re #1416
|
||||
# Pre ifd rewrite, ImageJMetaData was being written as a string(2),
|
||||
# Post ifd rewrite, it's defined as arbitrary bytes(7). It should
|
||||
# roundtrip with the actual bytes, rather than stripped text
|
||||
# of the premerge tests.
|
||||
#
|
||||
# For text items, we still have to decode('ascii','replace') because
|
||||
# the tiff file format can't take 8 bit bytes in that field.
|
||||
|
||||
basetextdata = "This is some arbitrary metadata for a text field"
|
||||
bindata = basetextdata.encode("ascii") + b" \xff"
|
||||
textdata = basetextdata + " " + chr(255)
|
||||
reloaded_textdata = basetextdata + " ?"
|
||||
floatdata = 12.345
|
||||
doubledata = 67.89
|
||||
info = TiffImagePlugin.ImageFileDirectory()
|
||||
|
||||
ImageJMetaData = TAG_IDS["ImageJMetaData"]
|
||||
ImageJMetaDataByteCounts = TAG_IDS["ImageJMetaDataByteCounts"]
|
||||
ImageDescription = TAG_IDS["ImageDescription"]
|
||||
|
||||
info[ImageJMetaDataByteCounts] = len(bindata)
|
||||
info[ImageJMetaData] = bindata
|
||||
info[TAG_IDS["RollAngle"]] = floatdata
|
||||
info.tagtype[TAG_IDS["RollAngle"]] = 11
|
||||
info[TAG_IDS["YawAngle"]] = doubledata
|
||||
info.tagtype[TAG_IDS["YawAngle"]] = 12
|
||||
|
||||
info[ImageDescription] = textdata
|
||||
|
||||
f = str(tmp_path / "temp.tif")
|
||||
|
||||
img.save(f, tiffinfo=info)
|
||||
|
||||
with Image.open(f) as loaded:
|
||||
|
||||
assert loaded.tag[ImageJMetaDataByteCounts] == (len(bindata),)
|
||||
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bindata),)
|
||||
|
||||
assert loaded.tag[ImageJMetaData] == bindata
|
||||
assert loaded.tag_v2[ImageJMetaData] == bindata
|
||||
|
||||
assert loaded.tag[ImageDescription] == (reloaded_textdata,)
|
||||
assert loaded.tag_v2[ImageDescription] == reloaded_textdata
|
||||
|
||||
loaded_float = loaded.tag[TAG_IDS["RollAngle"]][0]
|
||||
assert round(abs(loaded_float - floatdata), 5) == 0
|
||||
loaded_double = loaded.tag[TAG_IDS["YawAngle"]][0]
|
||||
assert round(abs(loaded_double - doubledata), 7) == 0
|
||||
|
||||
# check with 2 element ImageJMetaDataByteCounts, issue #2006
|
||||
|
||||
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
|
||||
img.save(f, tiffinfo=info)
|
||||
with Image.open(f) as loaded:
|
||||
|
||||
assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
|
||||
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
|
||||
|
||||
|
||||
def test_read_metadata():
|
||||
with Image.open("Tests/images/hopper_g4.tif") as img:
|
||||
|
||||
assert {
|
||||
"YResolution": IFDRational(4294967295, 113653537),
|
||||
"PlanarConfiguration": 1,
|
||||
"BitsPerSample": (1,),
|
||||
"ImageLength": 128,
|
||||
"Compression": 4,
|
||||
"FillOrder": 1,
|
||||
"RowsPerStrip": 128,
|
||||
"ResolutionUnit": 3,
|
||||
"PhotometricInterpretation": 0,
|
||||
"PageNumber": (0, 1),
|
||||
"XResolution": IFDRational(4294967295, 113653537),
|
||||
"ImageWidth": 128,
|
||||
"Orientation": 1,
|
||||
"StripByteCounts": (1968,),
|
||||
"SamplesPerPixel": 1,
|
||||
"StripOffsets": (8,),
|
||||
} == img.tag_v2.named()
|
||||
|
||||
assert {
|
||||
"YResolution": ((4294967295, 113653537),),
|
||||
"PlanarConfiguration": (1,),
|
||||
"BitsPerSample": (1,),
|
||||
"ImageLength": (128,),
|
||||
"Compression": (4,),
|
||||
"FillOrder": (1,),
|
||||
"RowsPerStrip": (128,),
|
||||
"ResolutionUnit": (3,),
|
||||
"PhotometricInterpretation": (0,),
|
||||
"PageNumber": (0, 1),
|
||||
"XResolution": ((4294967295, 113653537),),
|
||||
"ImageWidth": (128,),
|
||||
"Orientation": (1,),
|
||||
"StripByteCounts": (1968,),
|
||||
"SamplesPerPixel": (1,),
|
||||
"StripOffsets": (8,),
|
||||
} == img.tag.named()
|
||||
|
||||
|
||||
def test_write_metadata(tmp_path):
|
||||
""" Test metadata writing through the python code """
|
||||
with Image.open("Tests/images/hopper.tif") as img:
|
||||
f = str(tmp_path / "temp.tiff")
|
||||
img.save(f, tiffinfo=img.tag)
|
||||
|
||||
original = img.tag_v2.named()
|
||||
|
||||
with Image.open(f) as loaded:
|
||||
reloaded = loaded.tag_v2.named()
|
||||
|
||||
ignored = ["StripByteCounts", "RowsPerStrip", "PageNumber", "StripOffsets"]
|
||||
|
||||
out = self.tempfile("temp.tiff")
|
||||
im.save(out, tiffinfo=info, compression="raw")
|
||||
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
|
||||
)
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
assert numerator == reloaded.tag_v2[37380].numerator
|
||||
assert denominator == reloaded.tag_v2[37380].denominator
|
||||
for tag, value in original.items():
|
||||
if tag not in ignored:
|
||||
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:
|
||||
assert numerator == reloaded.tag_v2[37380].numerator
|
||||
assert denominator == reloaded.tag_v2[37380].denominator
|
||||
def test_empty_metadata():
|
||||
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)
|
||||
|
||||
# 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")
|
||||
im.save(out, tiffinfo=info, compression="raw")
|
||||
with Image.open(out) as reloaded:
|
||||
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):
|
||||
im = hopper()
|
||||
info = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
def test_iccprofile_binary():
|
||||
# https://github.com/python-pillow/Pillow/issues/1526
|
||||
# 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:
|
||||
assert reloaded.tag_v2[37000] == -60000
|
||||
def test_iccprofile_save_png(tmp_path):
|
||||
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):
|
||||
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 = 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_iccprofile_binary_save_png(tmp_path):
|
||||
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
|
||||
outfile = str(tmp_path / "temp.png")
|
||||
im.save(outfile)
|
||||
|
||||
def test_too_many_entries(self):
|
||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
|
||||
# 277: ("SamplesPerPixel", SHORT, 1),
|
||||
ifd._tagdata[277] = struct.pack("hh", 4, 4)
|
||||
ifd.tagtype[277] = TiffTags.SHORT
|
||||
def test_exif_div_zero(tmp_path):
|
||||
im = hopper()
|
||||
info = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
info[41988] = TiffImagePlugin.IFDRational(0, 0)
|
||||
|
||||
# Should not raise ValueError.
|
||||
pytest.warns(UserWarning, lambda: ifd[277])
|
||||
out = str(tmp_path / "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(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])
|
||||
|
|
|
@ -3,142 +3,134 @@ import itertools
|
|||
|
||||
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(self, i):
|
||||
return i / 255
|
||||
def int_to_float(i):
|
||||
return i / 255
|
||||
|
||||
def str_to_float(self, i):
|
||||
return ord(i) / 255
|
||||
|
||||
def tuple_to_ints(self, tp):
|
||||
x, y, z = tp
|
||||
return int(x * 255.0), int(y * 255.0), int(z * 255.0)
|
||||
def str_to_float(i):
|
||||
return ord(i) / 255
|
||||
|
||||
def test_sanity(self):
|
||||
Image.new("HSV", (100, 100))
|
||||
|
||||
def wedge(self):
|
||||
w = Image._wedge()
|
||||
w90 = w.rotate(90)
|
||||
def tuple_to_ints(tp):
|
||||
x, y, z = tp
|
||||
return int(x * 255.0), int(y * 255.0), int(z * 255.0)
|
||||
|
||||
(px, h) = w.size
|
||||
|
||||
r = Image.new("L", (px * 3, h))
|
||||
g = r.copy()
|
||||
b = r.copy()
|
||||
def test_sanity():
|
||||
Image.new("HSV", (100, 100))
|
||||
|
||||
r.paste(w, (0, 0))
|
||||
r.paste(w90, (px, 0))
|
||||
|
||||
g.paste(w90, (0, 0))
|
||||
g.paste(w, (2 * px, 0))
|
||||
def wedge():
|
||||
w = Image._wedge()
|
||||
w90 = w.rotate(90)
|
||||
|
||||
b.paste(w, (px, 0))
|
||||
b.paste(w90, (2 * px, 0))
|
||||
(px, h) = w.size
|
||||
|
||||
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):
|
||||
# convert the hard way using the library colorsys routines.
|
||||
g.paste(w90, (0, 0))
|
||||
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 = [
|
||||
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()
|
||||
)
|
||||
]
|
||||
return img
|
||||
|
||||
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):
|
||||
return self.to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
|
||||
conv_func = int_to_float
|
||||
|
||||
def to_rgb_colorsys(self, im):
|
||||
return self.to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
|
||||
converted = [
|
||||
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):
|
||||
src = self.wedge().resize((3 * 32, 32), Image.BILINEAR)
|
||||
im = src.convert("HSV")
|
||||
comparable = self.to_hsv_colorsys(src)
|
||||
new_bytes = b"".join(
|
||||
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
hsv = Image.frombytes(mode, r.size, new_bytes)
|
||||
|
||||
comparable = src
|
||||
im = im.convert("RGB")
|
||||
return hsv
|
||||
|
||||
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):
|
||||
im = hopper("RGB").convert("HSV")
|
||||
comparable = self.to_hsv_colorsys(hopper("RGB"))
|
||||
def to_hsv_colorsys(im):
|
||||
return to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
|
||||
|
||||
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):
|
||||
comparable = self.to_hsv_colorsys(hopper("RGB"))
|
||||
converted = comparable.convert("RGB")
|
||||
comparable = self.to_rgb_colorsys(comparable)
|
||||
def to_rgb_colorsys(im):
|
||||
return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
|
||||
|
||||
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",
|
||||
)
|
||||
|
||||
def test_wedge():
|
||||
src = wedge().resize((3 * 32, 32), Image.BILINEAR)
|
||||
im = src.convert("HSV")
|
||||
comparable = to_hsv_colorsys(src)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
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",
|
||||
)
|
||||
|
|
|
@ -1,250 +1,261 @@
|
|||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from .helper import (
|
||||
PillowTestCase,
|
||||
assert_image,
|
||||
assert_image_equal,
|
||||
assert_image_similar,
|
||||
hopper,
|
||||
)
|
||||
from .helper import assert_image, assert_image_equal, assert_image_similar, hopper
|
||||
|
||||
|
||||
class TestImageConvert(PillowTestCase):
|
||||
def test_sanity(self):
|
||||
def convert(im, mode):
|
||||
out = im.convert(mode)
|
||||
assert out.mode == mode
|
||||
assert out.size == im.size
|
||||
def test_sanity():
|
||||
def convert(im, mode):
|
||||
out = im.convert(mode)
|
||||
assert out.mode == mode
|
||||
assert out.size == im.size
|
||||
|
||||
modes = (
|
||||
"1",
|
||||
"L",
|
||||
"LA",
|
||||
"P",
|
||||
"PA",
|
||||
"I",
|
||||
"F",
|
||||
"RGB",
|
||||
"RGBA",
|
||||
"RGBX",
|
||||
"CMYK",
|
||||
"YCbCr",
|
||||
"HSV",
|
||||
)
|
||||
modes = (
|
||||
"1",
|
||||
"L",
|
||||
"LA",
|
||||
"P",
|
||||
"PA",
|
||||
"I",
|
||||
"F",
|
||||
"RGB",
|
||||
"RGBA",
|
||||
"RGBX",
|
||||
"CMYK",
|
||||
"YCbCr",
|
||||
"HSV",
|
||||
)
|
||||
|
||||
for mode in modes:
|
||||
im = hopper(mode)
|
||||
for mode in modes:
|
||||
im = hopper(mode)
|
||||
for mode in modes:
|
||||
convert(im, mode)
|
||||
convert(im, mode)
|
||||
|
||||
# Check 0
|
||||
im = Image.new(mode, (0, 0))
|
||||
for mode in modes:
|
||||
convert(im, mode)
|
||||
# Check 0
|
||||
im = Image.new(mode, (0, 0))
|
||||
for mode in modes:
|
||||
convert(im, mode)
|
||||
|
||||
def test_default(self):
|
||||
|
||||
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_default():
|
||||
|
||||
# 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):
|
||||
with Image.open("Tests/images/hopper.jpg") as im:
|
||||
self._test_float_conversion(im.convert("L"))
|
||||
# ref https://github.com/python-pillow/Pillow/issues/274
|
||||
|
||||
def test_16bit(self):
|
||||
with Image.open("Tests/images/16bit.cropped.tif") as im:
|
||||
self._test_float_conversion(im)
|
||||
|
||||
def test_16bit_workaround(self):
|
||||
with Image.open("Tests/images/16bit.cropped.tif") as im:
|
||||
self._test_float_conversion(im.convert("I"))
|
||||
def _test_float_conversion(im):
|
||||
orig = im.getpixel((5, 5))
|
||||
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")
|
||||
comparable = converted.convert("RGBA")
|
||||
def test_8bit():
|
||||
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):
|
||||
im = hopper("P")
|
||||
im.info["transparency"] = 0
|
||||
def test_16bit():
|
||||
with Image.open("Tests/images/16bit.cropped.tif") as im:
|
||||
_test_float_conversion(im)
|
||||
|
||||
f = self.tempfile("temp.png")
|
||||
|
||||
im_l = im.convert("L")
|
||||
assert im_l.info["transparency"] == 0 # undone
|
||||
im_l.save(f)
|
||||
def test_16bit_workaround():
|
||||
with Image.open("Tests/images/16bit.cropped.tif") as im:
|
||||
_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):
|
||||
# Arrange
|
||||
im = hopper("P")
|
||||
im.info["transparency"] = 128
|
||||
converted = im.convert("P")
|
||||
comparable = converted.convert("RGBA")
|
||||
|
||||
# Act
|
||||
im_rgba = im.convert("RGBA")
|
||||
assert_image_similar(im, comparable, 20)
|
||||
|
||||
# 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):
|
||||
im = hopper("L")
|
||||
im.info["transparency"] = 128
|
||||
def test_trns_p(tmp_path):
|
||||
im = hopper("P")
|
||||
im.info["transparency"] = 0
|
||||
|
||||
f = self.tempfile("temp.png")
|
||||
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_l = im.convert("L")
|
||||
assert im_l.info["transparency"] == 0 # undone
|
||||
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")
|
||||
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)
|
||||
# Should not raise ValueError: unrecognized raw mode
|
||||
im_p.load()
|
||||
|
||||
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.info["transparency"] = im.getpixel((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")
|
||||
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 / 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"
|
||||
|
||||
# Act
|
||||
# Convert with an identity matrix
|
||||
converted_im = im.convert(mode="RGB", matrix=identity_matrix)
|
||||
# Convert an RGB image to the CIE XYZ colour space
|
||||
converted_im = im.convert(mode=mode, matrix=matrix)
|
||||
|
||||
# Assert
|
||||
# No change
|
||||
assert_image_equal(converted_im, im)
|
||||
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():
|
||||
# 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)
|
||||
|
|
|
@ -1,62 +1,63 @@
|
|||
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(self):
|
||||
def split(mode):
|
||||
layers = hopper(mode).split()
|
||||
return [(i.mode, i.size[0], i.size[1]) for i in layers]
|
||||
def test_split():
|
||||
def split(mode):
|
||||
layers = hopper(mode).split()
|
||||
return [(i.mode, i.size[0], i.size[1]) for i in layers]
|
||||
|
||||
assert split("1") == [("1", 128, 128)]
|
||||
assert split("L") == [("L", 128, 128)]
|
||||
assert split("I") == [("I", 128, 128)]
|
||||
assert split("F") == [("F", 128, 128)]
|
||||
assert split("P") == [("P", 128, 128)]
|
||||
assert split("RGB") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)]
|
||||
assert split("RGBA") == [
|
||||
("L", 128, 128),
|
||||
("L", 128, 128),
|
||||
("L", 128, 128),
|
||||
("L", 128, 128),
|
||||
]
|
||||
assert split("CMYK") == [
|
||||
("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("1") == [("1", 128, 128)]
|
||||
assert split("L") == [("L", 128, 128)]
|
||||
assert split("I") == [("I", 128, 128)]
|
||||
assert split("F") == [("F", 128, 128)]
|
||||
assert split("P") == [("P", 128, 128)]
|
||||
assert split("RGB") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)]
|
||||
assert split("RGBA") == [
|
||||
("L", 128, 128),
|
||||
("L", 128, 128),
|
||||
("L", 128, 128),
|
||||
("L", 128, 128),
|
||||
]
|
||||
assert split("CMYK") == [
|
||||
("L", 128, 128),
|
||||
("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"))
|
||||
assert_image_equal(hopper("L"), split_merge("L"))
|
||||
assert_image_equal(hopper("I"), split_merge("I"))
|
||||
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_merge():
|
||||
def split_merge(mode):
|
||||
return Image.merge(mode, hopper(mode).split())
|
||||
|
||||
def test_split_open(self):
|
||||
if features.check("zlib"):
|
||||
test_file = self.tempfile("temp.png")
|
||||
else:
|
||||
test_file = self.tempfile("temp.pcx")
|
||||
assert_image_equal(hopper("1"), split_merge("1"))
|
||||
assert_image_equal(hopper("L"), split_merge("L"))
|
||||
assert_image_equal(hopper("I"), split_merge("I"))
|
||||
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 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
|
||||
def test_split_open(tmp_path):
|
||||
if features.check("zlib"):
|
||||
test_file = str(tmp_path / "temp.png")
|
||||
else:
|
||||
test_file = str(tmp_path / "temp.pcx")
|
||||
|
||||
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
|
||||
|
|
|
@ -1,140 +1,149 @@
|
|||
import pytest
|
||||
from PIL import Image, ImagePalette
|
||||
|
||||
from .helper import PillowTestCase, assert_image_equal
|
||||
from .helper import assert_image_equal
|
||||
|
||||
|
||||
class TestImagePalette(PillowTestCase):
|
||||
def test_sanity(self):
|
||||
def test_sanity():
|
||||
|
||||
ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||
with pytest.raises(ValueError):
|
||||
ImagePalette.ImagePalette("RGB", list(range(256)) * 2)
|
||||
ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||
with pytest.raises(ValueError):
|
||||
ImagePalette.ImagePalette("RGB", list(range(256)) * 2)
|
||||
|
||||
def test_getcolor(self):
|
||||
|
||||
palette = ImagePalette.ImagePalette()
|
||||
def test_getcolor():
|
||||
|
||||
test_map = {}
|
||||
for i in range(256):
|
||||
test_map[palette.getcolor((i, i, i))] = i
|
||||
palette = ImagePalette.ImagePalette()
|
||||
|
||||
assert len(test_map) == 256
|
||||
with pytest.raises(ValueError):
|
||||
palette.getcolor((1, 2, 3))
|
||||
test_map = {}
|
||||
for i in range(256):
|
||||
test_map[palette.getcolor((i, i, i))] = i
|
||||
|
||||
# Test unknown color specifier
|
||||
with pytest.raises(ValueError):
|
||||
palette.getcolor("unknown")
|
||||
assert len(test_map) == 256
|
||||
with pytest.raises(ValueError):
|
||||
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)
|
||||
|
||||
p = ImagePalette.load(f)
|
||||
|
||||
# load returns raw palette information
|
||||
assert len(p[0]) == 768
|
||||
assert p[1] == "RGB"
|
||||
def test_getdata():
|
||||
# Arrange
|
||||
data_in = list(range(256)) * 3
|
||||
palette = ImagePalette.ImagePalette("RGB", data_in)
|
||||
|
||||
p = ImagePalette.raw(p[1], p[0])
|
||||
assert isinstance(p, ImagePalette.ImagePalette)
|
||||
assert p.palette == palette.tobytes()
|
||||
# Act
|
||||
mode, data_out = palette.getdata()
|
||||
|
||||
def test_make_linear_lut(self):
|
||||
# Arrange
|
||||
black = 0
|
||||
white = 255
|
||||
# Assert
|
||||
assert mode == "RGB;L"
|
||||
|
||||
# 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_rawmode_getdata():
|
||||
# Arrange
|
||||
data_in = list(range(256)) * 3
|
||||
palette = ImagePalette.raw("RGB", data_in)
|
||||
|
||||
def test_make_linear_lut_not_yet_implemented(self):
|
||||
# Update after FIXME
|
||||
# Arrange
|
||||
black = 1
|
||||
white = 255
|
||||
# Act
|
||||
rawmode, data_out = palette.getdata()
|
||||
|
||||
# Act
|
||||
with pytest.raises(NotImplementedError):
|
||||
ImagePalette.make_linear_lut(black, white)
|
||||
# Assert
|
||||
assert rawmode == "RGB"
|
||||
assert data_in == data_out
|
||||
|
||||
def test_make_gamma_lut(self):
|
||||
# Arrange
|
||||
exp = 5
|
||||
|
||||
# Act
|
||||
lut = ImagePalette.make_gamma_lut(exp)
|
||||
def test_2bit_palette(tmp_path):
|
||||
# issue #2258, 2 bit palettes are corrupted.
|
||||
outfile = str(tmp_path / "temp.png")
|
||||
|
||||
# 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
|
||||
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")
|
||||
|
||||
def test_rawmode_valueerrors(self):
|
||||
# Arrange
|
||||
palette = ImagePalette.raw("RGB", list(range(256)) * 3)
|
||||
with Image.open(outfile) as reloaded:
|
||||
assert_image_equal(img, reloaded)
|
||||
|
||||
# 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):
|
||||
# Arrange
|
||||
data_in = list(range(256)) * 3
|
||||
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")
|
||||
def test_invalid_palette():
|
||||
with pytest.raises(IOError):
|
||||
ImagePalette.load("Tests/images/hopper.jpg")
|
||||
|
|
|
@ -1,98 +1,105 @@
|
|||
import pytest
|
||||
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(self):
|
||||
def test_sanity(tmp_path):
|
||||
|
||||
test_file = self.tempfile("temp.im")
|
||||
test_file = str(tmp_path / "temp.im")
|
||||
|
||||
im = hopper("RGB")
|
||||
im.save(test_file)
|
||||
im = hopper("RGB")
|
||||
im.save(test_file)
|
||||
|
||||
seq = ImageSequence.Iterator(im)
|
||||
seq = ImageSequence.Iterator(im)
|
||||
|
||||
index = 0
|
||||
for frame in seq:
|
||||
assert_image_equal(im, frame)
|
||||
assert im.tell() == index
|
||||
index += 1
|
||||
index = 0
|
||||
for frame in seq:
|
||||
assert_image_equal(im, frame)
|
||||
assert im.tell() == index
|
||||
index += 1
|
||||
|
||||
assert index == 1
|
||||
assert index == 1
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
ImageSequence.Iterator(0)
|
||||
with pytest.raises(AttributeError):
|
||||
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):
|
||||
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)
|
||||
def test_iterator():
|
||||
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_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):
|
||||
self._test_multipage_tiff()
|
||||
def test_iterator_min_frame():
|
||||
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):
|
||||
with Image.open("Tests/images/multipage.tiff") as im:
|
||||
firstFrame = None
|
||||
for frame in ImageSequence.Iterator(im):
|
||||
if firstFrame is None:
|
||||
firstFrame = frame.copy()
|
||||
for frame in ImageSequence.Iterator(im):
|
||||
assert_image_equal(frame, firstFrame)
|
||||
break
|
||||
def _test_multipage_tiff():
|
||||
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_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):
|
||||
# Test a single image
|
||||
with Image.open("Tests/images/iss634.gif") as im:
|
||||
ims = ImageSequence.all_frames(im)
|
||||
def test_tiff():
|
||||
_test_multipage_tiff()
|
||||
|
||||
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)
|
||||
@skip_unless_feature("libtiff")
|
||||
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
|
||||
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)
|
||||
def test_consecutive():
|
||||
with Image.open("Tests/images/multipage.tiff") as im:
|
||||
firstFrame = None
|
||||
for frame in ImageSequence.Iterator(im):
|
||||
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)
|
||||
|
|
|
@ -3,56 +3,58 @@ from fractions import Fraction
|
|||
from PIL import Image, TiffImagePlugin, features
|
||||
from PIL.TiffImagePlugin import IFDRational
|
||||
|
||||
from .helper import PillowTestCase, hopper
|
||||
from .helper import hopper
|
||||
|
||||
|
||||
class Test_IFDRational(PillowTestCase):
|
||||
def _test_equal(self, num, denom, target):
|
||||
def _test_equal(num, denom, target):
|
||||
|
||||
t = IFDRational(num, denom)
|
||||
t = IFDRational(num, denom)
|
||||
|
||||
assert target == t
|
||||
assert t == target
|
||||
assert target == t
|
||||
assert t == target
|
||||
|
||||
def test_sanity(self):
|
||||
|
||||
self._test_equal(1, 1, 1)
|
||||
self._test_equal(1, 1, Fraction(1, 1))
|
||||
def test_sanity():
|
||||
|
||||
self._test_equal(2, 2, 1)
|
||||
self._test_equal(1.0, 1, Fraction(1, 1))
|
||||
_test_equal(1, 1, 1)
|
||||
_test_equal(1, 1, Fraction(1, 1))
|
||||
|
||||
self._test_equal(Fraction(1, 1), 1, Fraction(1, 1))
|
||||
self._test_equal(IFDRational(1, 1), 1, 1)
|
||||
_test_equal(2, 2, 1)
|
||||
_test_equal(1.0, 1, Fraction(1, 1))
|
||||
|
||||
self._test_equal(1, 2, Fraction(1, 2))
|
||||
self._test_equal(1, 2, IFDRational(1, 2))
|
||||
_test_equal(Fraction(1, 1), 1, Fraction(1, 1))
|
||||
_test_equal(IFDRational(1, 1), 1, 1)
|
||||
|
||||
def test_nonetype(self):
|
||||
# Fails if the _delegate function doesn't return a valid function
|
||||
_test_equal(1, 2, Fraction(1, 2))
|
||||
_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
|
||||
assert xres and yres
|
||||
def test_nonetype():
|
||||
# Fails if the _delegate function doesn't return a valid function
|
||||
|
||||
def test_ifd_rational_save(self):
|
||||
methods = (True, False)
|
||||
if not features.check("libtiff"):
|
||||
methods = (False,)
|
||||
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
|
||||
|
||||
for libtiff in methods:
|
||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||
assert xres and 1
|
||||
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:
|
||||
assert float(IFDRational(301, 1)) == float(reloaded.tag_v2[282])
|
||||
def test_ifd_rational_save(tmp_path):
|
||||
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])
|
||||
|
|
|
@ -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(self):
|
||||
result = hopper("P").convert("RGB")
|
||||
target = hopper("RGB")
|
||||
assert_image_equal(result, target)
|
||||
def check_upload_equal():
|
||||
result = hopper("P").convert("RGB")
|
||||
target = hopper("RGB")
|
||||
assert_image_equal(result, target)
|
||||
|
||||
def check_upload_similar(self):
|
||||
result = hopper("P").convert("RGB")
|
||||
target = hopper("RGB")
|
||||
assert_image_similar(result, target, 0)
|
||||
|
||||
def check_upload_similar():
|
||||
result = hopper("P").convert("RGB")
|
||||
target = hopper("RGB")
|
||||
assert_image_similar(result, target, 0)
|
||||
|
|
Loading…
Reference in New Issue
Block a user