mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Replace unittest with pytest
This commit is contained in:
parent
098406c304
commit
affade7595
|
@ -1,7 +1,6 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, ImageFilter
|
from PIL import Image, ImageFilter
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
|
||||||
|
|
||||||
sample = Image.new("L", (7, 5))
|
sample = Image.new("L", (7, 5))
|
||||||
# fmt: off
|
# fmt: off
|
||||||
sample.putdata(sum([
|
sample.putdata(sum([
|
||||||
|
@ -21,226 +20,244 @@ def test_imageops_box_blur():
|
||||||
assert isinstance(i, Image.Image)
|
assert isinstance(i, Image.Image)
|
||||||
|
|
||||||
|
|
||||||
class TestBoxBlur(PillowTestCase):
|
def box_blur(image, radius=1, n=1):
|
||||||
def box_blur(self, image, radius=1, n=1):
|
return image._new(image.im.box_blur(radius, n))
|
||||||
return image._new(image.im.box_blur(radius, n))
|
|
||||||
|
|
||||||
def assertImage(self, im, data, delta=0):
|
|
||||||
it = iter(im.getdata())
|
|
||||||
for data_row in data:
|
|
||||||
im_row = [next(it) for _ in range(im.size[0])]
|
|
||||||
if any(
|
|
||||||
abs(data_v - im_v) > delta for data_v, im_v in zip(data_row, im_row)
|
|
||||||
):
|
|
||||||
self.assertEqual(im_row, data_row)
|
|
||||||
self.assertRaises(StopIteration, next, it)
|
|
||||||
|
|
||||||
def assertBlur(self, im, radius, data, passes=1, delta=0):
|
def assertImage(im, data, delta=0):
|
||||||
# check grayscale image
|
it = iter(im.getdata())
|
||||||
self.assertImage(self.box_blur(im, radius, passes), data, delta)
|
for data_row in data:
|
||||||
rgba = Image.merge("RGBA", (im, im, im, im))
|
im_row = [next(it) for _ in range(im.size[0])]
|
||||||
for band in self.box_blur(rgba, radius, passes).split():
|
if any(abs(data_v - im_v) > delta for data_v, im_v in zip(data_row, im_row)):
|
||||||
self.assertImage(band, data, delta)
|
assert im_row == data_row
|
||||||
|
with pytest.raises(StopIteration):
|
||||||
|
next(it)
|
||||||
|
|
||||||
def test_color_modes(self):
|
|
||||||
self.assertRaises(ValueError, self.box_blur, sample.convert("1"))
|
|
||||||
self.assertRaises(ValueError, self.box_blur, sample.convert("P"))
|
|
||||||
self.box_blur(sample.convert("L"))
|
|
||||||
self.box_blur(sample.convert("LA"))
|
|
||||||
self.box_blur(sample.convert("LA").convert("La"))
|
|
||||||
self.assertRaises(ValueError, self.box_blur, sample.convert("I"))
|
|
||||||
self.assertRaises(ValueError, self.box_blur, sample.convert("F"))
|
|
||||||
self.box_blur(sample.convert("RGB"))
|
|
||||||
self.box_blur(sample.convert("RGBA"))
|
|
||||||
self.box_blur(sample.convert("RGBA").convert("RGBa"))
|
|
||||||
self.box_blur(sample.convert("CMYK"))
|
|
||||||
self.assertRaises(ValueError, self.box_blur, sample.convert("YCbCr"))
|
|
||||||
|
|
||||||
def test_radius_0(self):
|
def assertBlur(im, radius, data, passes=1, delta=0):
|
||||||
self.assertBlur(
|
# check grayscale image
|
||||||
sample,
|
assertImage(box_blur(im, radius, passes), data, delta)
|
||||||
0,
|
rgba = Image.merge("RGBA", (im, im, im, im))
|
||||||
[
|
for band in box_blur(rgba, radius, passes).split():
|
||||||
# fmt: off
|
assertImage(band, data, delta)
|
||||||
[210, 50, 20, 10, 220, 230, 80],
|
|
||||||
[190, 210, 20, 180, 170, 40, 110],
|
|
||||||
[120, 210, 250, 60, 220, 0, 220],
|
|
||||||
[220, 40, 230, 80, 130, 250, 40],
|
|
||||||
[250, 0, 80, 30, 60, 20, 110],
|
|
||||||
# fmt: on
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_radius_0_02(self):
|
|
||||||
self.assertBlur(
|
|
||||||
sample,
|
|
||||||
0.02,
|
|
||||||
[
|
|
||||||
# fmt: off
|
|
||||||
[206, 55, 20, 17, 215, 223, 83],
|
|
||||||
[189, 203, 31, 171, 169, 46, 110],
|
|
||||||
[125, 206, 241, 69, 210, 13, 210],
|
|
||||||
[215, 49, 221, 82, 131, 235, 48],
|
|
||||||
[244, 7, 80, 32, 60, 27, 107],
|
|
||||||
# fmt: on
|
|
||||||
],
|
|
||||||
delta=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_radius_0_05(self):
|
def test_color_modes():
|
||||||
self.assertBlur(
|
with pytest.raises(ValueError):
|
||||||
sample,
|
box_blur(sample.convert("1"))
|
||||||
0.05,
|
with pytest.raises(ValueError):
|
||||||
[
|
box_blur(sample.convert("P"))
|
||||||
# fmt: off
|
box_blur(sample.convert("L"))
|
||||||
[202, 62, 22, 27, 209, 215, 88],
|
box_blur(sample.convert("LA"))
|
||||||
[188, 194, 44, 161, 168, 56, 111],
|
box_blur(sample.convert("LA").convert("La"))
|
||||||
[131, 201, 229, 81, 198, 31, 198],
|
with pytest.raises(ValueError):
|
||||||
[209, 62, 209, 86, 133, 216, 59],
|
box_blur(sample.convert("I"))
|
||||||
[237, 17, 80, 36, 60, 35, 103],
|
with pytest.raises(ValueError):
|
||||||
# fmt: on
|
box_blur(sample.convert("F"))
|
||||||
],
|
box_blur(sample.convert("RGB"))
|
||||||
delta=2,
|
box_blur(sample.convert("RGBA"))
|
||||||
)
|
box_blur(sample.convert("RGBA").convert("RGBa"))
|
||||||
|
box_blur(sample.convert("CMYK"))
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
box_blur(sample.convert("YCbCr"))
|
||||||
|
|
||||||
def test_radius_0_1(self):
|
|
||||||
self.assertBlur(
|
|
||||||
sample,
|
|
||||||
0.1,
|
|
||||||
[
|
|
||||||
# fmt: off
|
|
||||||
[196, 72, 24, 40, 200, 203, 93],
|
|
||||||
[187, 183, 62, 148, 166, 68, 111],
|
|
||||||
[139, 193, 213, 96, 182, 54, 182],
|
|
||||||
[201, 78, 193, 91, 133, 191, 73],
|
|
||||||
[227, 31, 80, 42, 61, 47, 99],
|
|
||||||
# fmt: on
|
|
||||||
],
|
|
||||||
delta=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_radius_0_5(self):
|
def test_radius_0():
|
||||||
self.assertBlur(
|
assertBlur(
|
||||||
sample,
|
sample,
|
||||||
0.5,
|
0,
|
||||||
[
|
[
|
||||||
# fmt: off
|
# fmt: off
|
||||||
[176, 101, 46, 83, 163, 165, 111],
|
[210, 50, 20, 10, 220, 230, 80],
|
||||||
[176, 149, 108, 122, 144, 120, 117],
|
[190, 210, 20, 180, 170, 40, 110],
|
||||||
[164, 171, 159, 141, 134, 119, 129],
|
[120, 210, 250, 60, 220, 0, 220],
|
||||||
[170, 136, 133, 114, 116, 124, 109],
|
[220, 40, 230, 80, 130, 250, 40],
|
||||||
[184, 95, 72, 70, 69, 81, 89],
|
[250, 0, 80, 30, 60, 20, 110],
|
||||||
# fmt: on
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def test_radius_1(self):
|
|
||||||
self.assertBlur(
|
|
||||||
sample,
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
# fmt: off
|
|
||||||
[170, 109, 63, 97, 146, 153, 116],
|
|
||||||
[168, 142, 112, 128, 126, 143, 121],
|
|
||||||
[169, 166, 142, 149, 126, 131, 114],
|
|
||||||
[159, 156, 109, 127, 94, 117, 112],
|
|
||||||
[164, 128, 63, 87, 76, 89, 90],
|
|
||||||
# fmt: on
|
|
||||||
],
|
|
||||||
delta=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_radius_1_5(self):
|
def test_radius_0_02():
|
||||||
self.assertBlur(
|
assertBlur(
|
||||||
sample,
|
sample,
|
||||||
1.5,
|
0.02,
|
||||||
[
|
[
|
||||||
# fmt: off
|
# fmt: off
|
||||||
[155, 120, 105, 112, 124, 137, 130],
|
[206, 55, 20, 17, 215, 223, 83],
|
||||||
[160, 136, 124, 125, 127, 134, 130],
|
[189, 203, 31, 171, 169, 46, 110],
|
||||||
[166, 147, 130, 125, 120, 121, 119],
|
[125, 206, 241, 69, 210, 13, 210],
|
||||||
[168, 145, 119, 109, 103, 105, 110],
|
[215, 49, 221, 82, 131, 235, 48],
|
||||||
[168, 134, 96, 85, 85, 89, 97],
|
[244, 7, 80, 32, 60, 27, 107],
|
||||||
# fmt: on
|
# fmt: on
|
||||||
],
|
],
|
||||||
delta=1,
|
delta=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_radius_bigger_then_half(self):
|
|
||||||
self.assertBlur(
|
|
||||||
sample,
|
|
||||||
3,
|
|
||||||
[
|
|
||||||
# fmt: off
|
|
||||||
[144, 145, 142, 128, 114, 115, 117],
|
|
||||||
[148, 145, 137, 122, 109, 111, 112],
|
|
||||||
[152, 145, 131, 117, 103, 107, 108],
|
|
||||||
[156, 144, 126, 111, 97, 102, 103],
|
|
||||||
[160, 144, 121, 106, 92, 98, 99],
|
|
||||||
# fmt: on
|
|
||||||
],
|
|
||||||
delta=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_radius_bigger_then_width(self):
|
def test_radius_0_05():
|
||||||
self.assertBlur(
|
assertBlur(
|
||||||
sample,
|
sample,
|
||||||
10,
|
0.05,
|
||||||
[
|
[
|
||||||
[158, 153, 147, 141, 135, 129, 123],
|
# fmt: off
|
||||||
[159, 153, 147, 141, 136, 130, 124],
|
[202, 62, 22, 27, 209, 215, 88],
|
||||||
[159, 154, 148, 142, 136, 130, 124],
|
[188, 194, 44, 161, 168, 56, 111],
|
||||||
[160, 154, 148, 142, 137, 131, 125],
|
[131, 201, 229, 81, 198, 31, 198],
|
||||||
[160, 155, 149, 143, 137, 131, 125],
|
[209, 62, 209, 86, 133, 216, 59],
|
||||||
],
|
[237, 17, 80, 36, 60, 35, 103],
|
||||||
delta=0,
|
# fmt: on
|
||||||
)
|
],
|
||||||
|
delta=2,
|
||||||
|
)
|
||||||
|
|
||||||
def test_extreme_large_radius(self):
|
|
||||||
self.assertBlur(
|
|
||||||
sample,
|
|
||||||
600,
|
|
||||||
[
|
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
|
||||||
[162, 162, 162, 162, 162, 162, 162],
|
|
||||||
],
|
|
||||||
delta=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_two_passes(self):
|
def test_radius_0_1():
|
||||||
self.assertBlur(
|
assertBlur(
|
||||||
sample,
|
sample,
|
||||||
1,
|
0.1,
|
||||||
[
|
[
|
||||||
# fmt: off
|
# fmt: off
|
||||||
[153, 123, 102, 109, 132, 135, 129],
|
[196, 72, 24, 40, 200, 203, 93],
|
||||||
[159, 138, 123, 121, 133, 131, 126],
|
[187, 183, 62, 148, 166, 68, 111],
|
||||||
[162, 147, 136, 124, 127, 121, 121],
|
[139, 193, 213, 96, 182, 54, 182],
|
||||||
[159, 140, 125, 108, 111, 106, 108],
|
[201, 78, 193, 91, 133, 191, 73],
|
||||||
[154, 126, 105, 87, 94, 93, 97],
|
[227, 31, 80, 42, 61, 47, 99],
|
||||||
# fmt: on
|
# fmt: on
|
||||||
],
|
],
|
||||||
passes=2,
|
delta=1,
|
||||||
delta=1,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def test_three_passes(self):
|
|
||||||
self.assertBlur(
|
def test_radius_0_5():
|
||||||
sample,
|
assertBlur(
|
||||||
1,
|
sample,
|
||||||
[
|
0.5,
|
||||||
# fmt: off
|
[
|
||||||
[146, 131, 116, 118, 126, 131, 130],
|
# fmt: off
|
||||||
[151, 138, 125, 123, 126, 128, 127],
|
[176, 101, 46, 83, 163, 165, 111],
|
||||||
[154, 143, 129, 123, 120, 120, 119],
|
[176, 149, 108, 122, 144, 120, 117],
|
||||||
[152, 139, 122, 113, 108, 108, 108],
|
[164, 171, 159, 141, 134, 119, 129],
|
||||||
[148, 132, 112, 102, 97, 99, 100],
|
[170, 136, 133, 114, 116, 124, 109],
|
||||||
# fmt: on
|
[184, 95, 72, 70, 69, 81, 89],
|
||||||
],
|
# fmt: on
|
||||||
passes=3,
|
],
|
||||||
delta=1,
|
delta=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_radius_1():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
# fmt: off
|
||||||
|
[170, 109, 63, 97, 146, 153, 116],
|
||||||
|
[168, 142, 112, 128, 126, 143, 121],
|
||||||
|
[169, 166, 142, 149, 126, 131, 114],
|
||||||
|
[159, 156, 109, 127, 94, 117, 112],
|
||||||
|
[164, 128, 63, 87, 76, 89, 90],
|
||||||
|
# fmt: on
|
||||||
|
],
|
||||||
|
delta=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_radius_1_5():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
1.5,
|
||||||
|
[
|
||||||
|
# fmt: off
|
||||||
|
[155, 120, 105, 112, 124, 137, 130],
|
||||||
|
[160, 136, 124, 125, 127, 134, 130],
|
||||||
|
[166, 147, 130, 125, 120, 121, 119],
|
||||||
|
[168, 145, 119, 109, 103, 105, 110],
|
||||||
|
[168, 134, 96, 85, 85, 89, 97],
|
||||||
|
# fmt: on
|
||||||
|
],
|
||||||
|
delta=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_radius_bigger_then_half():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
3,
|
||||||
|
[
|
||||||
|
# fmt: off
|
||||||
|
[144, 145, 142, 128, 114, 115, 117],
|
||||||
|
[148, 145, 137, 122, 109, 111, 112],
|
||||||
|
[152, 145, 131, 117, 103, 107, 108],
|
||||||
|
[156, 144, 126, 111, 97, 102, 103],
|
||||||
|
[160, 144, 121, 106, 92, 98, 99],
|
||||||
|
# fmt: on
|
||||||
|
],
|
||||||
|
delta=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_radius_bigger_then_width():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
10,
|
||||||
|
[
|
||||||
|
[158, 153, 147, 141, 135, 129, 123],
|
||||||
|
[159, 153, 147, 141, 136, 130, 124],
|
||||||
|
[159, 154, 148, 142, 136, 130, 124],
|
||||||
|
[160, 154, 148, 142, 137, 131, 125],
|
||||||
|
[160, 155, 149, 143, 137, 131, 125],
|
||||||
|
],
|
||||||
|
delta=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_extreme_large_radius():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
600,
|
||||||
|
[
|
||||||
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
|
[162, 162, 162, 162, 162, 162, 162],
|
||||||
|
],
|
||||||
|
delta=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_two_passes():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
# fmt: off
|
||||||
|
[153, 123, 102, 109, 132, 135, 129],
|
||||||
|
[159, 138, 123, 121, 133, 131, 126],
|
||||||
|
[162, 147, 136, 124, 127, 121, 121],
|
||||||
|
[159, 140, 125, 108, 111, 106, 108],
|
||||||
|
[154, 126, 105, 87, 94, 93, 97],
|
||||||
|
# fmt: on
|
||||||
|
],
|
||||||
|
passes=2,
|
||||||
|
delta=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_three_passes():
|
||||||
|
assertBlur(
|
||||||
|
sample,
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
# fmt: off
|
||||||
|
[146, 131, 116, 118, 126, 131, 130],
|
||||||
|
[151, 138, 125, 123, 126, 128, 127],
|
||||||
|
[154, 143, 129, 123, 120, 120, 119],
|
||||||
|
[152, 139, 122, 113, 108, 108, 108],
|
||||||
|
[148, 132, 112, 102, 97, 99, 100],
|
||||||
|
# fmt: on
|
||||||
|
],
|
||||||
|
passes=3,
|
||||||
|
delta=1,
|
||||||
|
)
|
||||||
|
|
|
@ -22,7 +22,7 @@ class TestDecompressionBomb(PillowTestCase):
|
||||||
# Arrange
|
# Arrange
|
||||||
# Turn limit off
|
# Turn limit off
|
||||||
Image.MAX_IMAGE_PIXELS = None
|
Image.MAX_IMAGE_PIXELS = None
|
||||||
self.assertIsNone(Image.MAX_IMAGE_PIXELS)
|
assert Image.MAX_IMAGE_PIXELS is None
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
# Implicit assert: no warning.
|
# Implicit assert: no warning.
|
||||||
|
@ -33,7 +33,7 @@ class TestDecompressionBomb(PillowTestCase):
|
||||||
def test_warning(self):
|
def test_warning(self):
|
||||||
# Set limit to trigger warning on the test file
|
# Set limit to trigger warning on the test file
|
||||||
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
|
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
|
||||||
self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1)
|
assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1
|
||||||
|
|
||||||
def open():
|
def open():
|
||||||
with Image.open(TEST_FILE):
|
with Image.open(TEST_FILE):
|
||||||
|
@ -44,18 +44,18 @@ class TestDecompressionBomb(PillowTestCase):
|
||||||
def test_exception(self):
|
def test_exception(self):
|
||||||
# Set limit to trigger exception on the test file
|
# Set limit to trigger exception on the test file
|
||||||
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
|
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
|
||||||
self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1)
|
assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1
|
||||||
|
|
||||||
with self.assertRaises(Image.DecompressionBombError):
|
with pytest.raises(Image.DecompressionBombError):
|
||||||
with Image.open(TEST_FILE):
|
with Image.open(TEST_FILE):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_exception_ico(self):
|
def test_exception_ico(self):
|
||||||
with self.assertRaises(Image.DecompressionBombError):
|
with pytest.raises(Image.DecompressionBombError):
|
||||||
Image.open("Tests/images/decompression_bomb.ico")
|
Image.open("Tests/images/decompression_bomb.ico")
|
||||||
|
|
||||||
def test_exception_gif(self):
|
def test_exception_gif(self):
|
||||||
with self.assertRaises(Image.DecompressionBombError):
|
with pytest.raises(Image.DecompressionBombError):
|
||||||
Image.open("Tests/images/decompression_bomb.gif")
|
Image.open("Tests/images/decompression_bomb.gif")
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,11 +85,11 @@ class TestDecompressionCrop(PillowTestCase):
|
||||||
error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))
|
error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))
|
||||||
|
|
||||||
for value in good_values:
|
for value in good_values:
|
||||||
self.assertEqual(im.crop(value).size, (9, 9))
|
assert im.crop(value).size == (9, 9)
|
||||||
|
|
||||||
for value in warning_values:
|
for value in warning_values:
|
||||||
pytest.warns(Image.DecompressionBombWarning, im.crop, value)
|
pytest.warns(Image.DecompressionBombWarning, im.crop, value)
|
||||||
|
|
||||||
for value in error_values:
|
for value in error_values:
|
||||||
with self.assertRaises(Image.DecompressionBombError):
|
with pytest.raises(Image.DecompressionBombError):
|
||||||
im.crop(value)
|
im.crop(value)
|
||||||
|
|
|
@ -1,84 +1,92 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import DcxImagePlugin, Image
|
from PIL import DcxImagePlugin, Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper, is_pypy
|
from .helper import assert_image_equal, hopper, is_pypy
|
||||||
|
|
||||||
# Created with ImageMagick: convert hopper.ppm hopper.dcx
|
# Created with ImageMagick: convert hopper.ppm hopper.dcx
|
||||||
TEST_FILE = "Tests/images/hopper.dcx"
|
TEST_FILE = "Tests/images/hopper.dcx"
|
||||||
|
|
||||||
|
|
||||||
class TestFileDcx(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
# Arrange
|
||||||
# Arrange
|
|
||||||
|
# Act
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert im.size == (128, 128)
|
||||||
|
assert isinstance(im, DcxImagePlugin.DcxImageFile)
|
||||||
|
orig = hopper()
|
||||||
|
assert_image_equal(im, orig)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
|
||||||
|
def test_unclosed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(TEST_FILE)
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
pytest.warns(ResourceWarning, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_closed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(TEST_FILE)
|
||||||
|
im.load()
|
||||||
|
im.close()
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_context_manager():
|
||||||
|
def open():
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_file():
|
||||||
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
DcxImagePlugin.DcxImageFile(fp)
|
||||||
|
|
||||||
|
|
||||||
|
def test_tell():
|
||||||
|
# Arrange
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
with Image.open(TEST_FILE) as im:
|
frame = im.tell()
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (128, 128))
|
assert frame == 0
|
||||||
self.assertIsInstance(im, DcxImagePlugin.DcxImageFile)
|
|
||||||
orig = hopper()
|
|
||||||
assert_image_equal(im, orig)
|
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy(), "Requires CPython")
|
|
||||||
def test_unclosed_file(self):
|
|
||||||
def open():
|
|
||||||
im = Image.open(TEST_FILE)
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
pytest.warns(ResourceWarning, open)
|
def test_n_frames():
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
assert im.n_frames == 1
|
||||||
|
assert not im.is_animated
|
||||||
|
|
||||||
def test_closed_file(self):
|
|
||||||
def open():
|
|
||||||
im = Image.open(TEST_FILE)
|
|
||||||
im.load()
|
|
||||||
im.close()
|
|
||||||
|
|
||||||
pytest.warns(None, open)
|
def test_eoferror():
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
n_frames = im.n_frames
|
||||||
|
|
||||||
def test_context_manager(self):
|
# Test seeking past the last frame
|
||||||
def open():
|
with pytest.raises(EOFError):
|
||||||
with Image.open(TEST_FILE) as im:
|
im.seek(n_frames)
|
||||||
im.load()
|
assert im.tell() < n_frames
|
||||||
|
|
||||||
pytest.warns(None, open)
|
# Test that seeking to the last frame does not raise an error
|
||||||
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
|
||||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
|
||||||
self.assertRaises(SyntaxError, DcxImagePlugin.DcxImageFile, fp)
|
|
||||||
|
|
||||||
def test_tell(self):
|
def test_seek_too_far():
|
||||||
# Arrange
|
# Arrange
|
||||||
with Image.open(TEST_FILE) as im:
|
with Image.open(TEST_FILE) as im:
|
||||||
|
frame = 999 # too big on purpose
|
||||||
|
|
||||||
# Act
|
# Act / Assert
|
||||||
frame = im.tell()
|
with pytest.raises(EOFError):
|
||||||
|
im.seek(frame)
|
||||||
# Assert
|
|
||||||
self.assertEqual(frame, 0)
|
|
||||||
|
|
||||||
def test_n_frames(self):
|
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
self.assertEqual(im.n_frames, 1)
|
|
||||||
self.assertFalse(im.is_animated)
|
|
||||||
|
|
||||||
def test_eoferror(self):
|
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
n_frames = im.n_frames
|
|
||||||
|
|
||||||
# Test seeking past the last frame
|
|
||||||
self.assertRaises(EOFError, im.seek, n_frames)
|
|
||||||
self.assertLess(im.tell(), n_frames)
|
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
|
||||||
im.seek(n_frames - 1)
|
|
||||||
|
|
||||||
def test_seek_too_far(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
frame = 999 # too big on purpose
|
|
||||||
|
|
||||||
# Act / Assert
|
|
||||||
self.assertRaises(EOFError, im.seek, frame)
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
"""Test DdsImagePlugin"""
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
import pytest
|
||||||
from PIL import DdsImagePlugin, Image
|
from PIL import DdsImagePlugin, Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal
|
from .helper import assert_image_equal
|
||||||
|
|
||||||
TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
|
TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
|
||||||
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds"
|
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds"
|
||||||
|
@ -12,146 +14,148 @@ TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds"
|
||||||
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds"
|
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds"
|
||||||
|
|
||||||
|
|
||||||
class TestFileDds(PillowTestCase):
|
def test_sanity_dxt1():
|
||||||
"""Test DdsImagePlugin"""
|
"""Check DXT1 images can be opened"""
|
||||||
|
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
|
||||||
|
target = target.convert("RGBA")
|
||||||
|
with Image.open(TEST_FILE_DXT1) as im:
|
||||||
|
im.load()
|
||||||
|
|
||||||
def test_sanity_dxt1(self):
|
assert im.format == "DDS"
|
||||||
"""Check DXT1 images can be opened"""
|
assert im.mode == "RGBA"
|
||||||
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
|
assert im.size == (256, 256)
|
||||||
target = target.convert("RGBA")
|
|
||||||
with Image.open(TEST_FILE_DXT1) as im:
|
assert_image_equal(im, target)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sanity_dxt5():
|
||||||
|
"""Check DXT5 images can be opened"""
|
||||||
|
|
||||||
|
with Image.open(TEST_FILE_DXT5) as im:
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
assert im.format == "DDS"
|
||||||
|
assert im.mode == "RGBA"
|
||||||
|
assert im.size == (256, 256)
|
||||||
|
|
||||||
|
with Image.open(TEST_FILE_DXT5.replace(".dds", ".png")) as target:
|
||||||
|
assert_image_equal(target, im)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sanity_dxt3():
|
||||||
|
"""Check DXT3 images can be opened"""
|
||||||
|
|
||||||
|
with Image.open(TEST_FILE_DXT3.replace(".dds", ".png")) as target:
|
||||||
|
with Image.open(TEST_FILE_DXT3) as im:
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assertEqual(im.format, "DDS")
|
assert im.format == "DDS"
|
||||||
self.assertEqual(im.mode, "RGBA")
|
assert im.mode == "RGBA"
|
||||||
self.assertEqual(im.size, (256, 256))
|
assert im.size == (256, 256)
|
||||||
|
|
||||||
assert_image_equal(im, target)
|
|
||||||
|
|
||||||
def test_sanity_dxt5(self):
|
|
||||||
"""Check DXT5 images can be opened"""
|
|
||||||
|
|
||||||
with Image.open(TEST_FILE_DXT5) as im:
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
self.assertEqual(im.format, "DDS")
|
|
||||||
self.assertEqual(im.mode, "RGBA")
|
|
||||||
self.assertEqual(im.size, (256, 256))
|
|
||||||
|
|
||||||
with Image.open(TEST_FILE_DXT5.replace(".dds", ".png")) as target:
|
|
||||||
assert_image_equal(target, im)
|
assert_image_equal(target, im)
|
||||||
|
|
||||||
def test_sanity_dxt3(self):
|
|
||||||
"""Check DXT3 images can be opened"""
|
|
||||||
|
|
||||||
with Image.open(TEST_FILE_DXT3.replace(".dds", ".png")) as target:
|
def test_dx10_bc7():
|
||||||
with Image.open(TEST_FILE_DXT3) as im:
|
"""Check DX10 images can be opened"""
|
||||||
im.load()
|
|
||||||
|
|
||||||
self.assertEqual(im.format, "DDS")
|
with Image.open(TEST_FILE_DX10_BC7) as im:
|
||||||
self.assertEqual(im.mode, "RGBA")
|
im.load()
|
||||||
self.assertEqual(im.size, (256, 256))
|
|
||||||
|
|
||||||
assert_image_equal(target, im)
|
assert im.format == "DDS"
|
||||||
|
assert im.mode == "RGBA"
|
||||||
|
assert im.size == (256, 256)
|
||||||
|
|
||||||
def test_dx10_bc7(self):
|
with Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png")) as target:
|
||||||
"""Check DX10 images can be opened"""
|
assert_image_equal(target, im)
|
||||||
|
|
||||||
with Image.open(TEST_FILE_DX10_BC7) as im:
|
|
||||||
|
def test_dx10_bc7_unorm_srgb():
|
||||||
|
"""Check DX10 unsigned normalized integer images can be opened"""
|
||||||
|
|
||||||
|
with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
assert im.format == "DDS"
|
||||||
|
assert im.mode == "RGBA"
|
||||||
|
assert im.size == (16, 16)
|
||||||
|
assert im.info["gamma"] == 1 / 2.2
|
||||||
|
|
||||||
|
with Image.open(
|
||||||
|
TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png")
|
||||||
|
) as target:
|
||||||
|
assert_image_equal(target, im)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unimplemented_dxgi_format():
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
Image.open("Tests/images/unimplemented_dxgi_format.dds",)
|
||||||
|
|
||||||
|
|
||||||
|
def test_uncompressed_rgb():
|
||||||
|
"""Check uncompressed RGB images can be opened"""
|
||||||
|
|
||||||
|
with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
assert im.format == "DDS"
|
||||||
|
assert im.mode == "RGBA"
|
||||||
|
assert im.size == (800, 600)
|
||||||
|
|
||||||
|
with Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png")) as target:
|
||||||
|
assert_image_equal(target, im)
|
||||||
|
|
||||||
|
|
||||||
|
def test__validate_true():
|
||||||
|
"""Check valid prefix"""
|
||||||
|
# Arrange
|
||||||
|
prefix = b"DDS etc"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
output = DdsImagePlugin._validate(prefix)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert output
|
||||||
|
|
||||||
|
|
||||||
|
def test__validate_false():
|
||||||
|
"""Check invalid prefix"""
|
||||||
|
# Arrange
|
||||||
|
prefix = b"something invalid"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
output = DdsImagePlugin._validate(prefix)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert not output
|
||||||
|
|
||||||
|
|
||||||
|
def test_short_header():
|
||||||
|
""" Check a short header"""
|
||||||
|
with open(TEST_FILE_DXT5, "rb") as f:
|
||||||
|
img_file = f.read()
|
||||||
|
|
||||||
|
def short_header():
|
||||||
|
Image.open(BytesIO(img_file[:119]))
|
||||||
|
|
||||||
|
with pytest.raises(IOError):
|
||||||
|
short_header()
|
||||||
|
|
||||||
|
|
||||||
|
def test_short_file():
|
||||||
|
""" Check that the appropriate error is thrown for a short file"""
|
||||||
|
|
||||||
|
with open(TEST_FILE_DXT5, "rb") as f:
|
||||||
|
img_file = f.read()
|
||||||
|
|
||||||
|
def short_file():
|
||||||
|
with Image.open(BytesIO(img_file[:-100])) as im:
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assertEqual(im.format, "DDS")
|
with pytest.raises(IOError):
|
||||||
self.assertEqual(im.mode, "RGBA")
|
short_file()
|
||||||
self.assertEqual(im.size, (256, 256))
|
|
||||||
|
|
||||||
with Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png")) as target:
|
|
||||||
assert_image_equal(target, im)
|
|
||||||
|
|
||||||
def test_dx10_bc7_unorm_srgb(self):
|
def test_unimplemented_pixel_format():
|
||||||
"""Check DX10 unsigned normalized integer images can be opened"""
|
with pytest.raises(NotImplementedError):
|
||||||
|
Image.open("Tests/images/unimplemented_pixel_format.dds",)
|
||||||
with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
self.assertEqual(im.format, "DDS")
|
|
||||||
self.assertEqual(im.mode, "RGBA")
|
|
||||||
self.assertEqual(im.size, (16, 16))
|
|
||||||
self.assertEqual(im.info["gamma"], 1 / 2.2)
|
|
||||||
|
|
||||||
with Image.open(
|
|
||||||
TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png")
|
|
||||||
) as target:
|
|
||||||
assert_image_equal(target, im)
|
|
||||||
|
|
||||||
def test_unimplemented_dxgi_format(self):
|
|
||||||
self.assertRaises(
|
|
||||||
NotImplementedError,
|
|
||||||
Image.open,
|
|
||||||
"Tests/images/unimplemented_dxgi_format.dds",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_uncompressed_rgb(self):
|
|
||||||
"""Check uncompressed RGB images can be opened"""
|
|
||||||
|
|
||||||
with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
self.assertEqual(im.format, "DDS")
|
|
||||||
self.assertEqual(im.mode, "RGBA")
|
|
||||||
self.assertEqual(im.size, (800, 600))
|
|
||||||
|
|
||||||
with Image.open(
|
|
||||||
TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png")
|
|
||||||
) as target:
|
|
||||||
assert_image_equal(target, im)
|
|
||||||
|
|
||||||
def test__validate_true(self):
|
|
||||||
"""Check valid prefix"""
|
|
||||||
# Arrange
|
|
||||||
prefix = b"DDS etc"
|
|
||||||
|
|
||||||
# Act
|
|
||||||
output = DdsImagePlugin._validate(prefix)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertTrue(output)
|
|
||||||
|
|
||||||
def test__validate_false(self):
|
|
||||||
"""Check invalid prefix"""
|
|
||||||
# Arrange
|
|
||||||
prefix = b"something invalid"
|
|
||||||
|
|
||||||
# Act
|
|
||||||
output = DdsImagePlugin._validate(prefix)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertFalse(output)
|
|
||||||
|
|
||||||
def test_short_header(self):
|
|
||||||
""" Check a short header"""
|
|
||||||
with open(TEST_FILE_DXT5, "rb") as f:
|
|
||||||
img_file = f.read()
|
|
||||||
|
|
||||||
def short_header():
|
|
||||||
Image.open(BytesIO(img_file[:119]))
|
|
||||||
|
|
||||||
self.assertRaises(IOError, short_header)
|
|
||||||
|
|
||||||
def test_short_file(self):
|
|
||||||
""" Check that the appropriate error is thrown for a short file"""
|
|
||||||
|
|
||||||
with open(TEST_FILE_DXT5, "rb") as f:
|
|
||||||
img_file = f.read()
|
|
||||||
|
|
||||||
def short_file():
|
|
||||||
with Image.open(BytesIO(img_file[:-100])) as im:
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
self.assertRaises(IOError, short_file)
|
|
||||||
|
|
||||||
def test_unimplemented_pixel_format(self):
|
|
||||||
self.assertRaises(
|
|
||||||
NotImplementedError,
|
|
||||||
Image.open,
|
|
||||||
"Tests/images/unimplemented_pixel_format.dds",
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import FliImagePlugin, Image
|
from PIL import FliImagePlugin, Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, is_pypy
|
from .helper import assert_image_equal, is_pypy
|
||||||
|
|
||||||
# created as an export of a palette image from Gimp2.6
|
# created as an export of a palette image from Gimp2.6
|
||||||
# save as...-> hopper.fli, default options.
|
# save as...-> hopper.fli, default options.
|
||||||
|
@ -13,105 +11,115 @@ static_test_file = "Tests/images/hopper.fli"
|
||||||
animated_test_file = "Tests/images/a.fli"
|
animated_test_file = "Tests/images/a.fli"
|
||||||
|
|
||||||
|
|
||||||
class TestFileFli(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
with Image.open(static_test_file) as im:
|
||||||
|
im.load()
|
||||||
|
assert im.mode == "P"
|
||||||
|
assert im.size == (128, 128)
|
||||||
|
assert im.format == "FLI"
|
||||||
|
assert not im.is_animated
|
||||||
|
|
||||||
|
with Image.open(animated_test_file) as im:
|
||||||
|
assert im.mode == "P"
|
||||||
|
assert im.size == (320, 200)
|
||||||
|
assert im.format == "FLI"
|
||||||
|
assert im.info["duration"] == 71
|
||||||
|
assert im.is_animated
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
|
||||||
|
def test_unclosed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(static_test_file)
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
pytest.warns(ResourceWarning, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_closed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(static_test_file)
|
||||||
|
im.load()
|
||||||
|
im.close()
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_context_manager():
|
||||||
|
def open():
|
||||||
with Image.open(static_test_file) as im:
|
with Image.open(static_test_file) as im:
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, "P")
|
|
||||||
self.assertEqual(im.size, (128, 128))
|
|
||||||
self.assertEqual(im.format, "FLI")
|
|
||||||
self.assertFalse(im.is_animated)
|
|
||||||
|
|
||||||
with Image.open(animated_test_file) as im:
|
pytest.warns(None, open)
|
||||||
self.assertEqual(im.mode, "P")
|
|
||||||
self.assertEqual(im.size, (320, 200))
|
|
||||||
self.assertEqual(im.format, "FLI")
|
|
||||||
self.assertEqual(im.info["duration"], 71)
|
|
||||||
self.assertTrue(im.is_animated)
|
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy(), "Requires CPython")
|
|
||||||
def test_unclosed_file(self):
|
|
||||||
def open():
|
|
||||||
im = Image.open(static_test_file)
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
pytest.warns(ResourceWarning, open)
|
def test_tell():
|
||||||
|
# Arrange
|
||||||
|
with Image.open(static_test_file) as im:
|
||||||
|
|
||||||
def test_closed_file(self):
|
# Act
|
||||||
def open():
|
frame = im.tell()
|
||||||
im = Image.open(static_test_file)
|
|
||||||
im.load()
|
|
||||||
im.close()
|
|
||||||
|
|
||||||
pytest.warns(None, open)
|
# Assert
|
||||||
|
assert frame == 0
|
||||||
|
|
||||||
def test_context_manager(self):
|
|
||||||
def open():
|
|
||||||
with Image.open(static_test_file) as im:
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
pytest.warns(None, open)
|
def test_invalid_file():
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
def test_tell(self):
|
with pytest.raises(SyntaxError):
|
||||||
# Arrange
|
FliImagePlugin.FliImageFile(invalid_file)
|
||||||
with Image.open(static_test_file) as im:
|
|
||||||
|
|
||||||
# Act
|
|
||||||
frame = im.tell()
|
|
||||||
|
|
||||||
# Assert
|
def test_n_frames():
|
||||||
self.assertEqual(frame, 0)
|
with Image.open(static_test_file) as im:
|
||||||
|
assert im.n_frames == 1
|
||||||
|
assert not im.is_animated
|
||||||
|
|
||||||
def test_invalid_file(self):
|
with Image.open(animated_test_file) as im:
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
assert im.n_frames == 384
|
||||||
|
assert im.is_animated
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
|
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_eoferror():
|
||||||
with Image.open(static_test_file) as im:
|
with Image.open(animated_test_file) as im:
|
||||||
self.assertEqual(im.n_frames, 1)
|
n_frames = im.n_frames
|
||||||
self.assertFalse(im.is_animated)
|
|
||||||
|
|
||||||
with Image.open(animated_test_file) as im:
|
# Test seeking past the last frame
|
||||||
self.assertEqual(im.n_frames, 384)
|
with pytest.raises(EOFError):
|
||||||
self.assertTrue(im.is_animated)
|
im.seek(n_frames)
|
||||||
|
assert im.tell() < n_frames
|
||||||
|
|
||||||
def test_eoferror(self):
|
# Test that seeking to the last frame does not raise an error
|
||||||
with Image.open(animated_test_file) as im:
|
im.seek(n_frames - 1)
|
||||||
n_frames = im.n_frames
|
|
||||||
|
|
||||||
# Test seeking past the last frame
|
|
||||||
self.assertRaises(EOFError, im.seek, n_frames)
|
|
||||||
self.assertLess(im.tell(), n_frames)
|
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
def test_seek_tell():
|
||||||
im.seek(n_frames - 1)
|
with Image.open(animated_test_file) as im:
|
||||||
|
|
||||||
def test_seek_tell(self):
|
layer_number = im.tell()
|
||||||
with Image.open(animated_test_file) as im:
|
assert layer_number == 0
|
||||||
|
|
||||||
layer_number = im.tell()
|
im.seek(0)
|
||||||
self.assertEqual(layer_number, 0)
|
layer_number = im.tell()
|
||||||
|
assert layer_number == 0
|
||||||
|
|
||||||
im.seek(0)
|
im.seek(1)
|
||||||
layer_number = im.tell()
|
layer_number = im.tell()
|
||||||
self.assertEqual(layer_number, 0)
|
assert layer_number == 1
|
||||||
|
|
||||||
im.seek(1)
|
im.seek(2)
|
||||||
layer_number = im.tell()
|
layer_number = im.tell()
|
||||||
self.assertEqual(layer_number, 1)
|
assert layer_number == 2
|
||||||
|
|
||||||
im.seek(2)
|
im.seek(1)
|
||||||
layer_number = im.tell()
|
layer_number = im.tell()
|
||||||
self.assertEqual(layer_number, 2)
|
assert layer_number == 1
|
||||||
|
|
||||||
im.seek(1)
|
|
||||||
layer_number = im.tell()
|
|
||||||
self.assertEqual(layer_number, 1)
|
|
||||||
|
|
||||||
def test_seek(self):
|
def test_seek():
|
||||||
with Image.open(animated_test_file) as im:
|
with Image.open(animated_test_file) as im:
|
||||||
im.seek(50)
|
im.seek(50)
|
||||||
|
|
||||||
with Image.open("Tests/images/a_fli.png") as expected:
|
with Image.open("Tests/images/a_fli.png") as expected:
|
||||||
assert_image_equal(im, expected)
|
assert_image_equal(im, expected)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import unittest
|
import pytest
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import FpxImagePlugin
|
from PIL import FpxImagePlugin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -11,18 +8,23 @@ except ImportError:
|
||||||
else:
|
else:
|
||||||
olefile_installed = True
|
olefile_installed = True
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.skipif(
|
||||||
|
not olefile_installed, reason="olefile package not installed"
|
||||||
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(olefile_installed, "olefile package not installed")
|
|
||||||
class TestFileFpx(PillowTestCase):
|
|
||||||
def test_invalid_file(self):
|
|
||||||
# Test an invalid OLE file
|
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
|
||||||
self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, invalid_file)
|
|
||||||
|
|
||||||
# Test a valid OLE file, but not an FPX file
|
def test_invalid_file():
|
||||||
ole_file = "Tests/images/test-ole-file.doc"
|
# Test an invalid OLE file
|
||||||
self.assertRaises(SyntaxError, FpxImagePlugin.FpxImageFile, ole_file)
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
FpxImagePlugin.FpxImageFile(invalid_file)
|
||||||
|
|
||||||
def test_fpx_invalid_number_of_bands(self):
|
# Test a valid OLE file, but not an FPX file
|
||||||
with self.assertRaisesRegex(IOError, "Invalid number of bands"):
|
ole_file = "Tests/images/test-ole-file.doc"
|
||||||
Image.open("Tests/images/input_bw_five_bands.fpx")
|
with pytest.raises(SyntaxError):
|
||||||
|
FpxImagePlugin.FpxImageFile(ole_file)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fpx_invalid_number_of_bands():
|
||||||
|
with pytest.raises(IOError, match="Invalid number of bands"):
|
||||||
|
Image.open("Tests/images/input_bw_five_bands.fpx")
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
|
import pytest
|
||||||
from PIL import GbrImagePlugin, Image
|
from PIL import GbrImagePlugin, Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal
|
from .helper import assert_image_equal
|
||||||
|
|
||||||
|
|
||||||
class TestFileGbr(PillowTestCase):
|
def test_invalid_file():
|
||||||
def test_invalid_file(self):
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file)
|
with pytest.raises(SyntaxError):
|
||||||
|
GbrImagePlugin.GbrImageFile(invalid_file)
|
||||||
|
|
||||||
def test_gbr_file(self):
|
|
||||||
with Image.open("Tests/images/gbr.gbr") as im:
|
def test_gbr_file():
|
||||||
with Image.open("Tests/images/gbr.png") as target:
|
with Image.open("Tests/images/gbr.gbr") as im:
|
||||||
assert_image_equal(target, im)
|
with Image.open("Tests/images/gbr.png") as target:
|
||||||
|
assert_image_equal(target, im)
|
||||||
|
|
|
@ -1,122 +1,128 @@
|
||||||
from PIL import GimpGradientFile
|
from PIL import GimpGradientFile
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
|
||||||
|
def test_linear_pos_le_middle():
|
||||||
|
# Arrange
|
||||||
|
middle = 0.5
|
||||||
|
pos = 0.25
|
||||||
|
|
||||||
|
# Act
|
||||||
|
ret = GimpGradientFile.linear(middle, pos)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert ret == 0.25
|
||||||
|
|
||||||
|
|
||||||
class TestImage(PillowTestCase):
|
def test_linear_pos_le_small_middle():
|
||||||
def test_linear_pos_le_middle(self):
|
# Arrange
|
||||||
# Arrange
|
middle = 1e-11
|
||||||
middle = 0.5
|
pos = 1e-12
|
||||||
pos = 0.25
|
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
ret = GimpGradientFile.linear(middle, pos)
|
ret = GimpGradientFile.linear(middle, pos)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(ret, 0.25)
|
assert ret == 0.0
|
||||||
|
|
||||||
def test_linear_pos_le_small_middle(self):
|
|
||||||
# Arrange
|
|
||||||
middle = 1e-11
|
|
||||||
pos = 1e-12
|
|
||||||
|
|
||||||
# Act
|
def test_linear_pos_gt_middle():
|
||||||
ret = GimpGradientFile.linear(middle, pos)
|
# Arrange
|
||||||
|
middle = 0.5
|
||||||
|
pos = 0.75
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(ret, 0.0)
|
ret = GimpGradientFile.linear(middle, pos)
|
||||||
|
|
||||||
def test_linear_pos_gt_middle(self):
|
# Assert
|
||||||
# Arrange
|
assert ret == 0.75
|
||||||
middle = 0.5
|
|
||||||
pos = 0.75
|
|
||||||
|
|
||||||
# Act
|
|
||||||
ret = GimpGradientFile.linear(middle, pos)
|
|
||||||
|
|
||||||
# Assert
|
def test_linear_pos_gt_small_middle():
|
||||||
self.assertEqual(ret, 0.75)
|
# Arrange
|
||||||
|
middle = 1 - 1e-11
|
||||||
|
pos = 1 - 1e-12
|
||||||
|
|
||||||
def test_linear_pos_gt_small_middle(self):
|
# Act
|
||||||
# Arrange
|
ret = GimpGradientFile.linear(middle, pos)
|
||||||
middle = 1 - 1e-11
|
|
||||||
pos = 1 - 1e-12
|
|
||||||
|
|
||||||
# Act
|
# Assert
|
||||||
ret = GimpGradientFile.linear(middle, pos)
|
assert ret == 1.0
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertEqual(ret, 1.0)
|
|
||||||
|
|
||||||
def test_curved(self):
|
def test_curved():
|
||||||
# Arrange
|
# Arrange
|
||||||
middle = 0.5
|
middle = 0.5
|
||||||
pos = 0.75
|
pos = 0.75
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
ret = GimpGradientFile.curved(middle, pos)
|
ret = GimpGradientFile.curved(middle, pos)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(ret, 0.75)
|
assert ret == 0.75
|
||||||
|
|
||||||
def test_sine(self):
|
|
||||||
# Arrange
|
|
||||||
middle = 0.5
|
|
||||||
pos = 0.75
|
|
||||||
|
|
||||||
# Act
|
def test_sine():
|
||||||
ret = GimpGradientFile.sine(middle, pos)
|
# Arrange
|
||||||
|
middle = 0.5
|
||||||
|
pos = 0.75
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(ret, 0.8535533905932737)
|
ret = GimpGradientFile.sine(middle, pos)
|
||||||
|
|
||||||
def test_sphere_increasing(self):
|
# Assert
|
||||||
# Arrange
|
assert ret == 0.8535533905932737
|
||||||
middle = 0.5
|
|
||||||
pos = 0.75
|
|
||||||
|
|
||||||
# Act
|
|
||||||
ret = GimpGradientFile.sphere_increasing(middle, pos)
|
|
||||||
|
|
||||||
# Assert
|
def test_sphere_increasing():
|
||||||
self.assertAlmostEqual(ret, 0.9682458365518543)
|
# Arrange
|
||||||
|
middle = 0.5
|
||||||
|
pos = 0.75
|
||||||
|
|
||||||
def test_sphere_decreasing(self):
|
# Act
|
||||||
# Arrange
|
ret = GimpGradientFile.sphere_increasing(middle, pos)
|
||||||
middle = 0.5
|
|
||||||
pos = 0.75
|
|
||||||
|
|
||||||
# Act
|
# Assert
|
||||||
ret = GimpGradientFile.sphere_decreasing(middle, pos)
|
assert round(abs(ret - 0.9682458365518543), 7) == 0
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertEqual(ret, 0.3385621722338523)
|
|
||||||
|
|
||||||
def test_load_via_imagepalette(self):
|
def test_sphere_decreasing():
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ImagePalette
|
middle = 0.5
|
||||||
|
pos = 0.75
|
||||||
|
|
||||||
test_file = "Tests/images/gimp_gradient.ggr"
|
# Act
|
||||||
|
ret = GimpGradientFile.sphere_decreasing(middle, pos)
|
||||||
|
|
||||||
# Act
|
# Assert
|
||||||
palette = ImagePalette.load(test_file)
|
assert ret == 0.3385621722338523
|
||||||
|
|
||||||
# Assert
|
|
||||||
# load returns raw palette information
|
|
||||||
self.assertEqual(len(palette[0]), 1024)
|
|
||||||
self.assertEqual(palette[1], "RGBA")
|
|
||||||
|
|
||||||
def test_load_1_3_via_imagepalette(self):
|
def test_load_via_imagepalette():
|
||||||
# Arrange
|
# Arrange
|
||||||
from PIL import ImagePalette
|
from PIL import ImagePalette
|
||||||
|
|
||||||
# GIMP 1.3 gradient files contain a name field
|
test_file = "Tests/images/gimp_gradient.ggr"
|
||||||
test_file = "Tests/images/gimp_gradient_with_name.ggr"
|
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
palette = ImagePalette.load(test_file)
|
palette = ImagePalette.load(test_file)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
# load returns raw palette information
|
# load returns raw palette information
|
||||||
self.assertEqual(len(palette[0]), 1024)
|
assert len(palette[0]) == 1024
|
||||||
self.assertEqual(palette[1], "RGBA")
|
assert palette[1] == "RGBA"
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_1_3_via_imagepalette():
|
||||||
|
# Arrange
|
||||||
|
from PIL import ImagePalette
|
||||||
|
|
||||||
|
# GIMP 1.3 gradient files contain a name field
|
||||||
|
test_file = "Tests/images/gimp_gradient_with_name.ggr"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
palette = ImagePalette.load(test_file)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
# load returns raw palette information
|
||||||
|
assert len(palette[0]) == 1024
|
||||||
|
assert palette[1] == "RGBA"
|
||||||
|
|
|
@ -1,28 +1,30 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, McIdasImagePlugin
|
from PIL import Image, McIdasImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal
|
from .helper import assert_image_equal
|
||||||
|
|
||||||
|
|
||||||
class TestFileMcIdas(PillowTestCase):
|
def test_invalid_file():
|
||||||
def test_invalid_file(self):
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, McIdasImagePlugin.McIdasImageFile, invalid_file)
|
with pytest.raises(SyntaxError):
|
||||||
|
McIdasImagePlugin.McIdasImageFile(invalid_file)
|
||||||
|
|
||||||
def test_valid_file(self):
|
|
||||||
# Arrange
|
|
||||||
# https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8
|
|
||||||
# https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/
|
|
||||||
test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara"
|
|
||||||
saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png"
|
|
||||||
|
|
||||||
# Act
|
def test_valid_file():
|
||||||
with Image.open(test_file) as im:
|
# Arrange
|
||||||
im.load()
|
# https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8
|
||||||
|
# https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/
|
||||||
|
test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara"
|
||||||
|
saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png"
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(im.format, "MCIDAS")
|
with Image.open(test_file) as im:
|
||||||
self.assertEqual(im.mode, "I")
|
im.load()
|
||||||
self.assertEqual(im.size, (1800, 400))
|
|
||||||
with Image.open(saved_file) as im2:
|
# Assert
|
||||||
assert_image_equal(im, im2)
|
assert im.format == "MCIDAS"
|
||||||
|
assert im.mode == "I"
|
||||||
|
assert im.size == (1800, 400)
|
||||||
|
with Image.open(saved_file) as im2:
|
||||||
|
assert_image_equal(im, im2)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import unittest
|
import pytest
|
||||||
|
|
||||||
from PIL import Image, ImagePalette, features
|
from PIL import Image, ImagePalette, features
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_similar, hopper
|
from .helper import assert_image_similar, hopper
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import MicImagePlugin
|
from PIL import MicImagePlugin
|
||||||
|
@ -14,52 +13,59 @@ else:
|
||||||
TEST_FILE = "Tests/images/hopper.mic"
|
TEST_FILE = "Tests/images/hopper.mic"
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(olefile_installed, "olefile package not installed")
|
pytestmark = [
|
||||||
@unittest.skipUnless(features.check("libtiff"), "libtiff not installed")
|
pytest.mark.skipif(not olefile_installed, reason="olefile package not installed"),
|
||||||
class TestFileMic(PillowTestCase):
|
pytest.mark.skipif(not features.check("libtiff"), reason="libtiff not installed"),
|
||||||
def test_sanity(self):
|
]
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
im.load()
|
|
||||||
self.assertEqual(im.mode, "RGBA")
|
|
||||||
self.assertEqual(im.size, (128, 128))
|
|
||||||
self.assertEqual(im.format, "MIC")
|
|
||||||
|
|
||||||
# Adjust for the gamma of 2.2 encoded into the file
|
|
||||||
lut = ImagePalette.make_gamma_lut(1 / 2.2)
|
|
||||||
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
|
|
||||||
|
|
||||||
im2 = hopper("RGBA")
|
def test_sanity():
|
||||||
assert_image_similar(im, im2, 10)
|
with Image.open(TEST_FILE) as im:
|
||||||
|
im.load()
|
||||||
|
assert im.mode == "RGBA"
|
||||||
|
assert im.size == (128, 128)
|
||||||
|
assert im.format == "MIC"
|
||||||
|
|
||||||
def test_n_frames(self):
|
# Adjust for the gamma of 2.2 encoded into the file
|
||||||
with Image.open(TEST_FILE) as im:
|
lut = ImagePalette.make_gamma_lut(1 / 2.2)
|
||||||
|
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
|
||||||
|
|
||||||
self.assertEqual(im.n_frames, 1)
|
im2 = hopper("RGBA")
|
||||||
|
assert_image_similar(im, im2, 10)
|
||||||
|
|
||||||
def test_is_animated(self):
|
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
|
|
||||||
self.assertFalse(im.is_animated)
|
def test_n_frames():
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
assert im.n_frames == 1
|
||||||
|
|
||||||
def test_tell(self):
|
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
|
|
||||||
self.assertEqual(im.tell(), 0)
|
def test_is_animated():
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
assert not im.is_animated
|
||||||
|
|
||||||
def test_seek(self):
|
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
|
|
||||||
im.seek(0)
|
def test_tell():
|
||||||
self.assertEqual(im.tell(), 0)
|
with Image.open(TEST_FILE) as im:
|
||||||
|
assert im.tell() == 0
|
||||||
|
|
||||||
self.assertRaises(EOFError, im.seek, 99)
|
|
||||||
self.assertEqual(im.tell(), 0)
|
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_seek():
|
||||||
# Test an invalid OLE file
|
with Image.open(TEST_FILE) as im:
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
im.seek(0)
|
||||||
self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, invalid_file)
|
assert im.tell() == 0
|
||||||
|
|
||||||
# Test a valid OLE file, but not a MIC file
|
with pytest.raises(EOFError):
|
||||||
ole_file = "Tests/images/test-ole-file.doc"
|
im.seek(99)
|
||||||
self.assertRaises(SyntaxError, MicImagePlugin.MicImageFile, ole_file)
|
assert im.tell() == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_file():
|
||||||
|
# Test an invalid OLE file
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
MicImagePlugin.MicImageFile(invalid_file)
|
||||||
|
|
||||||
|
# Test a valid OLE file, but not a MIC file
|
||||||
|
ole_file = "Tests/images/test-ole-file.doc"
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
MicImagePlugin.MicImageFile(ole_file)
|
||||||
|
|
|
@ -1,202 +1,221 @@
|
||||||
import unittest
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_similar, is_pypy
|
from .helper import assert_image_similar, is_pypy
|
||||||
|
|
||||||
test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
|
test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
|
||||||
|
|
||||||
|
|
||||||
class TestFileMpo(PillowTestCase):
|
def setup_module():
|
||||||
def setUp(self):
|
codecs = dir(Image.core)
|
||||||
codecs = dir(Image.core)
|
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
pytest.skip("jpeg support not available")
|
||||||
self.skipTest("jpeg support not available")
|
|
||||||
|
|
||||||
def frame_roundtrip(self, im, **options):
|
|
||||||
# Note that for now, there is no MPO saving functionality
|
|
||||||
out = BytesIO()
|
|
||||||
im.save(out, "MPO", **options)
|
|
||||||
test_bytes = out.tell()
|
|
||||||
out.seek(0)
|
|
||||||
im = Image.open(out)
|
|
||||||
im.bytes = test_bytes # for testing only
|
|
||||||
return im
|
|
||||||
|
|
||||||
def test_sanity(self):
|
def frame_roundtrip(im, **options):
|
||||||
for test_file in test_files:
|
# Note that for now, there is no MPO saving functionality
|
||||||
with Image.open(test_file) as im:
|
out = BytesIO()
|
||||||
im.load()
|
im.save(out, "MPO", **options)
|
||||||
self.assertEqual(im.mode, "RGB")
|
test_bytes = out.tell()
|
||||||
self.assertEqual(im.size, (640, 480))
|
out.seek(0)
|
||||||
self.assertEqual(im.format, "MPO")
|
im = Image.open(out)
|
||||||
|
im.bytes = test_bytes # for testing only
|
||||||
|
return im
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy(), "Requires CPython")
|
|
||||||
def test_unclosed_file(self):
|
def test_sanity():
|
||||||
def open():
|
for test_file in test_files:
|
||||||
im = Image.open(test_files[0])
|
with Image.open(test_file) as im:
|
||||||
|
im.load()
|
||||||
|
assert im.mode == "RGB"
|
||||||
|
assert im.size == (640, 480)
|
||||||
|
assert im.format == "MPO"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
|
||||||
|
def test_unclosed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(test_files[0])
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
pytest.warns(ResourceWarning, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_closed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(test_files[0])
|
||||||
|
im.load()
|
||||||
|
im.close()
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_context_manager():
|
||||||
|
def open():
|
||||||
|
with Image.open(test_files[0]) as im:
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
pytest.warns(ResourceWarning, open)
|
pytest.warns(None, open)
|
||||||
|
|
||||||
def test_closed_file(self):
|
|
||||||
def open():
|
|
||||||
im = Image.open(test_files[0])
|
|
||||||
im.load()
|
|
||||||
im.close()
|
|
||||||
|
|
||||||
pytest.warns(None, open)
|
def test_app():
|
||||||
|
for test_file in test_files:
|
||||||
def test_context_manager(self):
|
# Test APP/COM reader (@PIL135)
|
||||||
def open():
|
with Image.open(test_file) as im:
|
||||||
with Image.open(test_files[0]) as im:
|
assert im.applist[0][0] == "APP1"
|
||||||
im.load()
|
assert im.applist[1][0] == "APP2"
|
||||||
|
assert (
|
||||||
pytest.warns(None, open)
|
im.applist[1][1][:16]
|
||||||
|
== b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
|
||||||
def test_app(self):
|
|
||||||
for test_file in test_files:
|
|
||||||
# Test APP/COM reader (@PIL135)
|
|
||||||
with Image.open(test_file) as im:
|
|
||||||
self.assertEqual(im.applist[0][0], "APP1")
|
|
||||||
self.assertEqual(im.applist[1][0], "APP2")
|
|
||||||
self.assertEqual(
|
|
||||||
im.applist[1][1][:16],
|
|
||||||
b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00",
|
|
||||||
)
|
|
||||||
self.assertEqual(len(im.applist), 2)
|
|
||||||
|
|
||||||
def test_exif(self):
|
|
||||||
for test_file in test_files:
|
|
||||||
with Image.open(test_file) as im:
|
|
||||||
info = im._getexif()
|
|
||||||
self.assertEqual(info[272], "Nintendo 3DS")
|
|
||||||
self.assertEqual(info[296], 2)
|
|
||||||
self.assertEqual(info[34665], 188)
|
|
||||||
|
|
||||||
def test_frame_size(self):
|
|
||||||
# This image has been hexedited to contain a different size
|
|
||||||
# in the EXIF data of the second frame
|
|
||||||
with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
|
|
||||||
self.assertEqual(im.size, (640, 480))
|
|
||||||
|
|
||||||
im.seek(1)
|
|
||||||
self.assertEqual(im.size, (680, 480))
|
|
||||||
|
|
||||||
def test_parallax(self):
|
|
||||||
# Nintendo
|
|
||||||
with Image.open("Tests/images/sugarshack.mpo") as im:
|
|
||||||
exif = im.getexif()
|
|
||||||
self.assertEqual(
|
|
||||||
exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375
|
|
||||||
)
|
)
|
||||||
|
assert len(im.applist) == 2
|
||||||
|
|
||||||
# Fujifilm
|
|
||||||
with Image.open("Tests/images/fujifilm.mpo") as im:
|
|
||||||
im.seek(1)
|
|
||||||
exif = im.getexif()
|
|
||||||
self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125)
|
|
||||||
|
|
||||||
def test_mp(self):
|
def test_exif():
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
mpinfo = im._getmp()
|
info = im._getexif()
|
||||||
self.assertEqual(mpinfo[45056], b"0100")
|
assert info[272] == "Nintendo 3DS"
|
||||||
self.assertEqual(mpinfo[45057], 2)
|
assert info[296] == 2
|
||||||
|
assert info[34665] == 188
|
||||||
|
|
||||||
def test_mp_offset(self):
|
|
||||||
# This image has been manually hexedited to have an IFD offset of 10
|
def test_frame_size():
|
||||||
# in APP2 data, in contrast to normal 8
|
# This image has been hexedited to contain a different size
|
||||||
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
|
# in the EXIF data of the second frame
|
||||||
|
with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
|
||||||
|
assert im.size == (640, 480)
|
||||||
|
|
||||||
|
im.seek(1)
|
||||||
|
assert im.size == (680, 480)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parallax():
|
||||||
|
# Nintendo
|
||||||
|
with Image.open("Tests/images/sugarshack.mpo") as im:
|
||||||
|
exif = im.getexif()
|
||||||
|
assert exif.get_ifd(0x927C)[0x1101]["Parallax"] == -44.798187255859375
|
||||||
|
|
||||||
|
# Fujifilm
|
||||||
|
with Image.open("Tests/images/fujifilm.mpo") as im:
|
||||||
|
im.seek(1)
|
||||||
|
exif = im.getexif()
|
||||||
|
assert exif.get_ifd(0x927C)[0xB211] == -3.125
|
||||||
|
|
||||||
|
|
||||||
|
def test_mp():
|
||||||
|
for test_file in test_files:
|
||||||
|
with Image.open(test_file) as im:
|
||||||
mpinfo = im._getmp()
|
mpinfo = im._getmp()
|
||||||
self.assertEqual(mpinfo[45056], b"0100")
|
assert mpinfo[45056] == b"0100"
|
||||||
self.assertEqual(mpinfo[45057], 2)
|
assert mpinfo[45057] == 2
|
||||||
|
|
||||||
def test_mp_no_data(self):
|
|
||||||
# This image has been manually hexedited to have the second frame
|
|
||||||
# beyond the end of the file
|
|
||||||
with Image.open("Tests/images/sugarshack_no_data.mpo") as im:
|
|
||||||
with self.assertRaises(ValueError):
|
|
||||||
im.seek(1)
|
|
||||||
|
|
||||||
def test_mp_attribute(self):
|
def test_mp_offset():
|
||||||
for test_file in test_files:
|
# This image has been manually hexedited to have an IFD offset of 10
|
||||||
with Image.open(test_file) as im:
|
# in APP2 data, in contrast to normal 8
|
||||||
mpinfo = im._getmp()
|
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
|
||||||
frameNumber = 0
|
mpinfo = im._getmp()
|
||||||
for mpentry in mpinfo[45058]:
|
assert mpinfo[45056] == b"0100"
|
||||||
mpattr = mpentry["Attribute"]
|
assert mpinfo[45057] == 2
|
||||||
if frameNumber:
|
|
||||||
self.assertFalse(mpattr["RepresentativeImageFlag"])
|
|
||||||
else:
|
|
||||||
self.assertTrue(mpattr["RepresentativeImageFlag"])
|
|
||||||
self.assertFalse(mpattr["DependentParentImageFlag"])
|
|
||||||
self.assertFalse(mpattr["DependentChildImageFlag"])
|
|
||||||
self.assertEqual(mpattr["ImageDataFormat"], "JPEG")
|
|
||||||
self.assertEqual(mpattr["MPType"], "Multi-Frame Image: (Disparity)")
|
|
||||||
self.assertEqual(mpattr["Reserved"], 0)
|
|
||||||
frameNumber += 1
|
|
||||||
|
|
||||||
def test_seek(self):
|
|
||||||
for test_file in test_files:
|
|
||||||
with Image.open(test_file) as im:
|
|
||||||
self.assertEqual(im.tell(), 0)
|
|
||||||
# prior to first image raises an error, both blatant and borderline
|
|
||||||
self.assertRaises(EOFError, im.seek, -1)
|
|
||||||
self.assertRaises(EOFError, im.seek, -523)
|
|
||||||
# after the final image raises an error,
|
|
||||||
# both blatant and borderline
|
|
||||||
self.assertRaises(EOFError, im.seek, 2)
|
|
||||||
self.assertRaises(EOFError, im.seek, 523)
|
|
||||||
# bad calls shouldn't change the frame
|
|
||||||
self.assertEqual(im.tell(), 0)
|
|
||||||
# this one will work
|
|
||||||
im.seek(1)
|
|
||||||
self.assertEqual(im.tell(), 1)
|
|
||||||
# and this one, too
|
|
||||||
im.seek(0)
|
|
||||||
self.assertEqual(im.tell(), 0)
|
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_mp_no_data():
|
||||||
with Image.open("Tests/images/sugarshack.mpo") as im:
|
# This image has been manually hexedited to have the second frame
|
||||||
self.assertEqual(im.n_frames, 2)
|
# beyond the end of the file
|
||||||
self.assertTrue(im.is_animated)
|
with Image.open("Tests/images/sugarshack_no_data.mpo") as im:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
im.seek(1)
|
||||||
|
|
||||||
def test_eoferror(self):
|
|
||||||
with Image.open("Tests/images/sugarshack.mpo") as im:
|
|
||||||
n_frames = im.n_frames
|
|
||||||
|
|
||||||
# Test seeking past the last frame
|
def test_mp_attribute():
|
||||||
self.assertRaises(EOFError, im.seek, n_frames)
|
for test_file in test_files:
|
||||||
self.assertLess(im.tell(), n_frames)
|
with Image.open(test_file) as im:
|
||||||
|
mpinfo = im._getmp()
|
||||||
|
frameNumber = 0
|
||||||
|
for mpentry in mpinfo[45058]:
|
||||||
|
mpattr = mpentry["Attribute"]
|
||||||
|
if frameNumber:
|
||||||
|
assert not mpattr["RepresentativeImageFlag"]
|
||||||
|
else:
|
||||||
|
assert mpattr["RepresentativeImageFlag"]
|
||||||
|
assert not mpattr["DependentParentImageFlag"]
|
||||||
|
assert not mpattr["DependentChildImageFlag"]
|
||||||
|
assert mpattr["ImageDataFormat"] == "JPEG"
|
||||||
|
assert mpattr["MPType"] == "Multi-Frame Image: (Disparity)"
|
||||||
|
assert mpattr["Reserved"] == 0
|
||||||
|
frameNumber += 1
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
|
||||||
im.seek(n_frames - 1)
|
|
||||||
|
|
||||||
def test_image_grab(self):
|
def test_seek():
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
self.assertEqual(im.tell(), 0)
|
assert im.tell() == 0
|
||||||
im0 = im.tobytes()
|
# prior to first image raises an error, both blatant and borderline
|
||||||
im.seek(1)
|
with pytest.raises(EOFError):
|
||||||
self.assertEqual(im.tell(), 1)
|
im.seek(-1)
|
||||||
im1 = im.tobytes()
|
with pytest.raises(EOFError):
|
||||||
im.seek(0)
|
im.seek(-523)
|
||||||
self.assertEqual(im.tell(), 0)
|
# after the final image raises an error,
|
||||||
im02 = im.tobytes()
|
# both blatant and borderline
|
||||||
self.assertEqual(im0, im02)
|
with pytest.raises(EOFError):
|
||||||
self.assertNotEqual(im0, im1)
|
im.seek(2)
|
||||||
|
with pytest.raises(EOFError):
|
||||||
|
im.seek(523)
|
||||||
|
# bad calls shouldn't change the frame
|
||||||
|
assert im.tell() == 0
|
||||||
|
# this one will work
|
||||||
|
im.seek(1)
|
||||||
|
assert im.tell() == 1
|
||||||
|
# and this one, too
|
||||||
|
im.seek(0)
|
||||||
|
assert im.tell() == 0
|
||||||
|
|
||||||
def test_save(self):
|
|
||||||
# Note that only individual frames can be saved at present
|
def test_n_frames():
|
||||||
for test_file in test_files:
|
with Image.open("Tests/images/sugarshack.mpo") as im:
|
||||||
with Image.open(test_file) as im:
|
assert im.n_frames == 2
|
||||||
self.assertEqual(im.tell(), 0)
|
assert im.is_animated
|
||||||
jpg0 = self.frame_roundtrip(im)
|
|
||||||
assert_image_similar(im, jpg0, 30)
|
|
||||||
im.seek(1)
|
def test_eoferror():
|
||||||
self.assertEqual(im.tell(), 1)
|
with Image.open("Tests/images/sugarshack.mpo") as im:
|
||||||
jpg1 = self.frame_roundtrip(im)
|
n_frames = im.n_frames
|
||||||
assert_image_similar(im, jpg1, 30)
|
|
||||||
|
# Test seeking past the last frame
|
||||||
|
with pytest.raises(EOFError):
|
||||||
|
im.seek(n_frames)
|
||||||
|
assert im.tell() < n_frames
|
||||||
|
|
||||||
|
# Test that seeking to the last frame does not raise an error
|
||||||
|
im.seek(n_frames - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_image_grab():
|
||||||
|
for test_file in test_files:
|
||||||
|
with Image.open(test_file) as im:
|
||||||
|
assert im.tell() == 0
|
||||||
|
im0 = im.tobytes()
|
||||||
|
im.seek(1)
|
||||||
|
assert im.tell() == 1
|
||||||
|
im1 = im.tobytes()
|
||||||
|
im.seek(0)
|
||||||
|
assert im.tell() == 0
|
||||||
|
im02 = im.tobytes()
|
||||||
|
assert im0 == im02
|
||||||
|
assert im0 != im1
|
||||||
|
|
||||||
|
|
||||||
|
def test_save():
|
||||||
|
# Note that only individual frames can be saved at present
|
||||||
|
for test_file in test_files:
|
||||||
|
with Image.open(test_file) as im:
|
||||||
|
assert im.tell() == 0
|
||||||
|
jpg0 = frame_roundtrip(im)
|
||||||
|
assert_image_similar(im, jpg0, 30)
|
||||||
|
im.seek(1)
|
||||||
|
assert im.tell() == 1
|
||||||
|
jpg1 = frame_roundtrip(im)
|
||||||
|
assert_image_similar(im, jpg1, 30)
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, PixarImagePlugin
|
from PIL import Image, PixarImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_similar, hopper
|
from .helper import assert_image_similar, hopper
|
||||||
|
|
||||||
TEST_FILE = "Tests/images/hopper.pxr"
|
TEST_FILE = "Tests/images/hopper.pxr"
|
||||||
|
|
||||||
|
|
||||||
class TestFilePixar(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"
|
||||||
self.assertEqual(im.mode, "RGB")
|
assert im.size == (128, 128)
|
||||||
self.assertEqual(im.size, (128, 128))
|
assert im.format == "PIXAR"
|
||||||
self.assertEqual(im.format, "PIXAR")
|
assert im.get_format_mimetype() is None
|
||||||
self.assertIsNone(im.get_format_mimetype())
|
|
||||||
|
|
||||||
im2 = hopper()
|
im2 = hopper()
|
||||||
assert_image_similar(im, im2, 4.8)
|
assert_image_similar(im, im2, 4.8)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, PixarImagePlugin.PixarImageFile, invalid_file)
|
def test_invalid_file():
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
PixarImagePlugin.PixarImageFile(invalid_file)
|
||||||
|
|
|
@ -1,116 +1,129 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import Image, PsdImagePlugin
|
from PIL import Image, PsdImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_similar, hopper, is_pypy
|
from .helper import assert_image_similar, hopper, is_pypy
|
||||||
|
|
||||||
test_file = "Tests/images/hopper.psd"
|
test_file = "Tests/images/hopper.psd"
|
||||||
|
|
||||||
|
|
||||||
class TestImagePsd(PillowTestCase):
|
def test_sanity():
|
||||||
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 == "PSD"
|
||||||
|
|
||||||
|
im2 = hopper()
|
||||||
|
assert_image_similar(im, im2, 4.8)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
|
||||||
|
def test_unclosed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(test_file)
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
pytest.warns(ResourceWarning, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_closed_file():
|
||||||
|
def open():
|
||||||
|
im = Image.open(test_file)
|
||||||
|
im.load()
|
||||||
|
im.close()
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_context_manager():
|
||||||
|
def open():
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, "RGB")
|
|
||||||
self.assertEqual(im.size, (128, 128))
|
|
||||||
self.assertEqual(im.format, "PSD")
|
|
||||||
|
|
||||||
im2 = hopper()
|
pytest.warns(None, open)
|
||||||
assert_image_similar(im, im2, 4.8)
|
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy(), "Requires CPython")
|
|
||||||
def test_unclosed_file(self):
|
|
||||||
def open():
|
|
||||||
im = Image.open(test_file)
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
pytest.warns(ResourceWarning, open)
|
def test_invalid_file():
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
def test_closed_file(self):
|
with pytest.raises(SyntaxError):
|
||||||
def open():
|
PsdImagePlugin.PsdImageFile(invalid_file)
|
||||||
im = Image.open(test_file)
|
|
||||||
im.load()
|
|
||||||
im.close()
|
|
||||||
|
|
||||||
pytest.warns(None, open)
|
|
||||||
|
|
||||||
def test_context_manager(self):
|
def test_n_frames():
|
||||||
def open():
|
with Image.open("Tests/images/hopper_merged.psd") as im:
|
||||||
with Image.open(test_file) as im:
|
assert im.n_frames == 1
|
||||||
im.load()
|
assert not im.is_animated
|
||||||
|
|
||||||
pytest.warns(None, open)
|
with Image.open(test_file) as im:
|
||||||
|
assert im.n_frames == 2
|
||||||
|
assert im.is_animated
|
||||||
|
|
||||||
def test_invalid_file(self):
|
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file)
|
def test_eoferror():
|
||||||
|
with Image.open(test_file) as im:
|
||||||
|
# PSD seek index starts at 1 rather than 0
|
||||||
|
n_frames = im.n_frames + 1
|
||||||
|
|
||||||
def test_n_frames(self):
|
# Test seeking past the last frame
|
||||||
with Image.open("Tests/images/hopper_merged.psd") as im:
|
with pytest.raises(EOFError):
|
||||||
self.assertEqual(im.n_frames, 1)
|
im.seek(n_frames)
|
||||||
self.assertFalse(im.is_animated)
|
assert im.tell() < n_frames
|
||||||
|
|
||||||
with Image.open(test_file) as im:
|
# Test that seeking to the last frame does not raise an error
|
||||||
self.assertEqual(im.n_frames, 2)
|
im.seek(n_frames - 1)
|
||||||
self.assertTrue(im.is_animated)
|
|
||||||
|
|
||||||
def test_eoferror(self):
|
|
||||||
with Image.open(test_file) as im:
|
|
||||||
# PSD seek index starts at 1 rather than 0
|
|
||||||
n_frames = im.n_frames + 1
|
|
||||||
|
|
||||||
# Test seeking past the last frame
|
def test_seek_tell():
|
||||||
self.assertRaises(EOFError, im.seek, n_frames)
|
with Image.open(test_file) as im:
|
||||||
self.assertLess(im.tell(), n_frames)
|
|
||||||
|
|
||||||
# Test that seeking to the last frame does not raise an error
|
layer_number = im.tell()
|
||||||
im.seek(n_frames - 1)
|
assert layer_number == 1
|
||||||
|
|
||||||
def test_seek_tell(self):
|
with pytest.raises(EOFError):
|
||||||
with Image.open(test_file) as im:
|
im.seek(0)
|
||||||
|
|
||||||
layer_number = im.tell()
|
im.seek(1)
|
||||||
self.assertEqual(layer_number, 1)
|
layer_number = im.tell()
|
||||||
|
assert layer_number == 1
|
||||||
|
|
||||||
self.assertRaises(EOFError, im.seek, 0)
|
im.seek(2)
|
||||||
|
layer_number = im.tell()
|
||||||
|
assert layer_number == 2
|
||||||
|
|
||||||
im.seek(1)
|
|
||||||
layer_number = im.tell()
|
|
||||||
self.assertEqual(layer_number, 1)
|
|
||||||
|
|
||||||
im.seek(2)
|
def test_seek_eoferror():
|
||||||
layer_number = im.tell()
|
with Image.open(test_file) as im:
|
||||||
self.assertEqual(layer_number, 2)
|
|
||||||
|
|
||||||
def test_seek_eoferror(self):
|
with pytest.raises(EOFError):
|
||||||
with Image.open(test_file) as im:
|
im.seek(-1)
|
||||||
|
|
||||||
self.assertRaises(EOFError, im.seek, -1)
|
|
||||||
|
|
||||||
def test_open_after_exclusive_load(self):
|
def test_open_after_exclusive_load():
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
im.load()
|
im.load()
|
||||||
im.seek(im.tell() + 1)
|
im.seek(im.tell() + 1)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
def test_icc_profile(self):
|
|
||||||
with Image.open(test_file) as im:
|
|
||||||
self.assertIn("icc_profile", im.info)
|
|
||||||
|
|
||||||
icc_profile = im.info["icc_profile"]
|
def test_icc_profile():
|
||||||
self.assertEqual(len(icc_profile), 3144)
|
with Image.open(test_file) as im:
|
||||||
|
assert "icc_profile" in im.info
|
||||||
|
|
||||||
def test_no_icc_profile(self):
|
icc_profile = im.info["icc_profile"]
|
||||||
with Image.open("Tests/images/hopper_merged.psd") as im:
|
assert len(icc_profile) == 3144
|
||||||
self.assertNotIn("icc_profile", im.info)
|
|
||||||
|
|
||||||
def test_combined_larger_than_size(self):
|
|
||||||
# The 'combined' sizes of the individual parts is larger than the
|
|
||||||
# declared 'size' of the extra data field, resulting in a backwards seek.
|
|
||||||
|
|
||||||
# If we instead take the 'size' of the extra data field as the source of truth,
|
def test_no_icc_profile():
|
||||||
# then the seek can't be negative
|
with Image.open("Tests/images/hopper_merged.psd") as im:
|
||||||
with self.assertRaises(IOError):
|
assert "icc_profile" not in im.info
|
||||||
Image.open("Tests/images/combined_larger_than_size.psd")
|
|
||||||
|
|
||||||
|
def test_combined_larger_than_size():
|
||||||
|
# The 'combined' sizes of the individual parts is larger than the
|
||||||
|
# declared 'size' of the extra data field, resulting in a backwards seek.
|
||||||
|
|
||||||
|
# If we instead take the 'size' of the extra data field as the source of truth,
|
||||||
|
# then the seek can't be negative
|
||||||
|
with pytest.raises(IOError):
|
||||||
|
Image.open("Tests/images/combined_larger_than_size.psd")
|
||||||
|
|
|
@ -1,47 +1,51 @@
|
||||||
import os
|
import os
|
||||||
import unittest
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
from PIL import Image, SunImagePlugin
|
from PIL import Image, SunImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper
|
from .helper import assert_image_equal, assert_image_similar, hopper
|
||||||
|
|
||||||
EXTRA_DIR = "Tests/images/sunraster"
|
EXTRA_DIR = "Tests/images/sunraster"
|
||||||
|
|
||||||
|
|
||||||
class TestFileSun(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
# Arrange
|
||||||
# Arrange
|
# Created with ImageMagick: convert hopper.jpg hopper.ras
|
||||||
# Created with ImageMagick: convert hopper.jpg hopper.ras
|
test_file = "Tests/images/hopper.ras"
|
||||||
test_file = "Tests/images/hopper.ras"
|
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (128, 128))
|
assert im.size == (128, 128)
|
||||||
|
|
||||||
assert_image_similar(im, hopper(), 5) # visually verified
|
assert_image_similar(im, hopper(), 5) # visually verified
|
||||||
|
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
self.assertRaises(SyntaxError, SunImagePlugin.SunImageFile, invalid_file)
|
with pytest.raises(SyntaxError):
|
||||||
|
SunImagePlugin.SunImageFile(invalid_file)
|
||||||
|
|
||||||
def test_im1(self):
|
|
||||||
with Image.open("Tests/images/sunraster.im1") as im:
|
def test_im1():
|
||||||
with Image.open("Tests/images/sunraster.im1.png") as target:
|
with Image.open("Tests/images/sunraster.im1") as im:
|
||||||
|
with Image.open("Tests/images/sunraster.im1.png") as target:
|
||||||
|
assert_image_equal(im, target)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
|
||||||
|
)
|
||||||
|
def test_others():
|
||||||
|
files = (
|
||||||
|
os.path.join(EXTRA_DIR, f)
|
||||||
|
for f in os.listdir(EXTRA_DIR)
|
||||||
|
if os.path.splitext(f)[1] in (".sun", ".SUN", ".ras")
|
||||||
|
)
|
||||||
|
for path in files:
|
||||||
|
with Image.open(path) as im:
|
||||||
|
im.load()
|
||||||
|
assert isinstance(im, SunImagePlugin.SunImageFile)
|
||||||
|
target_path = "%s.png" % os.path.splitext(path)[0]
|
||||||
|
# im.save(target_file)
|
||||||
|
with Image.open(target_path) as target:
|
||||||
assert_image_equal(im, target)
|
assert_image_equal(im, target)
|
||||||
|
|
||||||
@unittest.skipUnless(os.path.exists(EXTRA_DIR), "Extra image files not installed")
|
|
||||||
def test_others(self):
|
|
||||||
files = (
|
|
||||||
os.path.join(EXTRA_DIR, f)
|
|
||||||
for f in os.listdir(EXTRA_DIR)
|
|
||||||
if os.path.splitext(f)[1] in (".sun", ".SUN", ".ras")
|
|
||||||
)
|
|
||||||
for path in files:
|
|
||||||
with Image.open(path) as im:
|
|
||||||
im.load()
|
|
||||||
self.assertIsInstance(im, SunImagePlugin.SunImageFile)
|
|
||||||
target_path = "%s.png" % os.path.splitext(path)[0]
|
|
||||||
# im.save(target_file)
|
|
||||||
with Image.open(target_path) as target:
|
|
||||||
assert_image_equal(im, target)
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import Image, TarIO
|
from PIL import Image, TarIO
|
||||||
|
|
||||||
from .helper import PillowTestCase, is_pypy
|
from .helper import is_pypy
|
||||||
|
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
|
|
||||||
|
@ -11,41 +9,44 @@ codecs = dir(Image.core)
|
||||||
TEST_TAR_FILE = "Tests/images/hopper.tar"
|
TEST_TAR_FILE = "Tests/images/hopper.tar"
|
||||||
|
|
||||||
|
|
||||||
class TestFileTar(PillowTestCase):
|
def setup_module():
|
||||||
def setUp(self):
|
if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs:
|
||||||
if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs:
|
pytest.skip("neither jpeg nor zip support available")
|
||||||
self.skipTest("neither jpeg nor zip support available")
|
|
||||||
|
|
||||||
def test_sanity(self):
|
|
||||||
for codec, test_path, format in [
|
|
||||||
["zip_decoder", "hopper.png", "PNG"],
|
|
||||||
["jpeg_decoder", "hopper.jpg", "JPEG"],
|
|
||||||
]:
|
|
||||||
if codec in codecs:
|
|
||||||
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
|
|
||||||
with Image.open(tar) as im:
|
|
||||||
im.load()
|
|
||||||
self.assertEqual(im.mode, "RGB")
|
|
||||||
self.assertEqual(im.size, (128, 128))
|
|
||||||
self.assertEqual(im.format, format)
|
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy(), "Requires CPython")
|
def test_sanity():
|
||||||
def test_unclosed_file(self):
|
for codec, test_path, format in [
|
||||||
def open():
|
["zip_decoder", "hopper.png", "PNG"],
|
||||||
TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
|
["jpeg_decoder", "hopper.jpg", "JPEG"],
|
||||||
|
]:
|
||||||
|
if codec in codecs:
|
||||||
|
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
|
||||||
|
with Image.open(tar) as im:
|
||||||
|
im.load()
|
||||||
|
assert im.mode == "RGB"
|
||||||
|
assert im.size == (128, 128)
|
||||||
|
assert im.format == format
|
||||||
|
|
||||||
pytest.warns(ResourceWarning, open)
|
|
||||||
|
|
||||||
def test_close(self):
|
@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
|
||||||
def open():
|
def test_unclosed_file():
|
||||||
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
|
def open():
|
||||||
tar.close()
|
TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
|
||||||
|
|
||||||
pytest.warns(None, open)
|
pytest.warns(ResourceWarning, open)
|
||||||
|
|
||||||
def test_contextmanager(self):
|
|
||||||
def open():
|
|
||||||
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
pytest.warns(None, open)
|
def test_close():
|
||||||
|
def open():
|
||||||
|
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
|
||||||
|
tar.close()
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
||||||
|
|
||||||
|
def test_contextmanager():
|
||||||
|
def open():
|
||||||
|
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
|
||||||
|
pass
|
||||||
|
|
||||||
|
pytest.warns(None, open)
|
||||||
|
|
|
@ -1,33 +1,36 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, XpmImagePlugin
|
from PIL import Image, XpmImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_similar, hopper
|
from .helper import assert_image_similar, hopper
|
||||||
|
|
||||||
TEST_FILE = "Tests/images/hopper.xpm"
|
TEST_FILE = "Tests/images/hopper.xpm"
|
||||||
|
|
||||||
|
|
||||||
class TestFileXpm(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 == "P"
|
||||||
self.assertEqual(im.mode, "P")
|
assert im.size == (128, 128)
|
||||||
self.assertEqual(im.size, (128, 128))
|
assert im.format == "XPM"
|
||||||
self.assertEqual(im.format, "XPM")
|
|
||||||
|
|
||||||
# large error due to quantization->44 colors.
|
# large error due to quantization->44 colors.
|
||||||
assert_image_similar(im.convert("RGB"), hopper("RGB"), 60)
|
assert_image_similar(im.convert("RGB"), hopper("RGB"), 60)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, XpmImagePlugin.XpmImageFile, invalid_file)
|
def test_invalid_file():
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
def test_load_read(self):
|
with pytest.raises(SyntaxError):
|
||||||
# Arrange
|
XpmImagePlugin.XpmImageFile(invalid_file)
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
dummy_bytes = 1
|
|
||||||
|
|
||||||
# Act
|
|
||||||
data = im.load_read(dummy_bytes)
|
|
||||||
|
|
||||||
# Assert
|
def test_load_read():
|
||||||
self.assertEqual(len(data), 16384)
|
# Arrange
|
||||||
|
with Image.open(TEST_FILE) as im:
|
||||||
|
dummy_bytes = 1
|
||||||
|
|
||||||
|
# Act
|
||||||
|
data = im.load_read(dummy_bytes)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert len(data) == 16384
|
||||||
|
|
|
@ -1,35 +1,37 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, XVThumbImagePlugin
|
from PIL import Image, XVThumbImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_similar, hopper
|
from .helper import assert_image_similar, hopper
|
||||||
|
|
||||||
TEST_FILE = "Tests/images/hopper.p7"
|
TEST_FILE = "Tests/images/hopper.p7"
|
||||||
|
|
||||||
|
|
||||||
class TestFileXVThumb(PillowTestCase):
|
def test_open():
|
||||||
def test_open(self):
|
# Act
|
||||||
# Act
|
with Image.open(TEST_FILE) as im:
|
||||||
with Image.open(TEST_FILE) as im:
|
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.format, "XVThumb")
|
assert im.format == "XVThumb"
|
||||||
|
|
||||||
# Create a Hopper image with a similar XV palette
|
# Create a Hopper image with a similar XV palette
|
||||||
im_hopper = hopper().quantize(palette=im)
|
im_hopper = hopper().quantize(palette=im)
|
||||||
assert_image_similar(im, im_hopper, 9)
|
assert_image_similar(im, im_hopper, 9)
|
||||||
|
|
||||||
def test_unexpected_eof(self):
|
|
||||||
# Test unexpected EOF reading XV thumbnail file
|
|
||||||
# Arrange
|
|
||||||
bad_file = "Tests/images/hopper_bad.p7"
|
|
||||||
|
|
||||||
# Act / Assert
|
def test_unexpected_eof():
|
||||||
self.assertRaises(SyntaxError, XVThumbImagePlugin.XVThumbImageFile, bad_file)
|
# Test unexpected EOF reading XV thumbnail file
|
||||||
|
# Arrange
|
||||||
|
bad_file = "Tests/images/hopper_bad.p7"
|
||||||
|
|
||||||
def test_invalid_file(self):
|
# Act / Assert
|
||||||
# Arrange
|
with pytest.raises(SyntaxError):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
XVThumbImagePlugin.XVThumbImageFile(bad_file)
|
||||||
|
|
||||||
# Act / Assert
|
|
||||||
self.assertRaises(
|
def test_invalid_file():
|
||||||
SyntaxError, XVThumbImagePlugin.XVThumbImageFile, invalid_file
|
# Arrange
|
||||||
)
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
# Act / Assert
|
||||||
|
with pytest.raises(SyntaxError):
|
||||||
|
XVThumbImagePlugin.XVThumbImageFile(invalid_file)
|
||||||
|
|
|
@ -1,103 +1,109 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageCrop(PillowTestCase):
|
def test_crop():
|
||||||
def test_crop(self):
|
def crop(mode):
|
||||||
def crop(mode):
|
im = hopper(mode)
|
||||||
im = hopper(mode)
|
assert_image_equal(im.crop(), im)
|
||||||
assert_image_equal(im.crop(), im)
|
|
||||||
|
|
||||||
cropped = im.crop((50, 50, 100, 100))
|
cropped = im.crop((50, 50, 100, 100))
|
||||||
self.assertEqual(cropped.mode, mode)
|
assert cropped.mode == mode
|
||||||
self.assertEqual(cropped.size, (50, 50))
|
assert cropped.size == (50, 50)
|
||||||
|
|
||||||
for mode in "1", "P", "L", "RGB", "I", "F":
|
for mode in "1", "P", "L", "RGB", "I", "F":
|
||||||
crop(mode)
|
crop(mode)
|
||||||
|
|
||||||
def test_wide_crop(self):
|
|
||||||
def crop(*bbox):
|
|
||||||
i = im.crop(bbox)
|
|
||||||
h = i.histogram()
|
|
||||||
while h and not h[-1]:
|
|
||||||
del h[-1]
|
|
||||||
return tuple(h)
|
|
||||||
|
|
||||||
im = Image.new("L", (100, 100), 1)
|
def test_wide_crop():
|
||||||
|
def crop(*bbox):
|
||||||
|
i = im.crop(bbox)
|
||||||
|
h = i.histogram()
|
||||||
|
while h and not h[-1]:
|
||||||
|
del h[-1]
|
||||||
|
return tuple(h)
|
||||||
|
|
||||||
self.assertEqual(crop(0, 0, 100, 100), (0, 10000))
|
im = Image.new("L", (100, 100), 1)
|
||||||
self.assertEqual(crop(25, 25, 75, 75), (0, 2500))
|
|
||||||
|
|
||||||
# sides
|
assert crop(0, 0, 100, 100) == (0, 10000)
|
||||||
self.assertEqual(crop(-25, 0, 25, 50), (1250, 1250))
|
assert crop(25, 25, 75, 75) == (0, 2500)
|
||||||
self.assertEqual(crop(0, -25, 50, 25), (1250, 1250))
|
|
||||||
self.assertEqual(crop(75, 0, 125, 50), (1250, 1250))
|
|
||||||
self.assertEqual(crop(0, 75, 50, 125), (1250, 1250))
|
|
||||||
|
|
||||||
self.assertEqual(crop(-25, 25, 125, 75), (2500, 5000))
|
# sides
|
||||||
self.assertEqual(crop(25, -25, 75, 125), (2500, 5000))
|
assert crop(-25, 0, 25, 50) == (1250, 1250)
|
||||||
|
assert crop(0, -25, 50, 25) == (1250, 1250)
|
||||||
|
assert crop(75, 0, 125, 50) == (1250, 1250)
|
||||||
|
assert crop(0, 75, 50, 125) == (1250, 1250)
|
||||||
|
|
||||||
# corners
|
assert crop(-25, 25, 125, 75) == (2500, 5000)
|
||||||
self.assertEqual(crop(-25, -25, 25, 25), (1875, 625))
|
assert crop(25, -25, 75, 125) == (2500, 5000)
|
||||||
self.assertEqual(crop(75, -25, 125, 25), (1875, 625))
|
|
||||||
self.assertEqual(crop(75, 75, 125, 125), (1875, 625))
|
|
||||||
self.assertEqual(crop(-25, 75, 25, 125), (1875, 625))
|
|
||||||
|
|
||||||
def test_negative_crop(self):
|
# corners
|
||||||
# Check negative crop size (@PIL171)
|
assert crop(-25, -25, 25, 25) == (1875, 625)
|
||||||
|
assert crop(75, -25, 125, 25) == (1875, 625)
|
||||||
|
assert crop(75, 75, 125, 125) == (1875, 625)
|
||||||
|
assert crop(-25, 75, 25, 125) == (1875, 625)
|
||||||
|
|
||||||
im = Image.new("L", (512, 512))
|
|
||||||
im = im.crop((400, 400, 200, 200))
|
|
||||||
|
|
||||||
self.assertEqual(im.size, (0, 0))
|
def test_negative_crop():
|
||||||
self.assertEqual(len(im.getdata()), 0)
|
# Check negative crop size (@PIL171)
|
||||||
self.assertRaises(IndexError, lambda: im.getdata()[0])
|
|
||||||
|
|
||||||
def test_crop_float(self):
|
im = Image.new("L", (512, 512))
|
||||||
# Check cropping floats are rounded to nearest integer
|
im = im.crop((400, 400, 200, 200))
|
||||||
# https://github.com/python-pillow/Pillow/issues/1744
|
|
||||||
|
|
||||||
# Arrange
|
assert im.size == (0, 0)
|
||||||
im = Image.new("RGB", (10, 10))
|
assert len(im.getdata()) == 0
|
||||||
self.assertEqual(im.size, (10, 10))
|
with pytest.raises(IndexError):
|
||||||
|
im.getdata()[0]
|
||||||
|
|
||||||
# Act
|
|
||||||
cropped = im.crop((0.9, 1.1, 4.2, 5.8))
|
|
||||||
|
|
||||||
# Assert
|
def test_crop_float():
|
||||||
self.assertEqual(cropped.size, (3, 5))
|
# Check cropping floats are rounded to nearest integer
|
||||||
|
# https://github.com/python-pillow/Pillow/issues/1744
|
||||||
|
|
||||||
def test_crop_crash(self):
|
# Arrange
|
||||||
# Image.crop crashes prepatch with an access violation
|
im = Image.new("RGB", (10, 10))
|
||||||
# apparently a use after free on windows, see
|
assert im.size == (10, 10)
|
||||||
# https://github.com/python-pillow/Pillow/issues/1077
|
|
||||||
|
|
||||||
test_img = "Tests/images/bmp/g/pal8-0.bmp"
|
# Act
|
||||||
extents = (1, 1, 10, 10)
|
cropped = im.crop((0.9, 1.1, 4.2, 5.8))
|
||||||
# works prepatch
|
|
||||||
with Image.open(test_img) as img:
|
|
||||||
img2 = img.crop(extents)
|
|
||||||
img2.load()
|
|
||||||
|
|
||||||
# fail prepatch
|
# Assert
|
||||||
with Image.open(test_img) as img:
|
assert cropped.size == (3, 5)
|
||||||
img = img.crop(extents)
|
|
||||||
img.load()
|
|
||||||
|
|
||||||
def test_crop_zero(self):
|
|
||||||
|
|
||||||
im = Image.new("RGB", (0, 0), "white")
|
def test_crop_crash():
|
||||||
|
# Image.crop crashes prepatch with an access violation
|
||||||
|
# apparently a use after free on Windows, see
|
||||||
|
# https://github.com/python-pillow/Pillow/issues/1077
|
||||||
|
|
||||||
cropped = im.crop((0, 0, 0, 0))
|
test_img = "Tests/images/bmp/g/pal8-0.bmp"
|
||||||
self.assertEqual(cropped.size, (0, 0))
|
extents = (1, 1, 10, 10)
|
||||||
|
# works prepatch
|
||||||
|
with Image.open(test_img) as img:
|
||||||
|
img2 = img.crop(extents)
|
||||||
|
img2.load()
|
||||||
|
|
||||||
cropped = im.crop((10, 10, 20, 20))
|
# fail prepatch
|
||||||
self.assertEqual(cropped.size, (10, 10))
|
with Image.open(test_img) as img:
|
||||||
self.assertEqual(cropped.getdata()[0], (0, 0, 0))
|
img = img.crop(extents)
|
||||||
|
img.load()
|
||||||
|
|
||||||
im = Image.new("RGB", (0, 0))
|
|
||||||
|
|
||||||
cropped = im.crop((10, 10, 20, 20))
|
def test_crop_zero():
|
||||||
self.assertEqual(cropped.size, (10, 10))
|
|
||||||
self.assertEqual(cropped.getdata()[2], (0, 0, 0))
|
im = Image.new("RGB", (0, 0), "white")
|
||||||
|
|
||||||
|
cropped = im.crop((0, 0, 0, 0))
|
||||||
|
assert cropped.size == (0, 0)
|
||||||
|
|
||||||
|
cropped = im.crop((10, 10, 20, 20))
|
||||||
|
assert cropped.size == (10, 10)
|
||||||
|
assert cropped.getdata()[0] == (0, 0, 0)
|
||||||
|
|
||||||
|
im = Image.new("RGB", (0, 0))
|
||||||
|
|
||||||
|
cropped = im.crop((10, 10, 20, 20))
|
||||||
|
assert cropped.size == (10, 10)
|
||||||
|
assert cropped.getdata()[2] == (0, 0, 0)
|
||||||
|
|
|
@ -1,73 +1,77 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, fromstring, tostring
|
from .helper import fromstring, tostring
|
||||||
|
|
||||||
|
|
||||||
class TestImageDraft(PillowTestCase):
|
def setup_module():
|
||||||
def setUp(self):
|
codecs = dir(Image.core)
|
||||||
codecs = dir(Image.core)
|
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
pytest.skip("jpeg support not available")
|
||||||
self.skipTest("jpeg support not available")
|
|
||||||
|
|
||||||
def draft_roundtrip(self, in_mode, in_size, req_mode, req_size):
|
|
||||||
im = Image.new(in_mode, in_size)
|
|
||||||
data = tostring(im, "JPEG")
|
|
||||||
im = fromstring(data)
|
|
||||||
mode, box = im.draft(req_mode, req_size)
|
|
||||||
scale, _ = im.decoderconfig
|
|
||||||
self.assertEqual(box[:2], (0, 0))
|
|
||||||
self.assertTrue((im.width - scale) < box[2] <= im.width)
|
|
||||||
self.assertTrue((im.height - scale) < box[3] <= im.height)
|
|
||||||
return im
|
|
||||||
|
|
||||||
def test_size(self):
|
def draft_roundtrip(in_mode, in_size, req_mode, req_size):
|
||||||
for in_size, req_size, out_size in [
|
im = Image.new(in_mode, in_size)
|
||||||
((435, 361), (2048, 2048), (435, 361)), # bigger
|
data = tostring(im, "JPEG")
|
||||||
((435, 361), (435, 361), (435, 361)), # same
|
im = fromstring(data)
|
||||||
((128, 128), (64, 64), (64, 64)),
|
mode, box = im.draft(req_mode, req_size)
|
||||||
((128, 128), (32, 32), (32, 32)),
|
scale, _ = im.decoderconfig
|
||||||
((128, 128), (16, 16), (16, 16)),
|
assert box[:2] == (0, 0)
|
||||||
# large requested width
|
assert (im.width - scale) < box[2] <= im.width
|
||||||
((435, 361), (218, 128), (435, 361)), # almost 2x
|
assert (im.height - scale) < box[3] <= im.height
|
||||||
((435, 361), (217, 128), (218, 181)), # more than 2x
|
return im
|
||||||
((435, 361), (109, 64), (218, 181)), # almost 4x
|
|
||||||
((435, 361), (108, 64), (109, 91)), # more than 4x
|
|
||||||
((435, 361), (55, 32), (109, 91)), # almost 8x
|
|
||||||
((435, 361), (54, 32), (55, 46)), # more than 8x
|
|
||||||
((435, 361), (27, 16), (55, 46)), # more than 16x
|
|
||||||
# and vice versa
|
|
||||||
((435, 361), (128, 181), (435, 361)), # almost 2x
|
|
||||||
((435, 361), (128, 180), (218, 181)), # more than 2x
|
|
||||||
((435, 361), (64, 91), (218, 181)), # almost 4x
|
|
||||||
((435, 361), (64, 90), (109, 91)), # more than 4x
|
|
||||||
((435, 361), (32, 46), (109, 91)), # almost 8x
|
|
||||||
((435, 361), (32, 45), (55, 46)), # more than 8x
|
|
||||||
((435, 361), (16, 22), (55, 46)), # more than 16x
|
|
||||||
]:
|
|
||||||
im = self.draft_roundtrip("L", in_size, None, req_size)
|
|
||||||
im.load()
|
|
||||||
self.assertEqual(im.size, out_size)
|
|
||||||
|
|
||||||
def test_mode(self):
|
|
||||||
for in_mode, req_mode, out_mode in [
|
|
||||||
("RGB", "1", "RGB"),
|
|
||||||
("RGB", "L", "L"),
|
|
||||||
("RGB", "RGB", "RGB"),
|
|
||||||
("RGB", "YCbCr", "YCbCr"),
|
|
||||||
("L", "1", "L"),
|
|
||||||
("L", "L", "L"),
|
|
||||||
("L", "RGB", "L"),
|
|
||||||
("L", "YCbCr", "L"),
|
|
||||||
("CMYK", "1", "CMYK"),
|
|
||||||
("CMYK", "L", "CMYK"),
|
|
||||||
("CMYK", "RGB", "CMYK"),
|
|
||||||
("CMYK", "YCbCr", "CMYK"),
|
|
||||||
]:
|
|
||||||
im = self.draft_roundtrip(in_mode, (64, 64), req_mode, None)
|
|
||||||
im.load()
|
|
||||||
self.assertEqual(im.mode, out_mode)
|
|
||||||
|
|
||||||
def test_several_drafts(self):
|
def test_size():
|
||||||
im = self.draft_roundtrip("L", (128, 128), None, (64, 64))
|
for in_size, req_size, out_size in [
|
||||||
im.draft(None, (64, 64))
|
((435, 361), (2048, 2048), (435, 361)), # bigger
|
||||||
|
((435, 361), (435, 361), (435, 361)), # same
|
||||||
|
((128, 128), (64, 64), (64, 64)),
|
||||||
|
((128, 128), (32, 32), (32, 32)),
|
||||||
|
((128, 128), (16, 16), (16, 16)),
|
||||||
|
# large requested width
|
||||||
|
((435, 361), (218, 128), (435, 361)), # almost 2x
|
||||||
|
((435, 361), (217, 128), (218, 181)), # more than 2x
|
||||||
|
((435, 361), (109, 64), (218, 181)), # almost 4x
|
||||||
|
((435, 361), (108, 64), (109, 91)), # more than 4x
|
||||||
|
((435, 361), (55, 32), (109, 91)), # almost 8x
|
||||||
|
((435, 361), (54, 32), (55, 46)), # more than 8x
|
||||||
|
((435, 361), (27, 16), (55, 46)), # more than 16x
|
||||||
|
# and vice versa
|
||||||
|
((435, 361), (128, 181), (435, 361)), # almost 2x
|
||||||
|
((435, 361), (128, 180), (218, 181)), # more than 2x
|
||||||
|
((435, 361), (64, 91), (218, 181)), # almost 4x
|
||||||
|
((435, 361), (64, 90), (109, 91)), # more than 4x
|
||||||
|
((435, 361), (32, 46), (109, 91)), # almost 8x
|
||||||
|
((435, 361), (32, 45), (55, 46)), # more than 8x
|
||||||
|
((435, 361), (16, 22), (55, 46)), # more than 16x
|
||||||
|
]:
|
||||||
|
im = draft_roundtrip("L", in_size, None, req_size)
|
||||||
im.load()
|
im.load()
|
||||||
|
assert im.size == out_size
|
||||||
|
|
||||||
|
|
||||||
|
def test_mode():
|
||||||
|
for in_mode, req_mode, out_mode in [
|
||||||
|
("RGB", "1", "RGB"),
|
||||||
|
("RGB", "L", "L"),
|
||||||
|
("RGB", "RGB", "RGB"),
|
||||||
|
("RGB", "YCbCr", "YCbCr"),
|
||||||
|
("L", "1", "L"),
|
||||||
|
("L", "L", "L"),
|
||||||
|
("L", "RGB", "L"),
|
||||||
|
("L", "YCbCr", "L"),
|
||||||
|
("CMYK", "1", "CMYK"),
|
||||||
|
("CMYK", "L", "CMYK"),
|
||||||
|
("CMYK", "RGB", "CMYK"),
|
||||||
|
("CMYK", "YCbCr", "CMYK"),
|
||||||
|
]:
|
||||||
|
im = draft_roundtrip(in_mode, (64, 64), req_mode, None)
|
||||||
|
im.load()
|
||||||
|
assert im.mode == out_mode
|
||||||
|
|
||||||
|
|
||||||
|
def test_several_drafts():
|
||||||
|
im = draft_roundtrip("L", (128, 128), None, (64, 64))
|
||||||
|
im.draft(None, (64, 64))
|
||||||
|
im.load()
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
from .helper import PillowTestCase, hopper
|
from .helper import hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageEntropy(PillowTestCase):
|
def test_entropy():
|
||||||
def test_entropy(self):
|
def entropy(mode):
|
||||||
def entropy(mode):
|
return hopper(mode).entropy()
|
||||||
return hopper(mode).entropy()
|
|
||||||
|
|
||||||
self.assertAlmostEqual(entropy("1"), 0.9138803254693582)
|
assert round(abs(entropy("1") - 0.9138803254693582), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("L"), 7.063008716585465)
|
assert round(abs(entropy("L") - 7.063008716585465), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("I"), 7.063008716585465)
|
assert round(abs(entropy("I") - 7.063008716585465), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("F"), 7.063008716585465)
|
assert round(abs(entropy("F") - 7.063008716585465), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("P"), 5.0530452472519745)
|
assert round(abs(entropy("P") - 5.0530452472519745), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("RGB"), 8.821286587714319)
|
assert round(abs(entropy("RGB") - 8.821286587714319), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("RGBA"), 7.42724306524488)
|
assert round(abs(entropy("RGBA") - 7.42724306524488), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("CMYK"), 7.4272430652448795)
|
assert round(abs(entropy("CMYK") - 7.4272430652448795), 7) == 0
|
||||||
self.assertAlmostEqual(entropy("YCbCr"), 7.698360534903628)
|
assert round(abs(entropy("YCbCr") - 7.698360534903628), 7) == 0
|
||||||
|
|
|
@ -1,143 +1,155 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, ImageFilter
|
from PIL import Image, ImageFilter
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageFilter(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
def apply_filter(filter_to_apply):
|
||||||
def filter(filter):
|
for mode in ["L", "RGB", "CMYK"]:
|
||||||
for mode in ["L", "RGB", "CMYK"]:
|
im = hopper(mode)
|
||||||
im = hopper(mode)
|
out = im.filter(filter_to_apply)
|
||||||
out = im.filter(filter)
|
assert out.mode == im.mode
|
||||||
self.assertEqual(out.mode, im.mode)
|
assert out.size == im.size
|
||||||
self.assertEqual(out.size, im.size)
|
|
||||||
|
|
||||||
filter(ImageFilter.BLUR)
|
apply_filter(ImageFilter.BLUR)
|
||||||
filter(ImageFilter.CONTOUR)
|
apply_filter(ImageFilter.CONTOUR)
|
||||||
filter(ImageFilter.DETAIL)
|
apply_filter(ImageFilter.DETAIL)
|
||||||
filter(ImageFilter.EDGE_ENHANCE)
|
apply_filter(ImageFilter.EDGE_ENHANCE)
|
||||||
filter(ImageFilter.EDGE_ENHANCE_MORE)
|
apply_filter(ImageFilter.EDGE_ENHANCE_MORE)
|
||||||
filter(ImageFilter.EMBOSS)
|
apply_filter(ImageFilter.EMBOSS)
|
||||||
filter(ImageFilter.FIND_EDGES)
|
apply_filter(ImageFilter.FIND_EDGES)
|
||||||
filter(ImageFilter.SMOOTH)
|
apply_filter(ImageFilter.SMOOTH)
|
||||||
filter(ImageFilter.SMOOTH_MORE)
|
apply_filter(ImageFilter.SMOOTH_MORE)
|
||||||
filter(ImageFilter.SHARPEN)
|
apply_filter(ImageFilter.SHARPEN)
|
||||||
filter(ImageFilter.MaxFilter)
|
apply_filter(ImageFilter.MaxFilter)
|
||||||
filter(ImageFilter.MedianFilter)
|
apply_filter(ImageFilter.MedianFilter)
|
||||||
filter(ImageFilter.MinFilter)
|
apply_filter(ImageFilter.MinFilter)
|
||||||
filter(ImageFilter.ModeFilter)
|
apply_filter(ImageFilter.ModeFilter)
|
||||||
filter(ImageFilter.GaussianBlur)
|
apply_filter(ImageFilter.GaussianBlur)
|
||||||
filter(ImageFilter.GaussianBlur(5))
|
apply_filter(ImageFilter.GaussianBlur(5))
|
||||||
filter(ImageFilter.BoxBlur(5))
|
apply_filter(ImageFilter.BoxBlur(5))
|
||||||
filter(ImageFilter.UnsharpMask)
|
apply_filter(ImageFilter.UnsharpMask)
|
||||||
filter(ImageFilter.UnsharpMask(10))
|
apply_filter(ImageFilter.UnsharpMask(10))
|
||||||
|
|
||||||
self.assertRaises(TypeError, filter, "hello")
|
with pytest.raises(TypeError):
|
||||||
|
apply_filter("hello")
|
||||||
|
|
||||||
def test_crash(self):
|
|
||||||
|
|
||||||
# crashes on small images
|
def test_crash():
|
||||||
im = Image.new("RGB", (1, 1))
|
|
||||||
im.filter(ImageFilter.SMOOTH)
|
|
||||||
|
|
||||||
im = Image.new("RGB", (2, 2))
|
# crashes on small images
|
||||||
im.filter(ImageFilter.SMOOTH)
|
im = Image.new("RGB", (1, 1))
|
||||||
|
im.filter(ImageFilter.SMOOTH)
|
||||||
|
|
||||||
im = Image.new("RGB", (3, 3))
|
im = Image.new("RGB", (2, 2))
|
||||||
im.filter(ImageFilter.SMOOTH)
|
im.filter(ImageFilter.SMOOTH)
|
||||||
|
|
||||||
def test_modefilter(self):
|
im = Image.new("RGB", (3, 3))
|
||||||
def modefilter(mode):
|
im.filter(ImageFilter.SMOOTH)
|
||||||
im = Image.new(mode, (3, 3), None)
|
|
||||||
im.putdata(list(range(9)))
|
|
||||||
# image is:
|
|
||||||
# 0 1 2
|
|
||||||
# 3 4 5
|
|
||||||
# 6 7 8
|
|
||||||
mod = im.filter(ImageFilter.ModeFilter).getpixel((1, 1))
|
|
||||||
im.putdata([0, 0, 1, 2, 5, 1, 5, 2, 0]) # mode=0
|
|
||||||
mod2 = im.filter(ImageFilter.ModeFilter).getpixel((1, 1))
|
|
||||||
return mod, mod2
|
|
||||||
|
|
||||||
self.assertEqual(modefilter("1"), (4, 0))
|
|
||||||
self.assertEqual(modefilter("L"), (4, 0))
|
|
||||||
self.assertEqual(modefilter("P"), (4, 0))
|
|
||||||
self.assertEqual(modefilter("RGB"), ((4, 0, 0), (0, 0, 0)))
|
|
||||||
|
|
||||||
def test_rankfilter(self):
|
def test_modefilter():
|
||||||
def rankfilter(mode):
|
def modefilter(mode):
|
||||||
im = Image.new(mode, (3, 3), None)
|
im = Image.new(mode, (3, 3), None)
|
||||||
im.putdata(list(range(9)))
|
im.putdata(list(range(9)))
|
||||||
# image is:
|
# image is:
|
||||||
# 0 1 2
|
# 0 1 2
|
||||||
# 3 4 5
|
# 3 4 5
|
||||||
# 6 7 8
|
# 6 7 8
|
||||||
minimum = im.filter(ImageFilter.MinFilter).getpixel((1, 1))
|
mod = im.filter(ImageFilter.ModeFilter).getpixel((1, 1))
|
||||||
med = im.filter(ImageFilter.MedianFilter).getpixel((1, 1))
|
im.putdata([0, 0, 1, 2, 5, 1, 5, 2, 0]) # mode=0
|
||||||
maximum = im.filter(ImageFilter.MaxFilter).getpixel((1, 1))
|
mod2 = im.filter(ImageFilter.ModeFilter).getpixel((1, 1))
|
||||||
return minimum, med, maximum
|
return mod, mod2
|
||||||
|
|
||||||
self.assertEqual(rankfilter("1"), (0, 4, 8))
|
assert modefilter("1") == (4, 0)
|
||||||
self.assertEqual(rankfilter("L"), (0, 4, 8))
|
assert modefilter("L") == (4, 0)
|
||||||
self.assertRaises(ValueError, rankfilter, "P")
|
assert modefilter("P") == (4, 0)
|
||||||
self.assertEqual(rankfilter("RGB"), ((0, 0, 0), (4, 0, 0), (8, 0, 0)))
|
assert modefilter("RGB") == ((4, 0, 0), (0, 0, 0))
|
||||||
self.assertEqual(rankfilter("I"), (0, 4, 8))
|
|
||||||
self.assertEqual(rankfilter("F"), (0.0, 4.0, 8.0))
|
|
||||||
|
|
||||||
def test_rankfilter_properties(self):
|
|
||||||
rankfilter = ImageFilter.RankFilter(1, 2)
|
|
||||||
|
|
||||||
self.assertEqual(rankfilter.size, 1)
|
def test_rankfilter():
|
||||||
self.assertEqual(rankfilter.rank, 2)
|
def rankfilter(mode):
|
||||||
|
im = Image.new(mode, (3, 3), None)
|
||||||
|
im.putdata(list(range(9)))
|
||||||
|
# image is:
|
||||||
|
# 0 1 2
|
||||||
|
# 3 4 5
|
||||||
|
# 6 7 8
|
||||||
|
minimum = im.filter(ImageFilter.MinFilter).getpixel((1, 1))
|
||||||
|
med = im.filter(ImageFilter.MedianFilter).getpixel((1, 1))
|
||||||
|
maximum = im.filter(ImageFilter.MaxFilter).getpixel((1, 1))
|
||||||
|
return minimum, med, maximum
|
||||||
|
|
||||||
def test_builtinfilter_p(self):
|
assert rankfilter("1") == (0, 4, 8)
|
||||||
builtinFilter = ImageFilter.BuiltinFilter()
|
assert rankfilter("L") == (0, 4, 8)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
rankfilter("P")
|
||||||
|
assert rankfilter("RGB") == ((0, 0, 0), (4, 0, 0), (8, 0, 0))
|
||||||
|
assert rankfilter("I") == (0, 4, 8)
|
||||||
|
assert rankfilter("F") == (0.0, 4.0, 8.0)
|
||||||
|
|
||||||
self.assertRaises(ValueError, builtinFilter.filter, hopper("P"))
|
|
||||||
|
|
||||||
def test_kernel_not_enough_coefficients(self):
|
def test_rankfilter_properties():
|
||||||
self.assertRaises(ValueError, lambda: ImageFilter.Kernel((3, 3), (0, 0)))
|
rankfilter = ImageFilter.RankFilter(1, 2)
|
||||||
|
|
||||||
def test_consistency_3x3(self):
|
assert rankfilter.size == 1
|
||||||
with Image.open("Tests/images/hopper.bmp") as source:
|
assert rankfilter.rank == 2
|
||||||
with Image.open("Tests/images/hopper_emboss.bmp") as reference:
|
|
||||||
kernel = ImageFilter.Kernel( # noqa: E127
|
|
||||||
(3, 3),
|
def test_builtinfilter_p():
|
||||||
# fmt: off
|
builtinFilter = ImageFilter.BuiltinFilter()
|
||||||
(-1, -1, 0,
|
|
||||||
-1, 0, 1,
|
with pytest.raises(ValueError):
|
||||||
0, 1, 1),
|
builtinFilter.filter(hopper("P"))
|
||||||
# fmt: on
|
|
||||||
0.3,
|
|
||||||
|
def test_kernel_not_enough_coefficients():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
ImageFilter.Kernel((3, 3), (0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_consistency_3x3():
|
||||||
|
with Image.open("Tests/images/hopper.bmp") as source:
|
||||||
|
with Image.open("Tests/images/hopper_emboss.bmp") as reference:
|
||||||
|
kernel = ImageFilter.Kernel( # noqa: E127
|
||||||
|
(3, 3),
|
||||||
|
# fmt: off
|
||||||
|
(-1, -1, 0,
|
||||||
|
-1, 0, 1,
|
||||||
|
0, 1, 1),
|
||||||
|
# fmt: on
|
||||||
|
0.3,
|
||||||
|
)
|
||||||
|
source = source.split() * 2
|
||||||
|
reference = reference.split() * 2
|
||||||
|
|
||||||
|
for mode in ["L", "LA", "RGB", "CMYK"]:
|
||||||
|
assert_image_equal(
|
||||||
|
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
||||||
|
Image.merge(mode, reference[: len(mode)]),
|
||||||
)
|
)
|
||||||
source = source.split() * 2
|
|
||||||
reference = reference.split() * 2
|
|
||||||
|
|
||||||
for mode in ["L", "LA", "RGB", "CMYK"]:
|
|
||||||
assert_image_equal(
|
|
||||||
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
|
||||||
Image.merge(mode, reference[: len(mode)]),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_consistency_5x5(self):
|
def test_consistency_5x5():
|
||||||
with Image.open("Tests/images/hopper.bmp") as source:
|
with Image.open("Tests/images/hopper.bmp") as source:
|
||||||
with Image.open("Tests/images/hopper_emboss_more.bmp") as reference:
|
with Image.open("Tests/images/hopper_emboss_more.bmp") as reference:
|
||||||
kernel = ImageFilter.Kernel( # noqa: E127
|
kernel = ImageFilter.Kernel( # noqa: E127
|
||||||
(5, 5),
|
(5, 5),
|
||||||
# fmt: off
|
# fmt: off
|
||||||
(-1, -1, -1, -1, 0,
|
(-1, -1, -1, -1, 0,
|
||||||
-1, -1, -1, 0, 1,
|
-1, -1, -1, 0, 1,
|
||||||
-1, -1, 0, 1, 1,
|
-1, -1, 0, 1, 1,
|
||||||
-1, 0, 1, 1, 1,
|
-1, 0, 1, 1, 1,
|
||||||
0, 1, 1, 1, 1),
|
0, 1, 1, 1, 1),
|
||||||
# fmt: on
|
# fmt: on
|
||||||
0.3,
|
0.3,
|
||||||
|
)
|
||||||
|
source = source.split() * 2
|
||||||
|
reference = reference.split() * 2
|
||||||
|
|
||||||
|
for mode in ["L", "LA", "RGB", "CMYK"]:
|
||||||
|
assert_image_equal(
|
||||||
|
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
||||||
|
Image.merge(mode, reference[: len(mode)]),
|
||||||
)
|
)
|
||||||
source = source.split() * 2
|
|
||||||
reference = reference.split() * 2
|
|
||||||
|
|
||||||
for mode in ["L", "LA", "RGB", "CMYK"]:
|
|
||||||
assert_image_equal(
|
|
||||||
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
|
||||||
Image.merge(mode, reference[: len(mode)]),
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageFromBytes(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
im1 = hopper()
|
||||||
im1 = hopper()
|
im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes())
|
||||||
im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes())
|
|
||||||
|
|
||||||
assert_image_equal(im1, im2)
|
assert_image_equal(im1, im2)
|
||||||
|
|
||||||
def test_not_implemented(self):
|
|
||||||
self.assertRaises(NotImplementedError, Image.fromstring)
|
def test_not_implemented():
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
Image.fromstring()
|
||||||
|
|
|
@ -1,39 +1,48 @@
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
import pytest
|
||||||
|
|
||||||
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImagePoint(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
im = hopper()
|
||||||
im = hopper()
|
|
||||||
|
|
||||||
self.assertRaises(ValueError, im.point, list(range(256)))
|
with pytest.raises(ValueError):
|
||||||
im.point(list(range(256)) * 3)
|
im.point(list(range(256)))
|
||||||
im.point(lambda x: x)
|
im.point(list(range(256)) * 3)
|
||||||
|
im.point(lambda x: x)
|
||||||
|
|
||||||
im = im.convert("I")
|
im = im.convert("I")
|
||||||
self.assertRaises(ValueError, im.point, list(range(256)))
|
with pytest.raises(ValueError):
|
||||||
im.point(lambda x: x * 1)
|
im.point(list(range(256)))
|
||||||
im.point(lambda x: x + 1)
|
im.point(lambda x: x * 1)
|
||||||
im.point(lambda x: x * 1 + 1)
|
im.point(lambda x: x + 1)
|
||||||
self.assertRaises(TypeError, im.point, lambda x: x - 1)
|
im.point(lambda x: x * 1 + 1)
|
||||||
self.assertRaises(TypeError, im.point, lambda x: x / 1)
|
with pytest.raises(TypeError):
|
||||||
|
im.point(lambda x: x - 1)
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
im.point(lambda x: x / 1)
|
||||||
|
|
||||||
def test_16bit_lut(self):
|
|
||||||
""" Tests for 16 bit -> 8 bit lut for converting I->L images
|
|
||||||
see https://github.com/python-pillow/Pillow/issues/440
|
|
||||||
"""
|
|
||||||
im = hopper("I")
|
|
||||||
im.point(list(range(256)) * 256, "L")
|
|
||||||
|
|
||||||
def test_f_lut(self):
|
def test_16bit_lut():
|
||||||
""" Tests for floating point lut of 8bit gray image """
|
""" Tests for 16 bit -> 8 bit lut for converting I->L images
|
||||||
im = hopper("L")
|
see https://github.com/python-pillow/Pillow/issues/440
|
||||||
lut = [0.5 * float(x) for x in range(256)]
|
"""
|
||||||
|
im = hopper("I")
|
||||||
|
im.point(list(range(256)) * 256, "L")
|
||||||
|
|
||||||
out = im.point(lut, "F")
|
|
||||||
|
|
||||||
int_lut = [x // 2 for x in range(256)]
|
def test_f_lut():
|
||||||
assert_image_equal(out.convert("L"), im.point(int_lut, "L"))
|
""" Tests for floating point lut of 8bit gray image """
|
||||||
|
im = hopper("L")
|
||||||
|
lut = [0.5 * float(x) for x in range(256)]
|
||||||
|
|
||||||
def test_f_mode(self):
|
out = im.point(lut, "F")
|
||||||
im = hopper("F")
|
|
||||||
self.assertRaises(ValueError, im.point, None)
|
int_lut = [x // 2 for x in range(256)]
|
||||||
|
assert_image_equal(out.convert("L"), im.point(int_lut, "L"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_f_mode():
|
||||||
|
im = hopper("F")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
im.point(None)
|
||||||
|
|
|
@ -3,83 +3,87 @@ from array import array
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImagePutData(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
im1 = hopper()
|
||||||
|
|
||||||
im1 = hopper()
|
data = list(im1.getdata())
|
||||||
|
|
||||||
data = list(im1.getdata())
|
im2 = Image.new(im1.mode, im1.size, 0)
|
||||||
|
im2.putdata(data)
|
||||||
|
|
||||||
im2 = Image.new(im1.mode, im1.size, 0)
|
assert_image_equal(im1, im2)
|
||||||
im2.putdata(data)
|
|
||||||
|
|
||||||
assert_image_equal(im1, im2)
|
# readonly
|
||||||
|
im2 = Image.new(im1.mode, im2.size, 0)
|
||||||
|
im2.readonly = 1
|
||||||
|
im2.putdata(data)
|
||||||
|
|
||||||
# readonly
|
assert not im2.readonly
|
||||||
im2 = Image.new(im1.mode, im2.size, 0)
|
assert_image_equal(im1, im2)
|
||||||
im2.readonly = 1
|
|
||||||
im2.putdata(data)
|
|
||||||
|
|
||||||
self.assertFalse(im2.readonly)
|
|
||||||
assert_image_equal(im1, im2)
|
|
||||||
|
|
||||||
def test_long_integers(self):
|
def test_long_integers():
|
||||||
# see bug-200802-systemerror
|
# see bug-200802-systemerror
|
||||||
def put(value):
|
def put(value):
|
||||||
im = Image.new("RGBA", (1, 1))
|
im = Image.new("RGBA", (1, 1))
|
||||||
im.putdata([value])
|
im.putdata([value])
|
||||||
return im.getpixel((0, 0))
|
return im.getpixel((0, 0))
|
||||||
|
|
||||||
self.assertEqual(put(0xFFFFFFFF), (255, 255, 255, 255))
|
assert put(0xFFFFFFFF) == (255, 255, 255, 255)
|
||||||
self.assertEqual(put(0xFFFFFFFF), (255, 255, 255, 255))
|
assert put(0xFFFFFFFF) == (255, 255, 255, 255)
|
||||||
self.assertEqual(put(-1), (255, 255, 255, 255))
|
assert put(-1) == (255, 255, 255, 255)
|
||||||
self.assertEqual(put(-1), (255, 255, 255, 255))
|
assert put(-1) == (255, 255, 255, 255)
|
||||||
if sys.maxsize > 2 ** 32:
|
if sys.maxsize > 2 ** 32:
|
||||||
self.assertEqual(put(sys.maxsize), (255, 255, 255, 255))
|
assert put(sys.maxsize) == (255, 255, 255, 255)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(put(sys.maxsize), (255, 255, 255, 127))
|
assert put(sys.maxsize) == (255, 255, 255, 127)
|
||||||
|
|
||||||
def test_pypy_performance(self):
|
|
||||||
im = Image.new("L", (256, 256))
|
|
||||||
im.putdata(list(range(256)) * 256)
|
|
||||||
|
|
||||||
def test_mode_i(self):
|
def test_pypy_performance():
|
||||||
src = hopper("L")
|
im = Image.new("L", (256, 256))
|
||||||
data = list(src.getdata())
|
im.putdata(list(range(256)) * 256)
|
||||||
im = Image.new("I", src.size, 0)
|
|
||||||
im.putdata(data, 2, 256)
|
|
||||||
|
|
||||||
target = [2 * elt + 256 for elt in data]
|
|
||||||
self.assertEqual(list(im.getdata()), target)
|
|
||||||
|
|
||||||
def test_mode_F(self):
|
def test_mode_i():
|
||||||
src = hopper("L")
|
src = hopper("L")
|
||||||
data = list(src.getdata())
|
data = list(src.getdata())
|
||||||
im = Image.new("F", src.size, 0)
|
im = Image.new("I", src.size, 0)
|
||||||
im.putdata(data, 2.0, 256.0)
|
im.putdata(data, 2, 256)
|
||||||
|
|
||||||
target = [2.0 * float(elt) + 256.0 for elt in data]
|
target = [2 * elt + 256 for elt in data]
|
||||||
self.assertEqual(list(im.getdata()), target)
|
assert list(im.getdata()) == target
|
||||||
|
|
||||||
def test_array_B(self):
|
|
||||||
# shouldn't segfault
|
|
||||||
# see https://github.com/python-pillow/Pillow/issues/1008
|
|
||||||
|
|
||||||
arr = array("B", [0]) * 15000
|
def test_mode_F():
|
||||||
im = Image.new("L", (150, 100))
|
src = hopper("L")
|
||||||
im.putdata(arr)
|
data = list(src.getdata())
|
||||||
|
im = Image.new("F", src.size, 0)
|
||||||
|
im.putdata(data, 2.0, 256.0)
|
||||||
|
|
||||||
self.assertEqual(len(im.getdata()), len(arr))
|
target = [2.0 * float(elt) + 256.0 for elt in data]
|
||||||
|
assert list(im.getdata()) == target
|
||||||
|
|
||||||
def test_array_F(self):
|
|
||||||
# shouldn't segfault
|
|
||||||
# see https://github.com/python-pillow/Pillow/issues/1008
|
|
||||||
|
|
||||||
im = Image.new("F", (150, 100))
|
def test_array_B():
|
||||||
arr = array("f", [0.0]) * 15000
|
# shouldn't segfault
|
||||||
im.putdata(arr)
|
# see https://github.com/python-pillow/Pillow/issues/1008
|
||||||
|
|
||||||
self.assertEqual(len(im.getdata()), len(arr))
|
arr = array("B", [0]) * 15000
|
||||||
|
im = Image.new("L", (150, 100))
|
||||||
|
im.putdata(arr)
|
||||||
|
|
||||||
|
assert len(im.getdata()) == len(arr)
|
||||||
|
|
||||||
|
|
||||||
|
def test_array_F():
|
||||||
|
# shouldn't segfault
|
||||||
|
# see https://github.com/python-pillow/Pillow/issues/1008
|
||||||
|
|
||||||
|
im = Image.new("F", (150, 100))
|
||||||
|
arr = array("f", [0.0]) * 15000
|
||||||
|
im.putdata(arr)
|
||||||
|
|
||||||
|
assert len(im.getdata()) == len(arr)
|
||||||
|
|
|
@ -1,67 +1,74 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image, assert_image_similar, hopper
|
from .helper import assert_image, assert_image_similar, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageQuantize(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
image = hopper()
|
||||||
image = hopper()
|
converted = image.quantize()
|
||||||
converted = image.quantize()
|
assert_image(converted, "P", converted.size)
|
||||||
assert_image(converted, "P", converted.size)
|
assert_image_similar(converted.convert("RGB"), image, 10)
|
||||||
assert_image_similar(converted.convert("RGB"), image, 10)
|
|
||||||
|
|
||||||
image = hopper()
|
image = hopper()
|
||||||
converted = image.quantize(palette=hopper("P"))
|
converted = image.quantize(palette=hopper("P"))
|
||||||
assert_image(converted, "P", converted.size)
|
assert_image(converted, "P", converted.size)
|
||||||
assert_image_similar(converted.convert("RGB"), image, 60)
|
assert_image_similar(converted.convert("RGB"), image, 60)
|
||||||
|
|
||||||
def test_libimagequant_quantize(self):
|
|
||||||
image = hopper()
|
|
||||||
try:
|
|
||||||
converted = image.quantize(100, Image.LIBIMAGEQUANT)
|
|
||||||
except ValueError as ex:
|
|
||||||
if "dependency" in str(ex).lower():
|
|
||||||
self.skipTest("libimagequant support not available")
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
assert_image(converted, "P", converted.size)
|
|
||||||
assert_image_similar(converted.convert("RGB"), image, 15)
|
|
||||||
self.assertEqual(len(converted.getcolors()), 100)
|
|
||||||
|
|
||||||
def test_octree_quantize(self):
|
def test_libimagequant_quantize():
|
||||||
image = hopper()
|
image = hopper()
|
||||||
converted = image.quantize(100, Image.FASTOCTREE)
|
try:
|
||||||
assert_image(converted, "P", converted.size)
|
converted = image.quantize(100, Image.LIBIMAGEQUANT)
|
||||||
assert_image_similar(converted.convert("RGB"), image, 20)
|
except ValueError as ex:
|
||||||
self.assertEqual(len(converted.getcolors()), 100)
|
if "dependency" in str(ex).lower():
|
||||||
|
pytest.skip("libimagequant support not available")
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
assert_image(converted, "P", converted.size)
|
||||||
|
assert_image_similar(converted.convert("RGB"), image, 15)
|
||||||
|
assert len(converted.getcolors()) == 100
|
||||||
|
|
||||||
def test_rgba_quantize(self):
|
|
||||||
image = hopper("RGBA")
|
|
||||||
self.assertRaises(ValueError, image.quantize, method=0)
|
|
||||||
|
|
||||||
self.assertEqual(image.quantize().convert().mode, "RGBA")
|
def test_octree_quantize():
|
||||||
|
image = hopper()
|
||||||
|
converted = image.quantize(100, Image.FASTOCTREE)
|
||||||
|
assert_image(converted, "P", converted.size)
|
||||||
|
assert_image_similar(converted.convert("RGB"), image, 20)
|
||||||
|
assert len(converted.getcolors()) == 100
|
||||||
|
|
||||||
def test_quantize(self):
|
|
||||||
with Image.open("Tests/images/caption_6_33_22.png") as image:
|
|
||||||
image = image.convert("RGB")
|
|
||||||
converted = image.quantize()
|
|
||||||
assert_image(converted, "P", converted.size)
|
|
||||||
assert_image_similar(converted.convert("RGB"), image, 1)
|
|
||||||
|
|
||||||
def test_quantize_no_dither(self):
|
def test_rgba_quantize():
|
||||||
image = hopper()
|
image = hopper("RGBA")
|
||||||
with Image.open("Tests/images/caption_6_33_22.png") as palette:
|
with pytest.raises(ValueError):
|
||||||
palette = palette.convert("P")
|
image.quantize(method=0)
|
||||||
|
|
||||||
converted = image.quantize(dither=0, palette=palette)
|
assert image.quantize().convert().mode == "RGBA"
|
||||||
assert_image(converted, "P", converted.size)
|
|
||||||
|
|
||||||
def test_quantize_dither_diff(self):
|
|
||||||
image = hopper()
|
|
||||||
with Image.open("Tests/images/caption_6_33_22.png") as palette:
|
|
||||||
palette = palette.convert("P")
|
|
||||||
|
|
||||||
dither = image.quantize(dither=1, palette=palette)
|
def test_quantize():
|
||||||
nodither = image.quantize(dither=0, palette=palette)
|
with Image.open("Tests/images/caption_6_33_22.png") as image:
|
||||||
|
image = image.convert("RGB")
|
||||||
|
converted = image.quantize()
|
||||||
|
assert_image(converted, "P", converted.size)
|
||||||
|
assert_image_similar(converted.convert("RGB"), image, 1)
|
||||||
|
|
||||||
self.assertNotEqual(dither.tobytes(), nodither.tobytes())
|
|
||||||
|
def test_quantize_no_dither():
|
||||||
|
image = hopper()
|
||||||
|
with Image.open("Tests/images/caption_6_33_22.png") as palette:
|
||||||
|
palette = palette.convert("P")
|
||||||
|
|
||||||
|
converted = image.quantize(dither=0, palette=palette)
|
||||||
|
assert_image(converted, "P", converted.size)
|
||||||
|
|
||||||
|
|
||||||
|
def test_quantize_dither_diff():
|
||||||
|
image = hopper()
|
||||||
|
with Image.open("Tests/images/caption_6_33_22.png") as palette:
|
||||||
|
palette = palette.convert("P")
|
||||||
|
|
||||||
|
dither = image.quantize(dither=1, palette=palette)
|
||||||
|
nodither = image.quantize(dither=0, palette=palette)
|
||||||
|
|
||||||
|
assert dither.tobytes() != nodither.tobytes()
|
||||||
|
|
|
@ -1,127 +1,140 @@
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class TestImageRotate(PillowTestCase):
|
def rotate(im, mode, angle, center=None, translate=None):
|
||||||
def rotate(self, im, mode, angle, center=None, translate=None):
|
out = im.rotate(angle, center=center, translate=translate)
|
||||||
out = im.rotate(angle, center=center, translate=translate)
|
assert out.mode == mode
|
||||||
self.assertEqual(out.mode, mode)
|
assert out.size == im.size # default rotate clips output
|
||||||
self.assertEqual(out.size, im.size) # default rotate clips output
|
out = im.rotate(angle, center=center, translate=translate, expand=1)
|
||||||
out = im.rotate(angle, center=center, translate=translate, expand=1)
|
assert out.mode == mode
|
||||||
self.assertEqual(out.mode, mode)
|
if angle % 180 == 0:
|
||||||
if angle % 180 == 0:
|
assert out.size == im.size
|
||||||
self.assertEqual(out.size, im.size)
|
elif im.size == (0, 0):
|
||||||
elif im.size == (0, 0):
|
assert out.size == im.size
|
||||||
self.assertEqual(out.size, im.size)
|
else:
|
||||||
else:
|
assert out.size != im.size
|
||||||
self.assertNotEqual(out.size, im.size)
|
|
||||||
|
|
||||||
def test_mode(self):
|
|
||||||
for mode in ("1", "P", "L", "RGB", "I", "F"):
|
|
||||||
im = hopper(mode)
|
|
||||||
self.rotate(im, mode, 45)
|
|
||||||
|
|
||||||
def test_angle(self):
|
def test_mode():
|
||||||
for angle in (0, 90, 180, 270):
|
for mode in ("1", "P", "L", "RGB", "I", "F"):
|
||||||
with Image.open("Tests/images/test-card.png") as im:
|
im = hopper(mode)
|
||||||
self.rotate(im, im.mode, angle)
|
rotate(im, mode, 45)
|
||||||
|
|
||||||
def test_zero(self):
|
|
||||||
for angle in (0, 45, 90, 180, 270):
|
|
||||||
im = Image.new("RGB", (0, 0))
|
|
||||||
self.rotate(im, im.mode, angle)
|
|
||||||
|
|
||||||
def test_resample(self):
|
def test_angle():
|
||||||
# Target image creation, inspected by eye.
|
for angle in (0, 90, 180, 270):
|
||||||
# >>> im = Image.open('Tests/images/hopper.ppm')
|
with Image.open("Tests/images/test-card.png") as im:
|
||||||
# >>> im = im.rotate(45, resample=Image.BICUBIC, expand=True)
|
rotate(im, im.mode, angle)
|
||||||
# >>> im.save('Tests/images/hopper_45.png')
|
|
||||||
|
|
||||||
with Image.open("Tests/images/hopper_45.png") as target:
|
|
||||||
for (resample, epsilon) in (
|
|
||||||
(Image.NEAREST, 10),
|
|
||||||
(Image.BILINEAR, 5),
|
|
||||||
(Image.BICUBIC, 0),
|
|
||||||
):
|
|
||||||
im = hopper()
|
|
||||||
im = im.rotate(45, resample=resample, expand=True)
|
|
||||||
assert_image_similar(im, target, epsilon)
|
|
||||||
|
|
||||||
def test_center_0(self):
|
def test_zero():
|
||||||
im = hopper()
|
for angle in (0, 45, 90, 180, 270):
|
||||||
im = im.rotate(45, center=(0, 0), resample=Image.BICUBIC)
|
im = Image.new("RGB", (0, 0))
|
||||||
|
rotate(im, im.mode, angle)
|
||||||
|
|
||||||
with Image.open("Tests/images/hopper_45.png") as target:
|
|
||||||
target_origin = target.size[1] / 2
|
|
||||||
target = target.crop((0, target_origin, 128, target_origin + 128))
|
|
||||||
|
|
||||||
assert_image_similar(im, target, 15)
|
def test_resample():
|
||||||
|
# Target image creation, inspected by eye.
|
||||||
|
# >>> im = Image.open('Tests/images/hopper.ppm')
|
||||||
|
# >>> im = im.rotate(45, resample=Image.BICUBIC, expand=True)
|
||||||
|
# >>> im.save('Tests/images/hopper_45.png')
|
||||||
|
|
||||||
def test_center_14(self):
|
with Image.open("Tests/images/hopper_45.png") as target:
|
||||||
im = hopper()
|
for (resample, epsilon) in (
|
||||||
im = im.rotate(45, center=(14, 14), resample=Image.BICUBIC)
|
(Image.NEAREST, 10),
|
||||||
|
(Image.BILINEAR, 5),
|
||||||
|
(Image.BICUBIC, 0),
|
||||||
|
):
|
||||||
|
im = hopper()
|
||||||
|
im = im.rotate(45, resample=resample, expand=True)
|
||||||
|
assert_image_similar(im, target, epsilon)
|
||||||
|
|
||||||
with Image.open("Tests/images/hopper_45.png") as target:
|
|
||||||
target_origin = target.size[1] / 2 - 14
|
|
||||||
target = target.crop((6, target_origin, 128 + 6, target_origin + 128))
|
|
||||||
|
|
||||||
assert_image_similar(im, target, 10)
|
def test_center_0():
|
||||||
|
im = hopper()
|
||||||
|
im = im.rotate(45, center=(0, 0), resample=Image.BICUBIC)
|
||||||
|
|
||||||
def test_translate(self):
|
with Image.open("Tests/images/hopper_45.png") as target:
|
||||||
im = hopper()
|
target_origin = target.size[1] / 2
|
||||||
with Image.open("Tests/images/hopper_45.png") as target:
|
target = target.crop((0, target_origin, 128, target_origin + 128))
|
||||||
target_origin = (target.size[1] / 2 - 64) - 5
|
|
||||||
target = target.crop(
|
|
||||||
(target_origin, target_origin, target_origin + 128, target_origin + 128)
|
|
||||||
)
|
|
||||||
|
|
||||||
im = im.rotate(45, translate=(5, 5), resample=Image.BICUBIC)
|
assert_image_similar(im, target, 15)
|
||||||
|
|
||||||
assert_image_similar(im, target, 1)
|
|
||||||
|
|
||||||
def test_fastpath_center(self):
|
def test_center_14():
|
||||||
# if the center is -1,-1 and we rotate by 90<=x<=270 the
|
im = hopper()
|
||||||
# resulting image should be black
|
im = im.rotate(45, center=(14, 14), resample=Image.BICUBIC)
|
||||||
for angle in (90, 180, 270):
|
|
||||||
im = hopper().rotate(angle, center=(-1, -1))
|
|
||||||
assert_image_equal(im, Image.new("RGB", im.size, "black"))
|
|
||||||
|
|
||||||
def test_fastpath_translate(self):
|
with Image.open("Tests/images/hopper_45.png") as target:
|
||||||
# if we post-translate by -128
|
target_origin = target.size[1] / 2 - 14
|
||||||
# resulting image should be black
|
target = target.crop((6, target_origin, 128 + 6, target_origin + 128))
|
||||||
for angle in (0, 90, 180, 270):
|
|
||||||
im = hopper().rotate(angle, translate=(-128, -128))
|
|
||||||
assert_image_equal(im, Image.new("RGB", im.size, "black"))
|
|
||||||
|
|
||||||
def test_center(self):
|
assert_image_similar(im, target, 10)
|
||||||
im = hopper()
|
|
||||||
self.rotate(im, im.mode, 45, center=(0, 0))
|
|
||||||
self.rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0))
|
|
||||||
self.rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0))
|
|
||||||
|
|
||||||
def test_rotate_no_fill(self):
|
|
||||||
im = Image.new("RGB", (100, 100), "green")
|
|
||||||
im = im.rotate(45)
|
|
||||||
with Image.open("Tests/images/rotate_45_no_fill.png") as target:
|
|
||||||
assert_image_equal(im, target)
|
|
||||||
|
|
||||||
def test_rotate_with_fill(self):
|
def test_translate():
|
||||||
im = Image.new("RGB", (100, 100), "green")
|
im = hopper()
|
||||||
im = im.rotate(45, fillcolor="white")
|
with Image.open("Tests/images/hopper_45.png") as target:
|
||||||
with Image.open("Tests/images/rotate_45_with_fill.png") as target:
|
target_origin = (target.size[1] / 2 - 64) - 5
|
||||||
assert_image_equal(im, target)
|
target = target.crop(
|
||||||
|
(target_origin, target_origin, target_origin + 128, target_origin + 128)
|
||||||
|
)
|
||||||
|
|
||||||
def test_alpha_rotate_no_fill(self):
|
im = im.rotate(45, translate=(5, 5), resample=Image.BICUBIC)
|
||||||
# Alpha images are handled differently internally
|
|
||||||
im = Image.new("RGBA", (10, 10), "green")
|
|
||||||
im = im.rotate(45, expand=1)
|
|
||||||
corner = im.getpixel((0, 0))
|
|
||||||
self.assertEqual(corner, (0, 0, 0, 0))
|
|
||||||
|
|
||||||
def test_alpha_rotate_with_fill(self):
|
assert_image_similar(im, target, 1)
|
||||||
# Alpha images are handled differently internally
|
|
||||||
im = Image.new("RGBA", (10, 10), "green")
|
|
||||||
im = im.rotate(45, expand=1, fillcolor=(255, 0, 0, 255))
|
def test_fastpath_center():
|
||||||
corner = im.getpixel((0, 0))
|
# if the center is -1,-1 and we rotate by 90<=x<=270 the
|
||||||
self.assertEqual(corner, (255, 0, 0, 255))
|
# resulting image should be black
|
||||||
|
for angle in (90, 180, 270):
|
||||||
|
im = hopper().rotate(angle, center=(-1, -1))
|
||||||
|
assert_image_equal(im, Image.new("RGB", im.size, "black"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_fastpath_translate():
|
||||||
|
# if we post-translate by -128
|
||||||
|
# resulting image should be black
|
||||||
|
for angle in (0, 90, 180, 270):
|
||||||
|
im = hopper().rotate(angle, translate=(-128, -128))
|
||||||
|
assert_image_equal(im, Image.new("RGB", im.size, "black"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_center():
|
||||||
|
im = hopper()
|
||||||
|
rotate(im, im.mode, 45, center=(0, 0))
|
||||||
|
rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0))
|
||||||
|
rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_rotate_no_fill():
|
||||||
|
im = Image.new("RGB", (100, 100), "green")
|
||||||
|
im = im.rotate(45)
|
||||||
|
with Image.open("Tests/images/rotate_45_no_fill.png") as target:
|
||||||
|
assert_image_equal(im, target)
|
||||||
|
|
||||||
|
|
||||||
|
def test_rotate_with_fill():
|
||||||
|
im = Image.new("RGB", (100, 100), "green")
|
||||||
|
im = im.rotate(45, fillcolor="white")
|
||||||
|
with Image.open("Tests/images/rotate_45_with_fill.png") as target:
|
||||||
|
assert_image_equal(im, target)
|
||||||
|
|
||||||
|
|
||||||
|
def test_alpha_rotate_no_fill():
|
||||||
|
# Alpha images are handled differently internally
|
||||||
|
im = Image.new("RGBA", (10, 10), "green")
|
||||||
|
im = im.rotate(45, expand=1)
|
||||||
|
corner = im.getpixel((0, 0))
|
||||||
|
assert corner == (0, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_alpha_rotate_with_fill():
|
||||||
|
# Alpha images are handled differently internally
|
||||||
|
im = Image.new("RGBA", (10, 10), "green")
|
||||||
|
im = im.rotate(45, expand=1, fillcolor=(255, 0, 0, 255))
|
||||||
|
corner = im.getpixel((0, 0))
|
||||||
|
assert corner == (255, 0, 0, 255)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import (
|
from .helper import (
|
||||||
PillowTestCase,
|
|
||||||
assert_image_equal,
|
assert_image_equal,
|
||||||
assert_image_similar,
|
assert_image_similar,
|
||||||
fromstring,
|
fromstring,
|
||||||
|
@ -10,98 +10,103 @@ from .helper import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestImageThumbnail(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
im = hopper()
|
||||||
im = hopper()
|
assert im.thumbnail((100, 100)) is None
|
||||||
self.assertIsNone(im.thumbnail((100, 100)))
|
|
||||||
|
|
||||||
self.assertEqual(im.size, (100, 100))
|
assert im.size == (100, 100)
|
||||||
|
|
||||||
def test_aspect(self):
|
|
||||||
im = Image.new("L", (128, 128))
|
|
||||||
im.thumbnail((100, 100))
|
|
||||||
self.assertEqual(im.size, (100, 100))
|
|
||||||
|
|
||||||
im = Image.new("L", (128, 256))
|
def test_aspect():
|
||||||
im.thumbnail((100, 100))
|
im = Image.new("L", (128, 128))
|
||||||
self.assertEqual(im.size, (50, 100))
|
im.thumbnail((100, 100))
|
||||||
|
assert im.size == (100, 100)
|
||||||
|
|
||||||
im = Image.new("L", (128, 256))
|
im = Image.new("L", (128, 256))
|
||||||
im.thumbnail((50, 100))
|
im.thumbnail((100, 100))
|
||||||
self.assertEqual(im.size, (50, 100))
|
assert im.size == (50, 100)
|
||||||
|
|
||||||
im = Image.new("L", (256, 128))
|
im = Image.new("L", (128, 256))
|
||||||
im.thumbnail((100, 100))
|
im.thumbnail((50, 100))
|
||||||
self.assertEqual(im.size, (100, 50))
|
assert im.size == (50, 100)
|
||||||
|
|
||||||
im = Image.new("L", (256, 128))
|
im = Image.new("L", (256, 128))
|
||||||
im.thumbnail((100, 50))
|
im.thumbnail((100, 100))
|
||||||
self.assertEqual(im.size, (100, 50))
|
assert im.size == (100, 50)
|
||||||
|
|
||||||
im = Image.new("L", (128, 128))
|
im = Image.new("L", (256, 128))
|
||||||
im.thumbnail((100, 100))
|
im.thumbnail((100, 50))
|
||||||
self.assertEqual(im.size, (100, 100))
|
assert im.size == (100, 50)
|
||||||
|
|
||||||
im = Image.new("L", (256, 162)) # ratio is 1.5802469136
|
im = Image.new("L", (128, 128))
|
||||||
im.thumbnail((33, 33))
|
im.thumbnail((100, 100))
|
||||||
self.assertEqual(im.size, (33, 21)) # ratio is 1.5714285714
|
assert im.size == (100, 100)
|
||||||
|
|
||||||
im = Image.new("L", (162, 256)) # ratio is 0.6328125
|
im = Image.new("L", (256, 162)) # ratio is 1.5802469136
|
||||||
im.thumbnail((33, 33))
|
im.thumbnail((33, 33))
|
||||||
self.assertEqual(im.size, (21, 33)) # ratio is 0.6363636364
|
assert im.size == (33, 21) # ratio is 1.5714285714
|
||||||
|
|
||||||
def test_float(self):
|
im = Image.new("L", (162, 256)) # ratio is 0.6328125
|
||||||
im = Image.new("L", (128, 128))
|
im.thumbnail((33, 33))
|
||||||
im.thumbnail((99.9, 99.9))
|
assert im.size == (21, 33) # ratio is 0.6363636364
|
||||||
self.assertEqual(im.size, (100, 100))
|
|
||||||
|
|
||||||
def test_no_resize(self):
|
|
||||||
# Check that draft() can resize the image to the destination size
|
|
||||||
with Image.open("Tests/images/hopper.jpg") as im:
|
|
||||||
im.draft(None, (64, 64))
|
|
||||||
self.assertEqual(im.size, (64, 64))
|
|
||||||
|
|
||||||
# Test thumbnail(), where only draft() is necessary to resize the image
|
def test_float():
|
||||||
with Image.open("Tests/images/hopper.jpg") as im:
|
im = Image.new("L", (128, 128))
|
||||||
im.thumbnail((64, 64))
|
im.thumbnail((99.9, 99.9))
|
||||||
self.assertEqual(im.size, (64, 64))
|
assert im.size == (100, 100)
|
||||||
|
|
||||||
def test_DCT_scaling_edges(self):
|
|
||||||
# Make an image with red borders and size (N * 8) + 1 to cross DCT grid
|
|
||||||
im = Image.new("RGB", (257, 257), "red")
|
|
||||||
im.paste(Image.new("RGB", (235, 235)), (11, 11))
|
|
||||||
|
|
||||||
thumb = fromstring(tostring(im, "JPEG", quality=99, subsampling=0))
|
def test_no_resize():
|
||||||
# small reducing_gap to amplify the effect
|
# Check that draft() can resize the image to the destination size
|
||||||
thumb.thumbnail((32, 32), Image.BICUBIC, reducing_gap=1.0)
|
with Image.open("Tests/images/hopper.jpg") as im:
|
||||||
|
im.draft(None, (64, 64))
|
||||||
|
assert im.size == (64, 64)
|
||||||
|
|
||||||
ref = im.resize((32, 32), Image.BICUBIC)
|
# Test thumbnail(), where only draft() is necessary to resize the image
|
||||||
# This is still JPEG, some error is present. Without the fix it is 11.5
|
with Image.open("Tests/images/hopper.jpg") as im:
|
||||||
assert_image_similar(thumb, ref, 1.5)
|
im.thumbnail((64, 64))
|
||||||
|
assert im.size == (64, 64)
|
||||||
|
|
||||||
def test_reducing_gap_values(self):
|
|
||||||
im = hopper()
|
|
||||||
im.thumbnail((18, 18), Image.BICUBIC)
|
|
||||||
|
|
||||||
ref = hopper()
|
def test_DCT_scaling_edges():
|
||||||
ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=2.0)
|
# Make an image with red borders and size (N * 8) + 1 to cross DCT grid
|
||||||
# reducing_gap=2.0 should be the default
|
im = Image.new("RGB", (257, 257), "red")
|
||||||
|
im.paste(Image.new("RGB", (235, 235)), (11, 11))
|
||||||
|
|
||||||
|
thumb = fromstring(tostring(im, "JPEG", quality=99, subsampling=0))
|
||||||
|
# small reducing_gap to amplify the effect
|
||||||
|
thumb.thumbnail((32, 32), Image.BICUBIC, reducing_gap=1.0)
|
||||||
|
|
||||||
|
ref = im.resize((32, 32), Image.BICUBIC)
|
||||||
|
# This is still JPEG, some error is present. Without the fix it is 11.5
|
||||||
|
assert_image_similar(thumb, ref, 1.5)
|
||||||
|
|
||||||
|
|
||||||
|
def test_reducing_gap_values():
|
||||||
|
im = hopper()
|
||||||
|
im.thumbnail((18, 18), Image.BICUBIC)
|
||||||
|
|
||||||
|
ref = hopper()
|
||||||
|
ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=2.0)
|
||||||
|
# reducing_gap=2.0 should be the default
|
||||||
|
assert_image_equal(ref, im)
|
||||||
|
|
||||||
|
ref = hopper()
|
||||||
|
ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=None)
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
assert_image_equal(ref, im)
|
assert_image_equal(ref, im)
|
||||||
|
|
||||||
ref = hopper()
|
assert_image_similar(ref, im, 3.5)
|
||||||
ref.thumbnail((18, 18), Image.BICUBIC, reducing_gap=None)
|
|
||||||
with self.assertRaises(AssertionError):
|
|
||||||
|
def test_reducing_gap_for_DCT_scaling():
|
||||||
|
with Image.open("Tests/images/hopper.jpg") as ref:
|
||||||
|
# thumbnail should call draft with reducing_gap scale
|
||||||
|
ref.draft(None, (18 * 3, 18 * 3))
|
||||||
|
ref = ref.resize((18, 18), Image.BICUBIC)
|
||||||
|
|
||||||
|
with Image.open("Tests/images/hopper.jpg") as im:
|
||||||
|
im.thumbnail((18, 18), Image.BICUBIC, reducing_gap=3.0)
|
||||||
|
|
||||||
assert_image_equal(ref, im)
|
assert_image_equal(ref, im)
|
||||||
|
|
||||||
assert_image_similar(ref, im, 3.5)
|
|
||||||
|
|
||||||
def test_reducing_gap_for_DCT_scaling(self):
|
|
||||||
with Image.open("Tests/images/hopper.jpg") as ref:
|
|
||||||
# thumbnail should call draft with reducing_gap scale
|
|
||||||
ref.draft(None, (18 * 3, 18 * 3))
|
|
||||||
ref = ref.resize((18, 18), Image.BICUBIC)
|
|
||||||
|
|
||||||
with Image.open("Tests/images/hopper.jpg") as im:
|
|
||||||
im.thumbnail((18, 18), Image.BICUBIC, reducing_gap=3.0)
|
|
||||||
|
|
||||||
assert_image_equal(ref, im)
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
from .helper import PillowTestCase, assert_image_equal, fromstring, hopper
|
import pytest
|
||||||
|
|
||||||
|
from .helper import assert_image_equal, fromstring, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageToBitmap(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
|
||||||
|
|
||||||
self.assertRaises(ValueError, lambda: hopper().tobitmap())
|
with pytest.raises(ValueError):
|
||||||
|
hopper().tobitmap()
|
||||||
|
|
||||||
im1 = hopper().convert("1")
|
im1 = hopper().convert("1")
|
||||||
|
|
||||||
bitmap = im1.tobitmap()
|
bitmap = im1.tobitmap()
|
||||||
|
|
||||||
self.assertIsInstance(bitmap, bytes)
|
assert isinstance(bitmap, bytes)
|
||||||
assert_image_equal(im1, fromstring(bitmap))
|
assert_image_equal(im1, fromstring(bitmap))
|
||||||
|
|
|
@ -9,151 +9,154 @@ from PIL.Image import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from .helper import PillowTestCase, assert_image_equal
|
from .helper import assert_image_equal
|
||||||
|
|
||||||
|
HOPPER = {
|
||||||
|
mode: helper.hopper(mode).crop((0, 0, 121, 127)).copy()
|
||||||
|
for mode in ["L", "RGB", "I;16", "I;16L", "I;16B"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestImageTranspose(PillowTestCase):
|
def test_flip_left_right():
|
||||||
|
def transpose(mode):
|
||||||
|
im = HOPPER[mode]
|
||||||
|
out = im.transpose(FLIP_LEFT_RIGHT)
|
||||||
|
assert out.mode == mode
|
||||||
|
assert out.size == im.size
|
||||||
|
|
||||||
hopper = {
|
x, y = im.size
|
||||||
mode: helper.hopper(mode).crop((0, 0, 121, 127)).copy()
|
assert im.getpixel((1, 1)) == out.getpixel((x - 2, 1))
|
||||||
for mode in ["L", "RGB", "I;16", "I;16L", "I;16B"]
|
assert im.getpixel((x - 2, 1)) == out.getpixel((1, 1))
|
||||||
}
|
assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, y - 2))
|
||||||
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, y - 2))
|
||||||
|
|
||||||
def test_flip_left_right(self):
|
for mode in HOPPER:
|
||||||
def transpose(mode):
|
transpose(mode)
|
||||||
im = self.hopper[mode]
|
|
||||||
out = im.transpose(FLIP_LEFT_RIGHT)
|
|
||||||
self.assertEqual(out.mode, mode)
|
|
||||||
self.assertEqual(out.size, im.size)
|
|
||||||
|
|
||||||
x, y = im.size
|
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((x - 2, 1)))
|
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, 1)))
|
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((x - 2, y - 2)))
|
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, y - 2)))
|
|
||||||
|
|
||||||
for mode in self.hopper:
|
def test_flip_top_bottom():
|
||||||
transpose(mode)
|
def transpose(mode):
|
||||||
|
im = HOPPER[mode]
|
||||||
|
out = im.transpose(FLIP_TOP_BOTTOM)
|
||||||
|
assert out.mode == mode
|
||||||
|
assert out.size == im.size
|
||||||
|
|
||||||
def test_flip_top_bottom(self):
|
x, y = im.size
|
||||||
def transpose(mode):
|
assert im.getpixel((1, 1)) == out.getpixel((1, y - 2))
|
||||||
im = self.hopper[mode]
|
assert im.getpixel((x - 2, 1)) == out.getpixel((x - 2, y - 2))
|
||||||
out = im.transpose(FLIP_TOP_BOTTOM)
|
assert im.getpixel((1, y - 2)) == out.getpixel((1, 1))
|
||||||
self.assertEqual(out.mode, mode)
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((x - 2, 1))
|
||||||
self.assertEqual(out.size, im.size)
|
|
||||||
|
|
||||||
x, y = im.size
|
for mode in HOPPER:
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, y - 2)))
|
transpose(mode)
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((x - 2, y - 2)))
|
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((1, 1)))
|
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((x - 2, 1)))
|
|
||||||
|
|
||||||
for mode in self.hopper:
|
|
||||||
transpose(mode)
|
|
||||||
|
|
||||||
def test_rotate_90(self):
|
def test_rotate_90():
|
||||||
def transpose(mode):
|
def transpose(mode):
|
||||||
im = self.hopper[mode]
|
im = HOPPER[mode]
|
||||||
out = im.transpose(ROTATE_90)
|
out = im.transpose(ROTATE_90)
|
||||||
self.assertEqual(out.mode, mode)
|
assert out.mode == mode
|
||||||
self.assertEqual(out.size, im.size[::-1])
|
assert out.size == im.size[::-1]
|
||||||
|
|
||||||
x, y = im.size
|
x, y = im.size
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, x - 2)))
|
assert im.getpixel((1, 1)) == out.getpixel((1, x - 2))
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, 1)))
|
assert im.getpixel((x - 2, 1)) == out.getpixel((1, 1))
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((y - 2, x - 2)))
|
assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, x - 2))
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((y - 2, 1)))
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, 1))
|
||||||
|
|
||||||
for mode in self.hopper:
|
for mode in HOPPER:
|
||||||
transpose(mode)
|
transpose(mode)
|
||||||
|
|
||||||
def test_rotate_180(self):
|
|
||||||
def transpose(mode):
|
|
||||||
im = self.hopper[mode]
|
|
||||||
out = im.transpose(ROTATE_180)
|
|
||||||
self.assertEqual(out.mode, mode)
|
|
||||||
self.assertEqual(out.size, im.size)
|
|
||||||
|
|
||||||
x, y = im.size
|
def test_rotate_180():
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((x - 2, y - 2)))
|
def transpose(mode):
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, y - 2)))
|
im = HOPPER[mode]
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((x - 2, 1)))
|
out = im.transpose(ROTATE_180)
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, 1)))
|
assert out.mode == mode
|
||||||
|
assert out.size == im.size
|
||||||
|
|
||||||
for mode in self.hopper:
|
x, y = im.size
|
||||||
transpose(mode)
|
assert im.getpixel((1, 1)) == out.getpixel((x - 2, y - 2))
|
||||||
|
assert im.getpixel((x - 2, 1)) == out.getpixel((1, y - 2))
|
||||||
|
assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, 1))
|
||||||
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1))
|
||||||
|
|
||||||
def test_rotate_270(self):
|
for mode in HOPPER:
|
||||||
def transpose(mode):
|
transpose(mode)
|
||||||
im = self.hopper[mode]
|
|
||||||
out = im.transpose(ROTATE_270)
|
|
||||||
self.assertEqual(out.mode, mode)
|
|
||||||
self.assertEqual(out.size, im.size[::-1])
|
|
||||||
|
|
||||||
x, y = im.size
|
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((y - 2, 1)))
|
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((y - 2, x - 2)))
|
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((1, 1)))
|
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, x - 2)))
|
|
||||||
|
|
||||||
for mode in self.hopper:
|
def test_rotate_270():
|
||||||
transpose(mode)
|
def transpose(mode):
|
||||||
|
im = HOPPER[mode]
|
||||||
|
out = im.transpose(ROTATE_270)
|
||||||
|
assert out.mode == mode
|
||||||
|
assert out.size == im.size[::-1]
|
||||||
|
|
||||||
def test_transpose(self):
|
x, y = im.size
|
||||||
def transpose(mode):
|
assert im.getpixel((1, 1)) == out.getpixel((y - 2, 1))
|
||||||
im = self.hopper[mode]
|
assert im.getpixel((x - 2, 1)) == out.getpixel((y - 2, x - 2))
|
||||||
out = im.transpose(TRANSPOSE)
|
assert im.getpixel((1, y - 2)) == out.getpixel((1, 1))
|
||||||
self.assertEqual(out.mode, mode)
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, x - 2))
|
||||||
self.assertEqual(out.size, im.size[::-1])
|
|
||||||
|
|
||||||
x, y = im.size
|
for mode in HOPPER:
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, 1)))
|
transpose(mode)
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((1, x - 2)))
|
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((y - 2, 1)))
|
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((y - 2, x - 2)))
|
|
||||||
|
|
||||||
for mode in self.hopper:
|
|
||||||
transpose(mode)
|
|
||||||
|
|
||||||
def test_tranverse(self):
|
def test_transpose():
|
||||||
def transpose(mode):
|
def transpose(mode):
|
||||||
im = self.hopper[mode]
|
im = HOPPER[mode]
|
||||||
out = im.transpose(TRANSVERSE)
|
out = im.transpose(TRANSPOSE)
|
||||||
self.assertEqual(out.mode, mode)
|
assert out.mode == mode
|
||||||
self.assertEqual(out.size, im.size[::-1])
|
assert out.size == im.size[::-1]
|
||||||
|
|
||||||
x, y = im.size
|
x, y = im.size
|
||||||
self.assertEqual(im.getpixel((1, 1)), out.getpixel((y - 2, x - 2)))
|
assert im.getpixel((1, 1)) == out.getpixel((1, 1))
|
||||||
self.assertEqual(im.getpixel((x - 2, 1)), out.getpixel((y - 2, 1)))
|
assert im.getpixel((x - 2, 1)) == out.getpixel((1, x - 2))
|
||||||
self.assertEqual(im.getpixel((1, y - 2)), out.getpixel((1, x - 2)))
|
assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, 1))
|
||||||
self.assertEqual(im.getpixel((x - 2, y - 2)), out.getpixel((1, 1)))
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, x - 2))
|
||||||
|
|
||||||
for mode in self.hopper:
|
for mode in HOPPER:
|
||||||
transpose(mode)
|
transpose(mode)
|
||||||
|
|
||||||
def test_roundtrip(self):
|
|
||||||
for mode in self.hopper:
|
|
||||||
im = self.hopper[mode]
|
|
||||||
|
|
||||||
def transpose(first, second):
|
def test_tranverse():
|
||||||
return im.transpose(first).transpose(second)
|
def transpose(mode):
|
||||||
|
im = HOPPER[mode]
|
||||||
|
out = im.transpose(TRANSVERSE)
|
||||||
|
assert out.mode == mode
|
||||||
|
assert out.size == im.size[::-1]
|
||||||
|
|
||||||
assert_image_equal(im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT))
|
x, y = im.size
|
||||||
assert_image_equal(im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM))
|
assert im.getpixel((1, 1)) == out.getpixel((y - 2, x - 2))
|
||||||
assert_image_equal(im, transpose(ROTATE_90, ROTATE_270))
|
assert im.getpixel((x - 2, 1)) == out.getpixel((y - 2, 1))
|
||||||
assert_image_equal(im, transpose(ROTATE_180, ROTATE_180))
|
assert im.getpixel((1, y - 2)) == out.getpixel((1, x - 2))
|
||||||
assert_image_equal(
|
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1))
|
||||||
im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM)
|
|
||||||
)
|
for mode in HOPPER:
|
||||||
assert_image_equal(
|
transpose(mode)
|
||||||
im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT)
|
|
||||||
)
|
|
||||||
assert_image_equal(
|
def test_roundtrip():
|
||||||
im.transpose(TRANSVERSE), transpose(ROTATE_90, FLIP_LEFT_RIGHT)
|
for mode in HOPPER:
|
||||||
)
|
im = HOPPER[mode]
|
||||||
assert_image_equal(
|
|
||||||
im.transpose(TRANSVERSE), transpose(ROTATE_270, FLIP_TOP_BOTTOM)
|
def transpose(first, second):
|
||||||
)
|
return im.transpose(first).transpose(second)
|
||||||
assert_image_equal(
|
|
||||||
im.transpose(TRANSVERSE), transpose(ROTATE_180, TRANSPOSE)
|
assert_image_equal(im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT))
|
||||||
)
|
assert_image_equal(im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM))
|
||||||
|
assert_image_equal(im, transpose(ROTATE_90, ROTATE_270))
|
||||||
|
assert_image_equal(im, transpose(ROTATE_180, ROTATE_180))
|
||||||
|
assert_image_equal(
|
||||||
|
im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM)
|
||||||
|
)
|
||||||
|
assert_image_equal(
|
||||||
|
im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT)
|
||||||
|
)
|
||||||
|
assert_image_equal(
|
||||||
|
im.transpose(TRANSVERSE), transpose(ROTATE_90, FLIP_LEFT_RIGHT)
|
||||||
|
)
|
||||||
|
assert_image_equal(
|
||||||
|
im.transpose(TRANSVERSE), transpose(ROTATE_270, FLIP_TOP_BOTTOM)
|
||||||
|
)
|
||||||
|
assert_image_equal(im.transpose(TRANSVERSE), transpose(ROTATE_180, TRANSPOSE))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from PIL import Image, ImageChops
|
from PIL import Image, ImageChops
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
BLACK = (0, 0, 0)
|
BLACK = (0, 0, 0)
|
||||||
BROWN = (127, 64, 0)
|
BROWN = (127, 64, 0)
|
||||||
|
@ -13,352 +13,373 @@ WHITE = (255, 255, 255)
|
||||||
GREY = 128
|
GREY = 128
|
||||||
|
|
||||||
|
|
||||||
class TestImageChops(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
im = hopper("L")
|
||||||
|
|
||||||
im = hopper("L")
|
ImageChops.constant(im, 128)
|
||||||
|
ImageChops.duplicate(im)
|
||||||
|
ImageChops.invert(im)
|
||||||
|
ImageChops.lighter(im, im)
|
||||||
|
ImageChops.darker(im, im)
|
||||||
|
ImageChops.difference(im, im)
|
||||||
|
ImageChops.multiply(im, im)
|
||||||
|
ImageChops.screen(im, im)
|
||||||
|
|
||||||
ImageChops.constant(im, 128)
|
ImageChops.add(im, im)
|
||||||
ImageChops.duplicate(im)
|
ImageChops.add(im, im, 2.0)
|
||||||
ImageChops.invert(im)
|
ImageChops.add(im, im, 2.0, 128)
|
||||||
ImageChops.lighter(im, im)
|
ImageChops.subtract(im, im)
|
||||||
ImageChops.darker(im, im)
|
ImageChops.subtract(im, im, 2.0)
|
||||||
ImageChops.difference(im, im)
|
ImageChops.subtract(im, im, 2.0, 128)
|
||||||
ImageChops.multiply(im, im)
|
|
||||||
ImageChops.screen(im, im)
|
|
||||||
|
|
||||||
ImageChops.add(im, im)
|
ImageChops.add_modulo(im, im)
|
||||||
ImageChops.add(im, im, 2.0)
|
ImageChops.subtract_modulo(im, im)
|
||||||
ImageChops.add(im, im, 2.0, 128)
|
|
||||||
ImageChops.subtract(im, im)
|
|
||||||
ImageChops.subtract(im, im, 2.0)
|
|
||||||
ImageChops.subtract(im, im, 2.0, 128)
|
|
||||||
|
|
||||||
ImageChops.add_modulo(im, im)
|
ImageChops.blend(im, im, 0.5)
|
||||||
ImageChops.subtract_modulo(im, im)
|
ImageChops.composite(im, im, im)
|
||||||
|
|
||||||
ImageChops.blend(im, im, 0.5)
|
ImageChops.offset(im, 10)
|
||||||
ImageChops.composite(im, im, im)
|
ImageChops.offset(im, 10, 20)
|
||||||
|
|
||||||
ImageChops.offset(im, 10)
|
|
||||||
ImageChops.offset(im, 10, 20)
|
|
||||||
|
|
||||||
def test_add(self):
|
def test_add():
|
||||||
# Arrange
|
# Arrange
|
||||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.add(im1, im2)
|
new = ImageChops.add(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
|
assert new.getbbox() == (25, 25, 76, 76)
|
||||||
self.assertEqual(new.getpixel((50, 50)), ORANGE)
|
assert new.getpixel((50, 50)) == ORANGE
|
||||||
|
|
||||||
def test_add_scale_offset(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
def test_add_scale_offset():
|
||||||
new = ImageChops.add(im1, im2, scale=2.5, offset=100)
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(new.getbbox(), (0, 0, 100, 100))
|
new = ImageChops.add(im1, im2, scale=2.5, offset=100)
|
||||||
self.assertEqual(new.getpixel((50, 50)), (202, 151, 100))
|
|
||||||
|
|
||||||
def test_add_clip(self):
|
# Assert
|
||||||
# Arrange
|
assert new.getbbox() == (0, 0, 100, 100)
|
||||||
im = hopper()
|
assert new.getpixel((50, 50)) == (202, 151, 100)
|
||||||
|
|
||||||
# Act
|
|
||||||
new = ImageChops.add(im, im)
|
|
||||||
|
|
||||||
# Assert
|
def test_add_clip():
|
||||||
self.assertEqual(new.getpixel((50, 50)), (255, 255, 254))
|
# Arrange
|
||||||
|
im = hopper()
|
||||||
|
|
||||||
def test_add_modulo(self):
|
# Act
|
||||||
# Arrange
|
new = ImageChops.add(im, im)
|
||||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
# Assert
|
||||||
new = ImageChops.add_modulo(im1, im2)
|
assert new.getpixel((50, 50)) == (255, 255, 254)
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
|
|
||||||
self.assertEqual(new.getpixel((50, 50)), ORANGE)
|
|
||||||
|
|
||||||
def test_add_modulo_no_clip(self):
|
def test_add_modulo():
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper()
|
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.add_modulo(im, im)
|
new = ImageChops.add_modulo(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getpixel((50, 50)), (224, 76, 254))
|
assert new.getbbox() == (25, 25, 76, 76)
|
||||||
|
assert new.getpixel((50, 50)) == ORANGE
|
||||||
|
|
||||||
def test_blend(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
def test_add_modulo_no_clip():
|
||||||
new = ImageChops.blend(im1, im2, 0.5)
|
# Arrange
|
||||||
|
im = hopper()
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
|
new = ImageChops.add_modulo(im, im)
|
||||||
self.assertEqual(new.getpixel((50, 50)), BROWN)
|
|
||||||
|
|
||||||
def test_constant(self):
|
# Assert
|
||||||
# Arrange
|
assert new.getpixel((50, 50)) == (224, 76, 254)
|
||||||
im = Image.new("RGB", (20, 10))
|
|
||||||
|
|
||||||
# Act
|
|
||||||
new = ImageChops.constant(im, GREY)
|
|
||||||
|
|
||||||
# Assert
|
def test_blend():
|
||||||
self.assertEqual(new.size, im.size)
|
# Arrange
|
||||||
self.assertEqual(new.getpixel((0, 0)), GREY)
|
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||||
self.assertEqual(new.getpixel((19, 9)), GREY)
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||||
|
|
||||||
def test_darker_image(self):
|
# Act
|
||||||
# Arrange
|
new = ImageChops.blend(im1, im2, 0.5)
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
# Assert
|
||||||
new = ImageChops.darker(im1, im2)
|
assert new.getbbox() == (25, 25, 76, 76)
|
||||||
|
assert new.getpixel((50, 50)) == BROWN
|
||||||
|
|
||||||
# Assert
|
|
||||||
assert_image_equal(new, im2)
|
|
||||||
|
|
||||||
def test_darker_pixel(self):
|
def test_constant():
|
||||||
# Arrange
|
# Arrange
|
||||||
im1 = hopper()
|
im = Image.new("RGB", (20, 10))
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
|
||||||
|
# Act
|
||||||
|
new = ImageChops.constant(im, GREY)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert new.size == im.size
|
||||||
|
assert new.getpixel((0, 0)) == GREY
|
||||||
|
assert new.getpixel((19, 9)) == GREY
|
||||||
|
|
||||||
|
|
||||||
|
def test_darker_image():
|
||||||
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.darker(im1, im2)
|
new = ImageChops.darker(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getpixel((50, 50)), (240, 166, 0))
|
assert_image_equal(new, im2)
|
||||||
|
|
||||||
def test_difference(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
def test_darker_pixel():
|
||||||
new = ImageChops.difference(im1, im2)
|
# Arrange
|
||||||
|
im1 = hopper()
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
|
new = ImageChops.darker(im1, im2)
|
||||||
|
|
||||||
def test_difference_pixel(self):
|
# Assert
|
||||||
# Arrange
|
assert new.getpixel((50, 50)) == (240, 166, 0)
|
||||||
im1 = hopper()
|
|
||||||
with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2:
|
|
||||||
|
def test_difference():
|
||||||
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.difference(im1, im2)
|
new = ImageChops.difference(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getpixel((50, 50)), (240, 166, 128))
|
assert new.getbbox() == (25, 25, 76, 76)
|
||||||
|
|
||||||
def test_duplicate(self):
|
|
||||||
# Arrange
|
def test_difference_pixel():
|
||||||
im = hopper()
|
# Arrange
|
||||||
|
im1 = hopper()
|
||||||
|
with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.duplicate(im)
|
new = ImageChops.difference(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert_image_equal(new, im)
|
assert new.getpixel((50, 50)) == (240, 166, 128)
|
||||||
|
|
||||||
def test_invert(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
|
|
||||||
|
|
||||||
# Act
|
def test_duplicate():
|
||||||
new = ImageChops.invert(im)
|
# Arrange
|
||||||
|
im = hopper()
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(new.getbbox(), (0, 0, 100, 100))
|
new = ImageChops.duplicate(im)
|
||||||
self.assertEqual(new.getpixel((0, 0)), WHITE)
|
|
||||||
self.assertEqual(new.getpixel((50, 50)), CYAN)
|
|
||||||
|
|
||||||
def test_lighter_image(self):
|
# Assert
|
||||||
# Arrange
|
assert_image_equal(new, im)
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
|
||||||
new = ImageChops.lighter(im1, im2)
|
|
||||||
|
|
||||||
# Assert
|
def test_invert():
|
||||||
assert_image_equal(new, im1)
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
|
||||||
|
|
||||||
def test_lighter_pixel(self):
|
# Act
|
||||||
# Arrange
|
new = ImageChops.invert(im)
|
||||||
im1 = hopper()
|
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
# Assert
|
||||||
|
assert new.getbbox() == (0, 0, 100, 100)
|
||||||
|
assert new.getpixel((0, 0)) == WHITE
|
||||||
|
assert new.getpixel((50, 50)) == CYAN
|
||||||
|
|
||||||
|
|
||||||
|
def test_lighter_image():
|
||||||
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.lighter(im1, im2)
|
new = ImageChops.lighter(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getpixel((50, 50)), (255, 255, 127))
|
assert_image_equal(new, im1)
|
||||||
|
|
||||||
def test_multiply_black(self):
|
|
||||||
"""If you multiply an image with a solid black image,
|
def test_lighter_pixel():
|
||||||
the result is black."""
|
# Arrange
|
||||||
# Arrange
|
im1 = hopper()
|
||||||
im1 = hopper()
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||||
black = Image.new("RGB", im1.size, "black")
|
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.multiply(im1, black)
|
new = ImageChops.lighter(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert_image_equal(new, black)
|
assert new.getpixel((50, 50)) == (255, 255, 127)
|
||||||
|
|
||||||
def test_multiply_green(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
|
|
||||||
green = Image.new("RGB", im.size, "green")
|
|
||||||
|
|
||||||
# Act
|
def test_multiply_black():
|
||||||
new = ImageChops.multiply(im, green)
|
"""If you multiply an image with a solid black image,
|
||||||
|
the result is black."""
|
||||||
|
# Arrange
|
||||||
|
im1 = hopper()
|
||||||
|
black = Image.new("RGB", im1.size, "black")
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
|
new = ImageChops.multiply(im1, black)
|
||||||
self.assertEqual(new.getpixel((25, 25)), DARK_GREEN)
|
|
||||||
self.assertEqual(new.getpixel((50, 50)), BLACK)
|
|
||||||
|
|
||||||
def test_multiply_white(self):
|
# Assert
|
||||||
"""If you multiply with a solid white image,
|
assert_image_equal(new, black)
|
||||||
the image is unaffected."""
|
|
||||||
# Arrange
|
|
||||||
im1 = hopper()
|
def test_multiply_green():
|
||||||
white = Image.new("RGB", im1.size, "white")
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
|
||||||
|
green = Image.new("RGB", im.size, "green")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.multiply(im1, white)
|
new = ImageChops.multiply(im, green)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert_image_equal(new, im1)
|
assert new.getbbox() == (25, 25, 76, 76)
|
||||||
|
assert new.getpixel((25, 25)) == DARK_GREEN
|
||||||
|
assert new.getpixel((50, 50)) == BLACK
|
||||||
|
|
||||||
def test_offset(self):
|
|
||||||
# Arrange
|
def test_multiply_white():
|
||||||
xoffset = 45
|
"""If you multiply with a solid white image, the image is unaffected."""
|
||||||
yoffset = 20
|
# Arrange
|
||||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im:
|
im1 = hopper()
|
||||||
|
white = Image.new("RGB", im1.size, "white")
|
||||||
|
|
||||||
|
# Act
|
||||||
|
new = ImageChops.multiply(im1, white)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert_image_equal(new, im1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_offset():
|
||||||
|
# Arrange
|
||||||
|
xoffset = 45
|
||||||
|
yoffset = 20
|
||||||
|
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im:
|
||||||
|
|
||||||
|
# Act
|
||||||
|
new = ImageChops.offset(im, xoffset, yoffset)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert new.getbbox() == (0, 45, 100, 96)
|
||||||
|
assert new.getpixel((50, 50)) == BLACK
|
||||||
|
assert new.getpixel((50 + xoffset, 50 + yoffset)) == DARK_GREEN
|
||||||
|
|
||||||
|
# Test no yoffset
|
||||||
|
assert ImageChops.offset(im, xoffset) == ImageChops.offset(im, xoffset, xoffset)
|
||||||
|
|
||||||
|
|
||||||
|
def test_screen():
|
||||||
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.offset(im, xoffset, yoffset)
|
new = ImageChops.screen(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getbbox(), (0, 45, 100, 96))
|
assert new.getbbox() == (25, 25, 76, 76)
|
||||||
self.assertEqual(new.getpixel((50, 50)), BLACK)
|
assert new.getpixel((50, 50)) == ORANGE
|
||||||
self.assertEqual(new.getpixel((50 + xoffset, 50 + yoffset)), DARK_GREEN)
|
|
||||||
|
|
||||||
# Test no yoffset
|
|
||||||
self.assertEqual(
|
|
||||||
ImageChops.offset(im, xoffset), ImageChops.offset(im, xoffset, xoffset)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_screen(self):
|
def test_subtract():
|
||||||
# Arrange
|
# Arrange
|
||||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
|
||||||
new = ImageChops.screen(im1, im2)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
|
|
||||||
self.assertEqual(new.getpixel((50, 50)), ORANGE)
|
|
||||||
|
|
||||||
def test_subtract(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
|
||||||
new = ImageChops.subtract(im1, im2)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertEqual(new.getbbox(), (25, 50, 76, 76))
|
|
||||||
self.assertEqual(new.getpixel((50, 50)), GREEN)
|
|
||||||
self.assertEqual(new.getpixel((50, 51)), BLACK)
|
|
||||||
|
|
||||||
def test_subtract_scale_offset(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
|
||||||
new = ImageChops.subtract(im1, im2, scale=2.5, offset=100)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertEqual(new.getbbox(), (0, 0, 100, 100))
|
|
||||||
self.assertEqual(new.getpixel((50, 50)), (100, 202, 100))
|
|
||||||
|
|
||||||
def test_subtract_clip(self):
|
|
||||||
# Arrange
|
|
||||||
im1 = hopper()
|
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.subtract(im1, im2)
|
new = ImageChops.subtract(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getpixel((50, 50)), (0, 0, 127))
|
assert new.getbbox() == (25, 50, 76, 76)
|
||||||
|
assert new.getpixel((50, 50)) == GREEN
|
||||||
|
assert new.getpixel((50, 51)) == BLACK
|
||||||
|
|
||||||
def test_subtract_modulo(self):
|
|
||||||
# Arrange
|
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
|
||||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
# Act
|
def test_subtract_scale_offset():
|
||||||
new = ImageChops.subtract_modulo(im1, im2)
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(new.getbbox(), (25, 50, 76, 76))
|
new = ImageChops.subtract(im1, im2, scale=2.5, offset=100)
|
||||||
self.assertEqual(new.getpixel((50, 50)), GREEN)
|
|
||||||
self.assertEqual(new.getpixel((50, 51)), BLACK)
|
|
||||||
|
|
||||||
def test_subtract_modulo_no_clip(self):
|
# Assert
|
||||||
# Arrange
|
assert new.getbbox() == (0, 0, 100, 100)
|
||||||
im1 = hopper()
|
assert new.getpixel((50, 50)) == (100, 202, 100)
|
||||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
|
||||||
|
|
||||||
|
def test_subtract_clip():
|
||||||
|
# Arrange
|
||||||
|
im1 = hopper()
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||||
|
|
||||||
|
# Act
|
||||||
|
new = ImageChops.subtract(im1, im2)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert new.getpixel((50, 50)) == (0, 0, 127)
|
||||||
|
|
||||||
|
|
||||||
|
def test_subtract_modulo():
|
||||||
|
# Arrange
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||||
|
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
new = ImageChops.subtract_modulo(im1, im2)
|
new = ImageChops.subtract_modulo(im1, im2)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(new.getpixel((50, 50)), (241, 167, 127))
|
assert new.getbbox() == (25, 50, 76, 76)
|
||||||
|
assert new.getpixel((50, 50)) == GREEN
|
||||||
|
assert new.getpixel((50, 51)) == BLACK
|
||||||
|
|
||||||
def test_logical(self):
|
|
||||||
def table(op, a, b):
|
|
||||||
out = []
|
|
||||||
for x in (a, b):
|
|
||||||
imx = Image.new("1", (1, 1), x)
|
|
||||||
for y in (a, b):
|
|
||||||
imy = Image.new("1", (1, 1), y)
|
|
||||||
out.append(op(imx, imy).getpixel((0, 0)))
|
|
||||||
return tuple(out)
|
|
||||||
|
|
||||||
self.assertEqual(table(ImageChops.logical_and, 0, 1), (0, 0, 0, 255))
|
def test_subtract_modulo_no_clip():
|
||||||
self.assertEqual(table(ImageChops.logical_or, 0, 1), (0, 255, 255, 255))
|
# Arrange
|
||||||
self.assertEqual(table(ImageChops.logical_xor, 0, 1), (0, 255, 255, 0))
|
im1 = hopper()
|
||||||
|
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||||
|
|
||||||
self.assertEqual(table(ImageChops.logical_and, 0, 128), (0, 0, 0, 255))
|
# Act
|
||||||
self.assertEqual(table(ImageChops.logical_or, 0, 128), (0, 255, 255, 255))
|
new = ImageChops.subtract_modulo(im1, im2)
|
||||||
self.assertEqual(table(ImageChops.logical_xor, 0, 128), (0, 255, 255, 0))
|
|
||||||
|
|
||||||
self.assertEqual(table(ImageChops.logical_and, 0, 255), (0, 0, 0, 255))
|
# Assert
|
||||||
self.assertEqual(table(ImageChops.logical_or, 0, 255), (0, 255, 255, 255))
|
assert new.getpixel((50, 50)) == (241, 167, 127)
|
||||||
self.assertEqual(table(ImageChops.logical_xor, 0, 255), (0, 255, 255, 0))
|
|
||||||
|
|
||||||
|
def test_logical():
|
||||||
|
def table(op, a, b):
|
||||||
|
out = []
|
||||||
|
for x in (a, b):
|
||||||
|
imx = Image.new("1", (1, 1), x)
|
||||||
|
for y in (a, b):
|
||||||
|
imy = Image.new("1", (1, 1), y)
|
||||||
|
out.append(op(imx, imy).getpixel((0, 0)))
|
||||||
|
return tuple(out)
|
||||||
|
|
||||||
|
assert table(ImageChops.logical_and, 0, 1) == (0, 0, 0, 255)
|
||||||
|
assert table(ImageChops.logical_or, 0, 1) == (0, 255, 255, 255)
|
||||||
|
assert table(ImageChops.logical_xor, 0, 1) == (0, 255, 255, 0)
|
||||||
|
|
||||||
|
assert table(ImageChops.logical_and, 0, 128) == (0, 0, 0, 255)
|
||||||
|
assert table(ImageChops.logical_or, 0, 128) == (0, 255, 255, 255)
|
||||||
|
assert table(ImageChops.logical_xor, 0, 128) == (0, 255, 255, 0)
|
||||||
|
|
||||||
|
assert table(ImageChops.logical_and, 0, 255) == (0, 0, 0, 255)
|
||||||
|
assert table(ImageChops.logical_or, 0, 255) == (0, 255, 255, 255)
|
||||||
|
assert table(ImageChops.logical_xor, 0, 255) == (0, 255, 255, 0)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
||||||
import os.path
|
import os.path
|
||||||
import unittest
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
from PIL import Image, ImageDraw2, features
|
from PIL import Image, ImageDraw2, features
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper
|
from .helper import assert_image_equal, assert_image_similar, hopper
|
||||||
|
|
||||||
BLACK = (0, 0, 0)
|
BLACK = (0, 0, 0)
|
||||||
WHITE = (255, 255, 255)
|
WHITE = (255, 255, 255)
|
||||||
|
@ -34,190 +34,206 @@ HAS_FREETYPE = features.check("freetype2")
|
||||||
FONT_PATH = "Tests/fonts/FreeMono.ttf"
|
FONT_PATH = "Tests/fonts/FreeMono.ttf"
|
||||||
|
|
||||||
|
|
||||||
class TestImageDraw(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
im = hopper("RGB").copy()
|
||||||
im = hopper("RGB").copy()
|
|
||||||
|
|
||||||
draw = ImageDraw2.Draw(im)
|
draw = ImageDraw2.Draw(im)
|
||||||
pen = ImageDraw2.Pen("blue", width=7)
|
pen = ImageDraw2.Pen("blue", width=7)
|
||||||
draw.line(list(range(10)), pen)
|
draw.line(list(range(10)), pen)
|
||||||
|
|
||||||
from PIL import ImageDraw
|
from PIL import ImageDraw
|
||||||
|
|
||||||
draw, handler = ImageDraw.getdraw(im)
|
draw, handler = ImageDraw.getdraw(im)
|
||||||
pen = ImageDraw2.Pen("blue", width=7)
|
pen = ImageDraw2.Pen("blue", width=7)
|
||||||
draw.line(list(range(10)), pen)
|
draw.line(list(range(10)), pen)
|
||||||
|
|
||||||
def helper_ellipse(self, mode, bbox):
|
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
pen = ImageDraw2.Pen("blue", width=2)
|
|
||||||
brush = ImageDraw2.Brush("green")
|
|
||||||
expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode)
|
|
||||||
|
|
||||||
# Act
|
def helper_ellipse(mode, bbox):
|
||||||
draw.ellipse(bbox, pen, brush)
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
pen = ImageDraw2.Pen("blue", width=2)
|
||||||
|
brush = ImageDraw2.Brush("green")
|
||||||
|
expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode)
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
assert_image_similar(im, Image.open(expected), 1)
|
draw.ellipse(bbox, pen, brush)
|
||||||
|
|
||||||
def test_ellipse1(self):
|
# Assert
|
||||||
self.helper_ellipse("RGB", BBOX1)
|
assert_image_similar(im, Image.open(expected), 1)
|
||||||
|
|
||||||
def test_ellipse2(self):
|
|
||||||
self.helper_ellipse("RGB", BBOX2)
|
|
||||||
|
|
||||||
def test_ellipse_edge(self):
|
def test_ellipse1():
|
||||||
# Arrange
|
helper_ellipse("RGB", BBOX1)
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
brush = ImageDraw2.Brush("white")
|
|
||||||
|
|
||||||
# Act
|
|
||||||
draw.ellipse(((0, 0), (W - 1, H)), brush)
|
|
||||||
|
|
||||||
# Assert
|
def test_ellipse2():
|
||||||
assert_image_similar(
|
helper_ellipse("RGB", BBOX2)
|
||||||
im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1
|
|
||||||
)
|
|
||||||
|
|
||||||
def helper_line(self, points):
|
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
pen = ImageDraw2.Pen("yellow", width=2)
|
|
||||||
|
|
||||||
# Act
|
def test_ellipse_edge():
|
||||||
draw.line(points, pen)
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
brush = ImageDraw2.Brush("white")
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png"))
|
draw.ellipse(((0, 0), (W - 1, H)), brush)
|
||||||
|
|
||||||
def test_line1_pen(self):
|
# Assert
|
||||||
self.helper_line(POINTS1)
|
assert_image_similar(im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1)
|
||||||
|
|
||||||
def test_line2_pen(self):
|
|
||||||
self.helper_line(POINTS2)
|
|
||||||
|
|
||||||
def test_line_pen_as_brush(self):
|
def helper_line(points):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.new("RGB", (W, H))
|
im = Image.new("RGB", (W, H))
|
||||||
draw = ImageDraw2.Draw(im)
|
draw = ImageDraw2.Draw(im)
|
||||||
pen = None
|
pen = ImageDraw2.Pen("yellow", width=2)
|
||||||
brush = ImageDraw2.Pen("yellow", width=2)
|
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
# Pass in the pen as the brush parameter
|
draw.line(points, pen)
|
||||||
draw.line(POINTS1, pen, brush)
|
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png"))
|
assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png"))
|
||||||
|
|
||||||
def helper_polygon(self, points):
|
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
pen = ImageDraw2.Pen("blue", width=2)
|
|
||||||
brush = ImageDraw2.Brush("red")
|
|
||||||
|
|
||||||
# Act
|
def test_line1_pen():
|
||||||
draw.polygon(points, pen, brush)
|
helper_line(POINTS1)
|
||||||
|
|
||||||
# Assert
|
|
||||||
assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png"))
|
|
||||||
|
|
||||||
def test_polygon1(self):
|
def test_line2_pen():
|
||||||
self.helper_polygon(POINTS1)
|
helper_line(POINTS2)
|
||||||
|
|
||||||
def test_polygon2(self):
|
|
||||||
self.helper_polygon(POINTS2)
|
|
||||||
|
|
||||||
def helper_rectangle(self, bbox):
|
def test_line_pen_as_brush():
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.new("RGB", (W, H))
|
im = Image.new("RGB", (W, H))
|
||||||
draw = ImageDraw2.Draw(im)
|
draw = ImageDraw2.Draw(im)
|
||||||
pen = ImageDraw2.Pen("green", width=2)
|
pen = None
|
||||||
brush = ImageDraw2.Brush("black")
|
brush = ImageDraw2.Pen("yellow", width=2)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
draw.rectangle(bbox, pen, brush)
|
# Pass in the pen as the brush parameter
|
||||||
|
draw.line(POINTS1, pen, brush)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png"))
|
assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png"))
|
||||||
|
|
||||||
def test_rectangle1(self):
|
|
||||||
self.helper_rectangle(BBOX1)
|
|
||||||
|
|
||||||
def test_rectangle2(self):
|
def helper_polygon(points):
|
||||||
self.helper_rectangle(BBOX2)
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
pen = ImageDraw2.Pen("blue", width=2)
|
||||||
|
brush = ImageDraw2.Brush("red")
|
||||||
|
|
||||||
def test_big_rectangle(self):
|
# Act
|
||||||
# Test drawing a rectangle bigger than the image
|
draw.polygon(points, pen, brush)
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
bbox = [(-1, -1), (W + 1, H + 1)]
|
|
||||||
brush = ImageDraw2.Brush("orange")
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
expected = "Tests/images/imagedraw_big_rectangle.png"
|
|
||||||
|
|
||||||
# Act
|
# Assert
|
||||||
draw.rectangle(bbox, brush)
|
assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png"))
|
||||||
|
|
||||||
# Assert
|
|
||||||
assert_image_similar(im, Image.open(expected), 1)
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not available")
|
def test_polygon1():
|
||||||
def test_text(self):
|
helper_polygon(POINTS1)
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
font = ImageDraw2.Font("white", FONT_PATH)
|
|
||||||
expected = "Tests/images/imagedraw2_text.png"
|
|
||||||
|
|
||||||
# Act
|
|
||||||
draw.text((5, 5), "ImageDraw2", font)
|
|
||||||
|
|
||||||
# Assert
|
def test_polygon2():
|
||||||
assert_image_similar(im, Image.open(expected), 13)
|
helper_polygon(POINTS2)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not available")
|
|
||||||
def test_textsize(self):
|
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
font = ImageDraw2.Font("white", FONT_PATH)
|
|
||||||
|
|
||||||
# Act
|
def helper_rectangle(bbox):
|
||||||
size = draw.textsize("ImageDraw2", font)
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
pen = ImageDraw2.Pen("green", width=2)
|
||||||
|
brush = ImageDraw2.Brush("black")
|
||||||
|
|
||||||
# Assert
|
# Act
|
||||||
self.assertEqual(size[1], 12)
|
draw.rectangle(bbox, pen, brush)
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not available")
|
# Assert
|
||||||
def test_textsize_empty_string(self):
|
assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png"))
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
font = ImageDraw2.Font("white", FONT_PATH)
|
|
||||||
|
|
||||||
# Act
|
|
||||||
# Should not cause 'SystemError: <built-in method getsize of
|
|
||||||
# ImagingFont object at 0x...> returned NULL without setting an error'
|
|
||||||
draw.textsize("", font)
|
|
||||||
draw.textsize("\n", font)
|
|
||||||
draw.textsize("test\n", font)
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not available")
|
def test_rectangle1():
|
||||||
def test_flush(self):
|
helper_rectangle(BBOX1)
|
||||||
# Arrange
|
|
||||||
im = Image.new("RGB", (W, H))
|
|
||||||
draw = ImageDraw2.Draw(im)
|
|
||||||
font = ImageDraw2.Font("white", FONT_PATH)
|
|
||||||
|
|
||||||
# Act
|
|
||||||
draw.text((5, 5), "ImageDraw2", font)
|
|
||||||
im2 = draw.flush()
|
|
||||||
|
|
||||||
# Assert
|
def test_rectangle2():
|
||||||
assert_image_equal(im, im2)
|
helper_rectangle(BBOX2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_big_rectangle():
|
||||||
|
# Test drawing a rectangle bigger than the image
|
||||||
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
bbox = [(-1, -1), (W + 1, H + 1)]
|
||||||
|
brush = ImageDraw2.Brush("orange")
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
expected = "Tests/images/imagedraw_big_rectangle.png"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
draw.rectangle(bbox, brush)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert_image_similar(im, Image.open(expected), 1)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available")
|
||||||
|
def test_text():
|
||||||
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
font = ImageDraw2.Font("white", FONT_PATH)
|
||||||
|
expected = "Tests/images/imagedraw2_text.png"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
draw.text((5, 5), "ImageDraw2", font)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert_image_similar(im, Image.open(expected), 13)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available")
|
||||||
|
def test_textsize():
|
||||||
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
font = ImageDraw2.Font("white", FONT_PATH)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
size = draw.textsize("ImageDraw2", font)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert size[1] == 12
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available")
|
||||||
|
def test_textsize_empty_string():
|
||||||
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
font = ImageDraw2.Font("white", FONT_PATH)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
# Should not cause 'SystemError: <built-in method getsize of
|
||||||
|
# ImagingFont object at 0x...> returned NULL without setting an error'
|
||||||
|
draw.textsize("", font)
|
||||||
|
draw.textsize("\n", font)
|
||||||
|
draw.textsize("test\n", font)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not HAS_FREETYPE, reason="ImageFont not available")
|
||||||
|
def test_flush():
|
||||||
|
# Arrange
|
||||||
|
im = Image.new("RGB", (W, H))
|
||||||
|
draw = ImageDraw2.Draw(im)
|
||||||
|
font = ImageDraw2.Font("white", FONT_PATH)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
draw.text((5, 5), "ImageDraw2", font)
|
||||||
|
im2 = draw.flush()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert_image_equal(im, im2)
|
||||||
|
|
|
@ -1,54 +1,55 @@
|
||||||
from PIL import Image, ImageEnhance
|
from PIL import Image, ImageEnhance
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
class TestImageEnhance(PillowTestCase):
|
def test_sanity():
|
||||||
def test_sanity(self):
|
# FIXME: assert_image
|
||||||
|
# Implicit asserts no exception:
|
||||||
|
ImageEnhance.Color(hopper()).enhance(0.5)
|
||||||
|
ImageEnhance.Contrast(hopper()).enhance(0.5)
|
||||||
|
ImageEnhance.Brightness(hopper()).enhance(0.5)
|
||||||
|
ImageEnhance.Sharpness(hopper()).enhance(0.5)
|
||||||
|
|
||||||
# FIXME: assert_image
|
|
||||||
# Implicit asserts no exception:
|
|
||||||
ImageEnhance.Color(hopper()).enhance(0.5)
|
|
||||||
ImageEnhance.Contrast(hopper()).enhance(0.5)
|
|
||||||
ImageEnhance.Brightness(hopper()).enhance(0.5)
|
|
||||||
ImageEnhance.Sharpness(hopper()).enhance(0.5)
|
|
||||||
|
|
||||||
def test_crash(self):
|
def test_crash():
|
||||||
|
# crashes on small images
|
||||||
|
im = Image.new("RGB", (1, 1))
|
||||||
|
ImageEnhance.Sharpness(im).enhance(0.5)
|
||||||
|
|
||||||
# crashes on small images
|
|
||||||
im = Image.new("RGB", (1, 1))
|
|
||||||
ImageEnhance.Sharpness(im).enhance(0.5)
|
|
||||||
|
|
||||||
def _half_transparent_image(self):
|
def _half_transparent_image():
|
||||||
# returns an image, half transparent, half solid
|
# returns an image, half transparent, half solid
|
||||||
im = hopper("RGB")
|
im = hopper("RGB")
|
||||||
|
|
||||||
transparent = Image.new("L", im.size, 0)
|
transparent = Image.new("L", im.size, 0)
|
||||||
solid = Image.new("L", (im.size[0] // 2, im.size[1]), 255)
|
solid = Image.new("L", (im.size[0] // 2, im.size[1]), 255)
|
||||||
transparent.paste(solid, (0, 0))
|
transparent.paste(solid, (0, 0))
|
||||||
im.putalpha(transparent)
|
im.putalpha(transparent)
|
||||||
|
|
||||||
return im
|
return im
|
||||||
|
|
||||||
def _check_alpha(self, im, original, op, amount):
|
|
||||||
self.assertEqual(im.getbands(), original.getbands())
|
|
||||||
assert_image_equal(
|
|
||||||
im.getchannel("A"),
|
|
||||||
original.getchannel("A"),
|
|
||||||
"Diff on {}: {}".format(op, amount),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_alpha(self):
|
def _check_alpha(im, original, op, amount):
|
||||||
# Issue https://github.com/python-pillow/Pillow/issues/899
|
assert im.getbands() == original.getbands()
|
||||||
# Is alpha preserved through image enhancement?
|
assert_image_equal(
|
||||||
|
im.getchannel("A"),
|
||||||
|
original.getchannel("A"),
|
||||||
|
"Diff on {}: {}".format(op, amount),
|
||||||
|
)
|
||||||
|
|
||||||
original = self._half_transparent_image()
|
|
||||||
|
|
||||||
for op in ["Color", "Brightness", "Contrast", "Sharpness"]:
|
def test_alpha():
|
||||||
for amount in [0, 0.5, 1.0]:
|
# Issue https://github.com/python-pillow/Pillow/issues/899
|
||||||
self._check_alpha(
|
# Is alpha preserved through image enhancement?
|
||||||
getattr(ImageEnhance, op)(original).enhance(amount),
|
|
||||||
original,
|
original = _half_transparent_image()
|
||||||
op,
|
|
||||||
amount,
|
for op in ["Color", "Brightness", "Contrast", "Sharpness"]:
|
||||||
)
|
for amount in [0, 0.5, 1.0]:
|
||||||
|
_check_alpha(
|
||||||
|
getattr(ImageEnhance, op)(original).enhance(amount),
|
||||||
|
original,
|
||||||
|
op,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
import pytest
|
||||||
from PIL import Image, ImageOps
|
from PIL import Image, ImageOps
|
||||||
|
|
||||||
from .helper import (
|
from .helper import (
|
||||||
PillowTestCase,
|
|
||||||
assert_image_equal,
|
assert_image_equal,
|
||||||
assert_image_similar,
|
assert_image_similar,
|
||||||
assert_tuple_approx_equal,
|
assert_tuple_approx_equal,
|
||||||
|
@ -16,287 +16,294 @@ except ImportError:
|
||||||
HAVE_WEBP = False
|
HAVE_WEBP = False
|
||||||
|
|
||||||
|
|
||||||
class TestImageOps(PillowTestCase):
|
class Deformer:
|
||||||
class Deformer:
|
def getmesh(self, im):
|
||||||
def getmesh(self, im):
|
x, y = im.size
|
||||||
x, y = im.size
|
return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))]
|
||||||
return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))]
|
|
||||||
|
|
||||||
deformer = Deformer()
|
|
||||||
|
|
||||||
def test_sanity(self):
|
deformer = Deformer()
|
||||||
|
|
||||||
ImageOps.autocontrast(hopper("L"))
|
|
||||||
ImageOps.autocontrast(hopper("RGB"))
|
|
||||||
|
|
||||||
ImageOps.autocontrast(hopper("L"), cutoff=10)
|
def test_sanity():
|
||||||
ImageOps.autocontrast(hopper("L"), ignore=[0, 255])
|
|
||||||
|
|
||||||
ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255))
|
ImageOps.autocontrast(hopper("L"))
|
||||||
ImageOps.colorize(hopper("L"), "black", "white")
|
ImageOps.autocontrast(hopper("RGB"))
|
||||||
|
|
||||||
ImageOps.pad(hopper("L"), (128, 128))
|
ImageOps.autocontrast(hopper("L"), cutoff=10)
|
||||||
ImageOps.pad(hopper("RGB"), (128, 128))
|
ImageOps.autocontrast(hopper("L"), ignore=[0, 255])
|
||||||
|
|
||||||
ImageOps.crop(hopper("L"), 1)
|
ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255))
|
||||||
ImageOps.crop(hopper("RGB"), 1)
|
ImageOps.colorize(hopper("L"), "black", "white")
|
||||||
|
|
||||||
ImageOps.deform(hopper("L"), self.deformer)
|
ImageOps.pad(hopper("L"), (128, 128))
|
||||||
ImageOps.deform(hopper("RGB"), self.deformer)
|
ImageOps.pad(hopper("RGB"), (128, 128))
|
||||||
|
|
||||||
ImageOps.equalize(hopper("L"))
|
ImageOps.crop(hopper("L"), 1)
|
||||||
ImageOps.equalize(hopper("RGB"))
|
ImageOps.crop(hopper("RGB"), 1)
|
||||||
|
|
||||||
ImageOps.expand(hopper("L"), 1)
|
ImageOps.deform(hopper("L"), deformer)
|
||||||
ImageOps.expand(hopper("RGB"), 1)
|
ImageOps.deform(hopper("RGB"), deformer)
|
||||||
ImageOps.expand(hopper("L"), 2, "blue")
|
|
||||||
ImageOps.expand(hopper("RGB"), 2, "blue")
|
|
||||||
|
|
||||||
ImageOps.fit(hopper("L"), (128, 128))
|
ImageOps.equalize(hopper("L"))
|
||||||
ImageOps.fit(hopper("RGB"), (128, 128))
|
ImageOps.equalize(hopper("RGB"))
|
||||||
|
|
||||||
ImageOps.flip(hopper("L"))
|
ImageOps.expand(hopper("L"), 1)
|
||||||
ImageOps.flip(hopper("RGB"))
|
ImageOps.expand(hopper("RGB"), 1)
|
||||||
|
ImageOps.expand(hopper("L"), 2, "blue")
|
||||||
|
ImageOps.expand(hopper("RGB"), 2, "blue")
|
||||||
|
|
||||||
ImageOps.grayscale(hopper("L"))
|
ImageOps.fit(hopper("L"), (128, 128))
|
||||||
ImageOps.grayscale(hopper("RGB"))
|
ImageOps.fit(hopper("RGB"), (128, 128))
|
||||||
|
|
||||||
ImageOps.invert(hopper("L"))
|
ImageOps.flip(hopper("L"))
|
||||||
ImageOps.invert(hopper("RGB"))
|
ImageOps.flip(hopper("RGB"))
|
||||||
|
|
||||||
ImageOps.mirror(hopper("L"))
|
ImageOps.grayscale(hopper("L"))
|
||||||
ImageOps.mirror(hopper("RGB"))
|
ImageOps.grayscale(hopper("RGB"))
|
||||||
|
|
||||||
ImageOps.posterize(hopper("L"), 4)
|
ImageOps.invert(hopper("L"))
|
||||||
ImageOps.posterize(hopper("RGB"), 4)
|
ImageOps.invert(hopper("RGB"))
|
||||||
|
|
||||||
ImageOps.solarize(hopper("L"))
|
ImageOps.mirror(hopper("L"))
|
||||||
ImageOps.solarize(hopper("RGB"))
|
ImageOps.mirror(hopper("RGB"))
|
||||||
|
|
||||||
ImageOps.exif_transpose(hopper("L"))
|
ImageOps.posterize(hopper("L"), 4)
|
||||||
ImageOps.exif_transpose(hopper("RGB"))
|
ImageOps.posterize(hopper("RGB"), 4)
|
||||||
|
|
||||||
def test_1pxfit(self):
|
ImageOps.solarize(hopper("L"))
|
||||||
# Division by zero in equalize if image is 1 pixel high
|
ImageOps.solarize(hopper("RGB"))
|
||||||
newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35))
|
|
||||||
self.assertEqual(newimg.size, (35, 35))
|
|
||||||
|
|
||||||
newimg = ImageOps.fit(hopper("RGB").resize((1, 100)), (35, 35))
|
ImageOps.exif_transpose(hopper("L"))
|
||||||
self.assertEqual(newimg.size, (35, 35))
|
ImageOps.exif_transpose(hopper("RGB"))
|
||||||
|
|
||||||
newimg = ImageOps.fit(hopper("RGB").resize((100, 1)), (35, 35))
|
|
||||||
self.assertEqual(newimg.size, (35, 35))
|
|
||||||
|
|
||||||
def test_fit_same_ratio(self):
|
def test_1pxfit():
|
||||||
# The ratio for this image is 1000.0 / 755 = 1.3245033112582782
|
# Division by zero in equalize if image is 1 pixel high
|
||||||
# If the ratios are not acknowledged to be the same,
|
newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35))
|
||||||
# and Pillow attempts to adjust the width to
|
assert newimg.size == (35, 35)
|
||||||
# 1.3245033112582782 * 755 = 1000.0000000000001
|
|
||||||
# then centering this greater width causes a negative x offset when cropping
|
|
||||||
with Image.new("RGB", (1000, 755)) as im:
|
|
||||||
new_im = ImageOps.fit(im, (1000, 755))
|
|
||||||
self.assertEqual(new_im.size, (1000, 755))
|
|
||||||
|
|
||||||
def test_pad(self):
|
newimg = ImageOps.fit(hopper("RGB").resize((1, 100)), (35, 35))
|
||||||
# Same ratio
|
assert newimg.size == (35, 35)
|
||||||
im = hopper()
|
|
||||||
new_size = (im.width * 2, im.height * 2)
|
|
||||||
new_im = ImageOps.pad(im, new_size)
|
|
||||||
self.assertEqual(new_im.size, new_size)
|
|
||||||
|
|
||||||
for label, color, new_size in [
|
newimg = ImageOps.fit(hopper("RGB").resize((100, 1)), (35, 35))
|
||||||
("h", None, (im.width * 4, im.height * 2)),
|
assert newimg.size == (35, 35)
|
||||||
("v", "#f00", (im.width * 2, im.height * 4)),
|
|
||||||
]:
|
|
||||||
for i, centering in enumerate([(0, 0), (0.5, 0.5), (1, 1)]):
|
|
||||||
new_im = ImageOps.pad(im, new_size, color=color, centering=centering)
|
|
||||||
self.assertEqual(new_im.size, new_size)
|
|
||||||
|
|
||||||
|
|
||||||
|
def test_fit_same_ratio():
|
||||||
|
# The ratio for this image is 1000.0 / 755 = 1.3245033112582782
|
||||||
|
# If the ratios are not acknowledged to be the same,
|
||||||
|
# and Pillow attempts to adjust the width to
|
||||||
|
# 1.3245033112582782 * 755 = 1000.0000000000001
|
||||||
|
# then centering this greater width causes a negative x offset when cropping
|
||||||
|
with Image.new("RGB", (1000, 755)) as im:
|
||||||
|
new_im = ImageOps.fit(im, (1000, 755))
|
||||||
|
assert new_im.size == (1000, 755)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pad():
|
||||||
|
# Same ratio
|
||||||
|
im = hopper()
|
||||||
|
new_size = (im.width * 2, im.height * 2)
|
||||||
|
new_im = ImageOps.pad(im, new_size)
|
||||||
|
assert new_im.size == new_size
|
||||||
|
|
||||||
|
for label, color, new_size in [
|
||||||
|
("h", None, (im.width * 4, im.height * 2)),
|
||||||
|
("v", "#f00", (im.width * 2, im.height * 4)),
|
||||||
|
]:
|
||||||
|
for i, centering in enumerate([(0, 0), (0.5, 0.5), (1, 1)]):
|
||||||
|
new_im = ImageOps.pad(im, new_size, color=color, centering=centering)
|
||||||
|
assert new_im.size == new_size
|
||||||
|
|
||||||
|
with Image.open(
|
||||||
|
"Tests/images/imageops_pad_" + label + "_" + str(i) + ".jpg"
|
||||||
|
) as target:
|
||||||
|
assert_image_similar(new_im, target, 6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pil163():
|
||||||
|
# Division by zero in equalize if < 255 pixels in image (@PIL163)
|
||||||
|
|
||||||
|
i = hopper("RGB").resize((15, 16))
|
||||||
|
|
||||||
|
ImageOps.equalize(i.convert("L"))
|
||||||
|
ImageOps.equalize(i.convert("P"))
|
||||||
|
ImageOps.equalize(i.convert("RGB"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_scale():
|
||||||
|
# Test the scaling function
|
||||||
|
i = hopper("L").resize((50, 50))
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
ImageOps.scale(i, -1)
|
||||||
|
|
||||||
|
newimg = ImageOps.scale(i, 1)
|
||||||
|
assert newimg.size == (50, 50)
|
||||||
|
|
||||||
|
newimg = ImageOps.scale(i, 2)
|
||||||
|
assert newimg.size == (100, 100)
|
||||||
|
|
||||||
|
newimg = ImageOps.scale(i, 0.5)
|
||||||
|
assert newimg.size == (25, 25)
|
||||||
|
|
||||||
|
|
||||||
|
def test_colorize_2color():
|
||||||
|
# Test the colorizing function with 2-color functionality
|
||||||
|
|
||||||
|
# Open test image (256px by 10px, black to white)
|
||||||
|
with Image.open("Tests/images/bw_gradient.png") as im:
|
||||||
|
im = im.convert("L")
|
||||||
|
|
||||||
|
# Create image with original 2-color functionality
|
||||||
|
im_test = ImageOps.colorize(im, "red", "green")
|
||||||
|
|
||||||
|
# Test output image (2-color)
|
||||||
|
left = (0, 1)
|
||||||
|
middle = (127, 1)
|
||||||
|
right = (255, 1)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(left),
|
||||||
|
(255, 0, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="black test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(middle),
|
||||||
|
(127, 63, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="mid test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(right),
|
||||||
|
(0, 127, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="white test pixel incorrect",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_colorize_2color_offset():
|
||||||
|
# Test the colorizing function with 2-color functionality and offset
|
||||||
|
|
||||||
|
# Open test image (256px by 10px, black to white)
|
||||||
|
with Image.open("Tests/images/bw_gradient.png") as im:
|
||||||
|
im = im.convert("L")
|
||||||
|
|
||||||
|
# Create image with original 2-color functionality with offsets
|
||||||
|
im_test = ImageOps.colorize(
|
||||||
|
im, black="red", white="green", blackpoint=50, whitepoint=100
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test output image (2-color) with offsets
|
||||||
|
left = (25, 1)
|
||||||
|
middle = (75, 1)
|
||||||
|
right = (125, 1)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(left),
|
||||||
|
(255, 0, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="black test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(middle),
|
||||||
|
(127, 63, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="mid test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(right),
|
||||||
|
(0, 127, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="white test pixel incorrect",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_colorize_3color_offset():
|
||||||
|
# Test the colorizing function with 3-color functionality and offset
|
||||||
|
|
||||||
|
# Open test image (256px by 10px, black to white)
|
||||||
|
with Image.open("Tests/images/bw_gradient.png") as im:
|
||||||
|
im = im.convert("L")
|
||||||
|
|
||||||
|
# Create image with new three color functionality with offsets
|
||||||
|
im_test = ImageOps.colorize(
|
||||||
|
im,
|
||||||
|
black="red",
|
||||||
|
white="green",
|
||||||
|
mid="blue",
|
||||||
|
blackpoint=50,
|
||||||
|
whitepoint=200,
|
||||||
|
midpoint=100,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test output image (3-color) with offsets
|
||||||
|
left = (25, 1)
|
||||||
|
left_middle = (75, 1)
|
||||||
|
middle = (100, 1)
|
||||||
|
right_middle = (150, 1)
|
||||||
|
right = (225, 1)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(left),
|
||||||
|
(255, 0, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="black test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(left_middle),
|
||||||
|
(127, 0, 127),
|
||||||
|
threshold=1,
|
||||||
|
msg="low-mid test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(middle), (0, 0, 255), threshold=1, msg="mid incorrect"
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(right_middle),
|
||||||
|
(0, 63, 127),
|
||||||
|
threshold=1,
|
||||||
|
msg="high-mid test pixel incorrect",
|
||||||
|
)
|
||||||
|
assert_tuple_approx_equal(
|
||||||
|
im_test.getpixel(right),
|
||||||
|
(0, 127, 0),
|
||||||
|
threshold=1,
|
||||||
|
msg="white test pixel incorrect",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_exif_transpose():
|
||||||
|
exts = [".jpg"]
|
||||||
|
if HAVE_WEBP and _webp.HAVE_WEBPANIM:
|
||||||
|
exts.append(".webp")
|
||||||
|
for ext in exts:
|
||||||
|
with Image.open("Tests/images/hopper" + ext) as base_im:
|
||||||
|
|
||||||
|
def check(orientation_im):
|
||||||
|
for im in [
|
||||||
|
orientation_im,
|
||||||
|
orientation_im.copy(),
|
||||||
|
]: # ImageFile # Image
|
||||||
|
if orientation_im is base_im:
|
||||||
|
assert "exif" not in im.info
|
||||||
|
else:
|
||||||
|
original_exif = im.info["exif"]
|
||||||
|
transposed_im = ImageOps.exif_transpose(im)
|
||||||
|
assert_image_similar(base_im, transposed_im, 17)
|
||||||
|
if orientation_im is base_im:
|
||||||
|
assert "exif" not in im.info
|
||||||
|
else:
|
||||||
|
assert transposed_im.info["exif"] != original_exif
|
||||||
|
|
||||||
|
assert 0x0112 not in transposed_im.getexif()
|
||||||
|
|
||||||
|
# Repeat the operation to test that it does not keep transposing
|
||||||
|
transposed_im2 = ImageOps.exif_transpose(transposed_im)
|
||||||
|
assert_image_equal(transposed_im2, transposed_im)
|
||||||
|
|
||||||
|
check(base_im)
|
||||||
|
for i in range(2, 9):
|
||||||
with Image.open(
|
with Image.open(
|
||||||
"Tests/images/imageops_pad_" + label + "_" + str(i) + ".jpg"
|
"Tests/images/hopper_orientation_" + str(i) + ext
|
||||||
) as target:
|
) as orientation_im:
|
||||||
assert_image_similar(new_im, target, 6)
|
check(orientation_im)
|
||||||
|
|
||||||
def test_pil163(self):
|
|
||||||
# Division by zero in equalize if < 255 pixels in image (@PIL163)
|
|
||||||
|
|
||||||
i = hopper("RGB").resize((15, 16))
|
|
||||||
|
|
||||||
ImageOps.equalize(i.convert("L"))
|
|
||||||
ImageOps.equalize(i.convert("P"))
|
|
||||||
ImageOps.equalize(i.convert("RGB"))
|
|
||||||
|
|
||||||
def test_scale(self):
|
|
||||||
# Test the scaling function
|
|
||||||
i = hopper("L").resize((50, 50))
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
|
||||||
ImageOps.scale(i, -1)
|
|
||||||
|
|
||||||
newimg = ImageOps.scale(i, 1)
|
|
||||||
self.assertEqual(newimg.size, (50, 50))
|
|
||||||
|
|
||||||
newimg = ImageOps.scale(i, 2)
|
|
||||||
self.assertEqual(newimg.size, (100, 100))
|
|
||||||
|
|
||||||
newimg = ImageOps.scale(i, 0.5)
|
|
||||||
self.assertEqual(newimg.size, (25, 25))
|
|
||||||
|
|
||||||
def test_colorize_2color(self):
|
|
||||||
# Test the colorizing function with 2-color functionality
|
|
||||||
|
|
||||||
# Open test image (256px by 10px, black to white)
|
|
||||||
with Image.open("Tests/images/bw_gradient.png") as im:
|
|
||||||
im = im.convert("L")
|
|
||||||
|
|
||||||
# Create image with original 2-color functionality
|
|
||||||
im_test = ImageOps.colorize(im, "red", "green")
|
|
||||||
|
|
||||||
# Test output image (2-color)
|
|
||||||
left = (0, 1)
|
|
||||||
middle = (127, 1)
|
|
||||||
right = (255, 1)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(left),
|
|
||||||
(255, 0, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="black test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(middle),
|
|
||||||
(127, 63, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="mid test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(right),
|
|
||||||
(0, 127, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="white test pixel incorrect",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_colorize_2color_offset(self):
|
|
||||||
# Test the colorizing function with 2-color functionality and offset
|
|
||||||
|
|
||||||
# Open test image (256px by 10px, black to white)
|
|
||||||
with Image.open("Tests/images/bw_gradient.png") as im:
|
|
||||||
im = im.convert("L")
|
|
||||||
|
|
||||||
# Create image with original 2-color functionality with offsets
|
|
||||||
im_test = ImageOps.colorize(
|
|
||||||
im, black="red", white="green", blackpoint=50, whitepoint=100
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test output image (2-color) with offsets
|
|
||||||
left = (25, 1)
|
|
||||||
middle = (75, 1)
|
|
||||||
right = (125, 1)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(left),
|
|
||||||
(255, 0, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="black test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(middle),
|
|
||||||
(127, 63, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="mid test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(right),
|
|
||||||
(0, 127, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="white test pixel incorrect",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_colorize_3color_offset(self):
|
|
||||||
# Test the colorizing function with 3-color functionality and offset
|
|
||||||
|
|
||||||
# Open test image (256px by 10px, black to white)
|
|
||||||
with Image.open("Tests/images/bw_gradient.png") as im:
|
|
||||||
im = im.convert("L")
|
|
||||||
|
|
||||||
# Create image with new three color functionality with offsets
|
|
||||||
im_test = ImageOps.colorize(
|
|
||||||
im,
|
|
||||||
black="red",
|
|
||||||
white="green",
|
|
||||||
mid="blue",
|
|
||||||
blackpoint=50,
|
|
||||||
whitepoint=200,
|
|
||||||
midpoint=100,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test output image (3-color) with offsets
|
|
||||||
left = (25, 1)
|
|
||||||
left_middle = (75, 1)
|
|
||||||
middle = (100, 1)
|
|
||||||
right_middle = (150, 1)
|
|
||||||
right = (225, 1)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(left),
|
|
||||||
(255, 0, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="black test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(left_middle),
|
|
||||||
(127, 0, 127),
|
|
||||||
threshold=1,
|
|
||||||
msg="low-mid test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(middle), (0, 0, 255), threshold=1, msg="mid incorrect"
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(right_middle),
|
|
||||||
(0, 63, 127),
|
|
||||||
threshold=1,
|
|
||||||
msg="high-mid test pixel incorrect",
|
|
||||||
)
|
|
||||||
assert_tuple_approx_equal(
|
|
||||||
im_test.getpixel(right),
|
|
||||||
(0, 127, 0),
|
|
||||||
threshold=1,
|
|
||||||
msg="white test pixel incorrect",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_exif_transpose(self):
|
|
||||||
exts = [".jpg"]
|
|
||||||
if HAVE_WEBP and _webp.HAVE_WEBPANIM:
|
|
||||||
exts.append(".webp")
|
|
||||||
for ext in exts:
|
|
||||||
with Image.open("Tests/images/hopper" + ext) as base_im:
|
|
||||||
|
|
||||||
def check(orientation_im):
|
|
||||||
for im in [
|
|
||||||
orientation_im,
|
|
||||||
orientation_im.copy(),
|
|
||||||
]: # ImageFile # Image
|
|
||||||
if orientation_im is base_im:
|
|
||||||
self.assertNotIn("exif", im.info)
|
|
||||||
else:
|
|
||||||
original_exif = im.info["exif"]
|
|
||||||
transposed_im = ImageOps.exif_transpose(im)
|
|
||||||
assert_image_similar(base_im, transposed_im, 17)
|
|
||||||
if orientation_im is base_im:
|
|
||||||
self.assertNotIn("exif", im.info)
|
|
||||||
else:
|
|
||||||
self.assertNotEqual(
|
|
||||||
transposed_im.info["exif"], original_exif
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertNotIn(0x0112, transposed_im.getexif())
|
|
||||||
|
|
||||||
# Repeat the operation
|
|
||||||
# to test that it does not keep transposing
|
|
||||||
transposed_im2 = ImageOps.exif_transpose(transposed_im)
|
|
||||||
assert_image_equal(transposed_im2, transposed_im)
|
|
||||||
|
|
||||||
check(base_im)
|
|
||||||
for i in range(2, 9):
|
|
||||||
with Image.open(
|
|
||||||
"Tests/images/hopper_orientation_" + str(i) + ext
|
|
||||||
) as orientation_im:
|
|
||||||
check(orientation_im)
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import unittest
|
import pytest
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import ImageTk
|
from PIL import ImageTk
|
||||||
|
@ -12,76 +11,81 @@ try:
|
||||||
dir(ImageTk)
|
dir(ImageTk)
|
||||||
HAS_TK = True
|
HAS_TK = True
|
||||||
except (OSError, ImportError):
|
except (OSError, ImportError):
|
||||||
# Skipped via setUp()
|
# Skipped via pytestmark
|
||||||
HAS_TK = False
|
HAS_TK = False
|
||||||
|
|
||||||
TK_MODES = ("1", "L", "P", "RGB", "RGBA")
|
TK_MODES = ("1", "L", "P", "RGB", "RGBA")
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_TK, "Tk not installed")
|
pytestmark = pytest.mark.skipif(not HAS_TK, reason="Tk not installed")
|
||||||
class TestImageTk(PillowTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
try:
|
|
||||||
# setup tk
|
|
||||||
tk.Frame()
|
|
||||||
# root = tk.Tk()
|
|
||||||
except tk.TclError as v:
|
|
||||||
self.skipTest("TCL Error: %s" % v)
|
|
||||||
|
|
||||||
def test_kw(self):
|
|
||||||
TEST_JPG = "Tests/images/hopper.jpg"
|
|
||||||
TEST_PNG = "Tests/images/hopper.png"
|
|
||||||
with Image.open(TEST_JPG) as im1:
|
|
||||||
with Image.open(TEST_PNG) as im2:
|
|
||||||
with open(TEST_PNG, "rb") as fp:
|
|
||||||
data = fp.read()
|
|
||||||
kw = {"file": TEST_JPG, "data": data}
|
|
||||||
|
|
||||||
# Test "file"
|
def setup_module():
|
||||||
im = ImageTk._get_image_from_kw(kw)
|
try:
|
||||||
assert_image_equal(im, im1)
|
# setup tk
|
||||||
|
tk.Frame()
|
||||||
|
# root = tk.Tk()
|
||||||
|
except tk.TclError as v:
|
||||||
|
pytest.skip("TCL Error: %s" % v)
|
||||||
|
|
||||||
# Test "data"
|
|
||||||
im = ImageTk._get_image_from_kw(kw)
|
|
||||||
assert_image_equal(im, im2)
|
|
||||||
|
|
||||||
# Test no relevant entry
|
def test_kw():
|
||||||
im = ImageTk._get_image_from_kw(kw)
|
TEST_JPG = "Tests/images/hopper.jpg"
|
||||||
self.assertIsNone(im)
|
TEST_PNG = "Tests/images/hopper.png"
|
||||||
|
with Image.open(TEST_JPG) as im1:
|
||||||
|
with Image.open(TEST_PNG) as im2:
|
||||||
|
with open(TEST_PNG, "rb") as fp:
|
||||||
|
data = fp.read()
|
||||||
|
kw = {"file": TEST_JPG, "data": data}
|
||||||
|
|
||||||
def test_photoimage(self):
|
# Test "file"
|
||||||
for mode in TK_MODES:
|
im = ImageTk._get_image_from_kw(kw)
|
||||||
# test as image:
|
assert_image_equal(im, im1)
|
||||||
im = hopper(mode)
|
|
||||||
|
|
||||||
# this should not crash
|
# Test "data"
|
||||||
im_tk = ImageTk.PhotoImage(im)
|
im = ImageTk._get_image_from_kw(kw)
|
||||||
|
assert_image_equal(im, im2)
|
||||||
|
|
||||||
self.assertEqual(im_tk.width(), im.width)
|
# Test no relevant entry
|
||||||
self.assertEqual(im_tk.height(), im.height)
|
im = ImageTk._get_image_from_kw(kw)
|
||||||
|
assert im is None
|
||||||
|
|
||||||
reloaded = ImageTk.getimage(im_tk)
|
|
||||||
assert_image_equal(reloaded, im.convert("RGBA"))
|
|
||||||
|
|
||||||
def test_photoimage_blank(self):
|
def test_photoimage():
|
||||||
# test a image using mode/size:
|
for mode in TK_MODES:
|
||||||
for mode in TK_MODES:
|
# test as image:
|
||||||
im_tk = ImageTk.PhotoImage(mode, (100, 100))
|
im = hopper(mode)
|
||||||
|
|
||||||
self.assertEqual(im_tk.width(), 100)
|
|
||||||
self.assertEqual(im_tk.height(), 100)
|
|
||||||
|
|
||||||
# reloaded = ImageTk.getimage(im_tk)
|
|
||||||
# assert_image_equal(reloaded, im)
|
|
||||||
|
|
||||||
def test_bitmapimage(self):
|
|
||||||
im = hopper("1")
|
|
||||||
|
|
||||||
# this should not crash
|
# this should not crash
|
||||||
im_tk = ImageTk.BitmapImage(im)
|
im_tk = ImageTk.PhotoImage(im)
|
||||||
|
|
||||||
self.assertEqual(im_tk.width(), im.width)
|
assert im_tk.width() == im.width
|
||||||
self.assertEqual(im_tk.height(), im.height)
|
assert im_tk.height() == im.height
|
||||||
|
|
||||||
|
reloaded = ImageTk.getimage(im_tk)
|
||||||
|
assert_image_equal(reloaded, im.convert("RGBA"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_photoimage_blank():
|
||||||
|
# test a image using mode/size:
|
||||||
|
for mode in TK_MODES:
|
||||||
|
im_tk = ImageTk.PhotoImage(mode, (100, 100))
|
||||||
|
|
||||||
|
assert im_tk.width() == 100
|
||||||
|
assert im_tk.height() == 100
|
||||||
|
|
||||||
# reloaded = ImageTk.getimage(im_tk)
|
# reloaded = ImageTk.getimage(im_tk)
|
||||||
# assert_image_equal(reloaded, im)
|
# assert_image_equal(reloaded, im)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bitmapimage():
|
||||||
|
im = hopper("1")
|
||||||
|
|
||||||
|
# this should not crash
|
||||||
|
im_tk = ImageTk.BitmapImage(im)
|
||||||
|
|
||||||
|
assert im_tk.width() == im.width
|
||||||
|
assert im_tk.height() == im.height
|
||||||
|
|
||||||
|
# reloaded = ImageTk.getimage(im_tk)
|
||||||
|
# assert_image_equal(reloaded, im)
|
||||||
|
|
|
@ -1,38 +1,39 @@
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, is_win32
|
from .helper import is_win32
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpy
|
import numpy
|
||||||
except ImportError:
|
except ImportError:
|
||||||
numpy = None
|
numpy = None
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.skipif(is_win32(), reason="Win32 does not call map_buffer")
|
||||||
|
|
||||||
@unittest.skipIf(is_win32(), "Win32 does not call map_buffer")
|
|
||||||
class TestMap(PillowTestCase):
|
|
||||||
def test_overflow(self):
|
|
||||||
# There is the potential to overflow comparisons in map.c
|
|
||||||
# if there are > SIZE_MAX bytes in the image or if
|
|
||||||
# the file encodes an offset that makes
|
|
||||||
# (offset + size(bytes)) > SIZE_MAX
|
|
||||||
|
|
||||||
# Note that this image triggers the decompression bomb warning:
|
def test_overflow():
|
||||||
max_pixels = Image.MAX_IMAGE_PIXELS
|
# There is the potential to overflow comparisons in map.c
|
||||||
Image.MAX_IMAGE_PIXELS = None
|
# if there are > SIZE_MAX bytes in the image or if
|
||||||
|
# the file encodes an offset that makes
|
||||||
|
# (offset + size(bytes)) > SIZE_MAX
|
||||||
|
|
||||||
# This image hits the offset test.
|
# Note that this image triggers the decompression bomb warning:
|
||||||
with Image.open("Tests/images/l2rgb_read.bmp") as im:
|
max_pixels = Image.MAX_IMAGE_PIXELS
|
||||||
with self.assertRaises((ValueError, MemoryError, IOError)):
|
Image.MAX_IMAGE_PIXELS = None
|
||||||
im.load()
|
|
||||||
|
|
||||||
Image.MAX_IMAGE_PIXELS = max_pixels
|
# This image hits the offset test.
|
||||||
|
with Image.open("Tests/images/l2rgb_read.bmp") as im:
|
||||||
|
with pytest.raises((ValueError, MemoryError, IOError)):
|
||||||
|
im.load()
|
||||||
|
|
||||||
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
Image.MAX_IMAGE_PIXELS = max_pixels
|
||||||
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
|
||||||
def test_ysize(self):
|
|
||||||
# Should not raise 'Integer overflow in ysize'
|
@pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system")
|
||||||
arr = numpy.zeros((46341, 46341), dtype=numpy.uint8)
|
@pytest.mark.skipif(numpy is None, reason="NumPy is not installed")
|
||||||
Image.fromarray(arr)
|
def test_ysize():
|
||||||
|
# Should not raise 'Integer overflow in ysize'
|
||||||
|
arr = numpy.zeros((46341, 46341), dtype=numpy.uint8)
|
||||||
|
Image.fromarray(arr)
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, assert_deep_equal, assert_image, hopper
|
from .helper import assert_deep_equal, assert_image, hopper
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpy
|
import numpy
|
||||||
|
@ -14,211 +12,227 @@ except ImportError:
|
||||||
TEST_IMAGE_SIZE = (10, 10)
|
TEST_IMAGE_SIZE = (10, 10)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
pytestmark = pytest.mark.skipif(numpy is None, reason="NumPy is not installed")
|
||||||
class TestNumpy(PillowTestCase):
|
|
||||||
def test_numpy_to_image(self):
|
|
||||||
def to_image(dtype, bands=1, boolean=0):
|
def test_numpy_to_image():
|
||||||
if bands == 1:
|
def to_image(dtype, bands=1, boolean=0):
|
||||||
if boolean:
|
if bands == 1:
|
||||||
data = [0, 255] * 50
|
if boolean:
|
||||||
else:
|
data = [0, 255] * 50
|
||||||
data = list(range(100))
|
|
||||||
a = numpy.array(data, dtype=dtype)
|
|
||||||
a.shape = TEST_IMAGE_SIZE
|
|
||||||
i = Image.fromarray(a)
|
|
||||||
if list(i.getdata()) != data:
|
|
||||||
print("data mismatch for", dtype)
|
|
||||||
else:
|
else:
|
||||||
data = list(range(100))
|
data = list(range(100))
|
||||||
a = numpy.array([[x] * bands for x in data], dtype=dtype)
|
a = numpy.array(data, dtype=dtype)
|
||||||
a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands
|
a.shape = TEST_IMAGE_SIZE
|
||||||
i = Image.fromarray(a)
|
i = Image.fromarray(a)
|
||||||
if list(i.getchannel(0).getdata()) != list(range(100)):
|
if list(i.getdata()) != data:
|
||||||
print("data mismatch for", dtype)
|
print("data mismatch for", dtype)
|
||||||
return i
|
|
||||||
|
|
||||||
# Check supported 1-bit integer formats
|
|
||||||
assert_image(to_image(numpy.bool, 1, 1), "1", TEST_IMAGE_SIZE)
|
|
||||||
assert_image(to_image(numpy.bool8, 1, 1), "1", TEST_IMAGE_SIZE)
|
|
||||||
|
|
||||||
# Check supported 8-bit integer formats
|
|
||||||
assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
|
|
||||||
assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE)
|
|
||||||
assert_image(to_image(numpy.uint8, 4), "RGBA", TEST_IMAGE_SIZE)
|
|
||||||
assert_image(to_image(numpy.int8), "I", TEST_IMAGE_SIZE)
|
|
||||||
|
|
||||||
# Check non-fixed-size integer types
|
|
||||||
# These may fail, depending on the platform, since we have no native
|
|
||||||
# 64 bit int image types.
|
|
||||||
# assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE)
|
|
||||||
# assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE)
|
|
||||||
|
|
||||||
# Check 16-bit integer formats
|
|
||||||
if Image._ENDIAN == "<":
|
|
||||||
assert_image(to_image(numpy.uint16), "I;16", TEST_IMAGE_SIZE)
|
|
||||||
else:
|
else:
|
||||||
assert_image(to_image(numpy.uint16), "I;16B", TEST_IMAGE_SIZE)
|
data = list(range(100))
|
||||||
|
a = numpy.array([[x] * bands for x in data], dtype=dtype)
|
||||||
|
a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands
|
||||||
|
i = Image.fromarray(a)
|
||||||
|
if list(i.getchannel(0).getdata()) != list(range(100)):
|
||||||
|
print("data mismatch for", dtype)
|
||||||
|
return i
|
||||||
|
|
||||||
assert_image(to_image(numpy.int16), "I", TEST_IMAGE_SIZE)
|
# Check supported 1-bit integer formats
|
||||||
|
assert_image(to_image(numpy.bool, 1, 1), "1", TEST_IMAGE_SIZE)
|
||||||
|
assert_image(to_image(numpy.bool8, 1, 1), "1", TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
# Check 32-bit integer formats
|
# Check supported 8-bit integer formats
|
||||||
assert_image(to_image(numpy.uint32), "I", TEST_IMAGE_SIZE)
|
assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
|
||||||
assert_image(to_image(numpy.int32), "I", TEST_IMAGE_SIZE)
|
assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE)
|
||||||
|
assert_image(to_image(numpy.uint8, 4), "RGBA", TEST_IMAGE_SIZE)
|
||||||
|
assert_image(to_image(numpy.int8), "I", TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
# Check 64-bit integer formats
|
# Check non-fixed-size integer types
|
||||||
self.assertRaises(TypeError, to_image, numpy.uint64)
|
# These may fail, depending on the platform, since we have no native
|
||||||
self.assertRaises(TypeError, to_image, numpy.int64)
|
# 64-bit int image types.
|
||||||
|
# assert_image(to_image(numpy.uint), "I", TEST_IMAGE_SIZE)
|
||||||
|
# assert_image(to_image(numpy.int), "I", TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
# Check floating-point formats
|
# Check 16-bit integer formats
|
||||||
assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE)
|
if Image._ENDIAN == "<":
|
||||||
self.assertRaises(TypeError, to_image, numpy.float16)
|
assert_image(to_image(numpy.uint16), "I;16", TEST_IMAGE_SIZE)
|
||||||
assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE)
|
else:
|
||||||
assert_image(to_image(numpy.float64), "F", TEST_IMAGE_SIZE)
|
assert_image(to_image(numpy.uint16), "I;16B", TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
assert_image(to_image(numpy.uint8, 2), "LA", (10, 10))
|
assert_image(to_image(numpy.int16), "I", TEST_IMAGE_SIZE)
|
||||||
assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10))
|
|
||||||
assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10))
|
|
||||||
|
|
||||||
# based on an erring example at
|
# Check 32-bit integer formats
|
||||||
# https://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function
|
assert_image(to_image(numpy.uint32), "I", TEST_IMAGE_SIZE)
|
||||||
def test_3d_array(self):
|
assert_image(to_image(numpy.int32), "I", TEST_IMAGE_SIZE)
|
||||||
size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1])
|
|
||||||
a = numpy.ones(size, dtype=numpy.uint8)
|
|
||||||
assert_image(Image.fromarray(a[1, :, :]), "L", TEST_IMAGE_SIZE)
|
|
||||||
size = (TEST_IMAGE_SIZE[0], 5, TEST_IMAGE_SIZE[1])
|
|
||||||
a = numpy.ones(size, dtype=numpy.uint8)
|
|
||||||
assert_image(Image.fromarray(a[:, 1, :]), "L", TEST_IMAGE_SIZE)
|
|
||||||
size = (TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], 5)
|
|
||||||
a = numpy.ones(size, dtype=numpy.uint8)
|
|
||||||
assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE)
|
|
||||||
|
|
||||||
def _test_img_equals_nparray(self, img, np):
|
# Check 64-bit integer formats
|
||||||
self.assertGreaterEqual(len(np.shape), 2)
|
with pytest.raises(TypeError):
|
||||||
np_size = np.shape[1], np.shape[0]
|
to_image(numpy.uint64)
|
||||||
self.assertEqual(img.size, np_size)
|
with pytest.raises(TypeError):
|
||||||
px = img.load()
|
to_image(numpy.int64)
|
||||||
for x in range(0, img.size[0], int(img.size[0] / 10)):
|
|
||||||
for y in range(0, img.size[1], int(img.size[1] / 10)):
|
|
||||||
assert_deep_equal(px[x, y], np[y, x])
|
|
||||||
|
|
||||||
def test_16bit(self):
|
# Check floating-point formats
|
||||||
with Image.open("Tests/images/16bit.cropped.tif") as img:
|
assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE)
|
||||||
np_img = numpy.array(img)
|
with pytest.raises(TypeError):
|
||||||
self._test_img_equals_nparray(img, np_img)
|
to_image(numpy.float16)
|
||||||
self.assertEqual(np_img.dtype, numpy.dtype("<u2"))
|
assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE)
|
||||||
|
assert_image(to_image(numpy.float64), "F", TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
def test_1bit(self):
|
assert_image(to_image(numpy.uint8, 2), "LA", (10, 10))
|
||||||
# Test that 1-bit arrays convert to numpy and back
|
assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10))
|
||||||
# See: https://github.com/python-pillow/Pillow/issues/350
|
assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10))
|
||||||
arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], "u1")
|
|
||||||
img = Image.fromarray(arr * 255).convert("1")
|
|
||||||
self.assertEqual(img.mode, "1")
|
|
||||||
arr_back = numpy.array(img)
|
|
||||||
numpy.testing.assert_array_equal(arr, arr_back)
|
|
||||||
|
|
||||||
def test_save_tiff_uint16(self):
|
|
||||||
# Tests that we're getting the pixel value in the right byte order.
|
|
||||||
pixel_value = 0x1234
|
|
||||||
a = numpy.array(
|
|
||||||
[pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16
|
|
||||||
)
|
|
||||||
a.shape = TEST_IMAGE_SIZE
|
|
||||||
img = Image.fromarray(a)
|
|
||||||
|
|
||||||
img_px = img.load()
|
# Based on an erring example at
|
||||||
self.assertEqual(img_px[0, 0], pixel_value)
|
# https://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function
|
||||||
|
def test_3d_array():
|
||||||
|
size = (5, TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1])
|
||||||
|
a = numpy.ones(size, dtype=numpy.uint8)
|
||||||
|
assert_image(Image.fromarray(a[1, :, :]), "L", TEST_IMAGE_SIZE)
|
||||||
|
size = (TEST_IMAGE_SIZE[0], 5, TEST_IMAGE_SIZE[1])
|
||||||
|
a = numpy.ones(size, dtype=numpy.uint8)
|
||||||
|
assert_image(Image.fromarray(a[:, 1, :]), "L", TEST_IMAGE_SIZE)
|
||||||
|
size = (TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], 5)
|
||||||
|
a = numpy.ones(size, dtype=numpy.uint8)
|
||||||
|
assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
def test_to_array(self):
|
|
||||||
def _to_array(mode, dtype):
|
|
||||||
img = hopper(mode)
|
|
||||||
|
|
||||||
# Resize to non-square
|
def _test_img_equals_nparray(img, np):
|
||||||
img = img.crop((3, 0, 124, 127))
|
assert len(np.shape) >= 2
|
||||||
self.assertEqual(img.size, (121, 127))
|
np_size = np.shape[1], np.shape[0]
|
||||||
|
assert img.size == np_size
|
||||||
|
px = img.load()
|
||||||
|
for x in range(0, img.size[0], int(img.size[0] / 10)):
|
||||||
|
for y in range(0, img.size[1], int(img.size[1] / 10)):
|
||||||
|
assert_deep_equal(px[x, y], np[y, x])
|
||||||
|
|
||||||
np_img = numpy.array(img)
|
|
||||||
self._test_img_equals_nparray(img, np_img)
|
|
||||||
self.assertEqual(np_img.dtype, dtype)
|
|
||||||
|
|
||||||
modes = [
|
def test_16bit():
|
||||||
("L", numpy.uint8),
|
with Image.open("Tests/images/16bit.cropped.tif") as img:
|
||||||
("I", numpy.int32),
|
np_img = numpy.array(img)
|
||||||
("F", numpy.float32),
|
_test_img_equals_nparray(img, np_img)
|
||||||
("LA", numpy.uint8),
|
assert np_img.dtype == numpy.dtype("<u2")
|
||||||
("RGB", numpy.uint8),
|
|
||||||
("RGBA", numpy.uint8),
|
|
||||||
("RGBX", numpy.uint8),
|
|
||||||
("CMYK", numpy.uint8),
|
|
||||||
("YCbCr", numpy.uint8),
|
|
||||||
("I;16", "<u2"),
|
|
||||||
("I;16B", ">u2"),
|
|
||||||
("I;16L", "<u2"),
|
|
||||||
("HSV", numpy.uint8),
|
|
||||||
]
|
|
||||||
|
|
||||||
for mode in modes:
|
|
||||||
_to_array(*mode)
|
|
||||||
|
|
||||||
def test_point_lut(self):
|
def test_1bit():
|
||||||
# see https://github.com/python-pillow/Pillow/issues/439
|
# Test that 1-bit arrays convert to numpy and back
|
||||||
|
# See: https://github.com/python-pillow/Pillow/issues/350
|
||||||
|
arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], "u1")
|
||||||
|
img = Image.fromarray(arr * 255).convert("1")
|
||||||
|
assert img.mode == "1"
|
||||||
|
arr_back = numpy.array(img)
|
||||||
|
numpy.testing.assert_array_equal(arr, arr_back)
|
||||||
|
|
||||||
data = list(range(256)) * 3
|
|
||||||
lut = numpy.array(data, dtype=numpy.uint8)
|
|
||||||
|
|
||||||
im = hopper()
|
def test_save_tiff_uint16():
|
||||||
|
# Tests that we're getting the pixel value in the right byte order.
|
||||||
|
pixel_value = 0x1234
|
||||||
|
a = numpy.array(
|
||||||
|
[pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16
|
||||||
|
)
|
||||||
|
a.shape = TEST_IMAGE_SIZE
|
||||||
|
img = Image.fromarray(a)
|
||||||
|
|
||||||
im.point(lut)
|
img_px = img.load()
|
||||||
|
assert img_px[0, 0] == pixel_value
|
||||||
|
|
||||||
def test_putdata(self):
|
|
||||||
# shouldn't segfault
|
|
||||||
# see https://github.com/python-pillow/Pillow/issues/1008
|
|
||||||
|
|
||||||
im = Image.new("F", (150, 100))
|
def test_to_array():
|
||||||
arr = numpy.zeros((15000,), numpy.float32)
|
def _to_array(mode, dtype):
|
||||||
im.putdata(arr)
|
img = hopper(mode)
|
||||||
|
|
||||||
self.assertEqual(len(im.getdata()), len(arr))
|
# Resize to non-square
|
||||||
|
img = img.crop((3, 0, 124, 127))
|
||||||
|
assert img.size == (121, 127)
|
||||||
|
|
||||||
def test_roundtrip_eye(self):
|
np_img = numpy.array(img)
|
||||||
for dtype in (
|
_test_img_equals_nparray(img, np_img)
|
||||||
numpy.bool,
|
assert np_img.dtype == dtype
|
||||||
numpy.bool8,
|
|
||||||
numpy.int8,
|
|
||||||
numpy.int16,
|
|
||||||
numpy.int32,
|
|
||||||
numpy.uint8,
|
|
||||||
numpy.uint16,
|
|
||||||
numpy.uint32,
|
|
||||||
numpy.float,
|
|
||||||
numpy.float32,
|
|
||||||
numpy.float64,
|
|
||||||
):
|
|
||||||
arr = numpy.eye(10, dtype=dtype)
|
|
||||||
numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr)))
|
|
||||||
|
|
||||||
def test_zero_size(self):
|
modes = [
|
||||||
# Shouldn't cause floating point exception
|
("L", numpy.uint8),
|
||||||
# See https://github.com/python-pillow/Pillow/issues/2259
|
("I", numpy.int32),
|
||||||
|
("F", numpy.float32),
|
||||||
|
("LA", numpy.uint8),
|
||||||
|
("RGB", numpy.uint8),
|
||||||
|
("RGBA", numpy.uint8),
|
||||||
|
("RGBX", numpy.uint8),
|
||||||
|
("CMYK", numpy.uint8),
|
||||||
|
("YCbCr", numpy.uint8),
|
||||||
|
("I;16", "<u2"),
|
||||||
|
("I;16B", ">u2"),
|
||||||
|
("I;16L", "<u2"),
|
||||||
|
("HSV", numpy.uint8),
|
||||||
|
]
|
||||||
|
|
||||||
im = Image.fromarray(numpy.empty((0, 0), dtype=numpy.uint8))
|
for mode in modes:
|
||||||
|
_to_array(*mode)
|
||||||
|
|
||||||
self.assertEqual(im.size, (0, 0))
|
|
||||||
|
|
||||||
def test_bool(self):
|
def test_point_lut():
|
||||||
# https://github.com/python-pillow/Pillow/issues/2044
|
# See https://github.com/python-pillow/Pillow/issues/439
|
||||||
a = numpy.zeros((10, 2), dtype=numpy.bool)
|
|
||||||
a[0][0] = True
|
|
||||||
|
|
||||||
im2 = Image.fromarray(a)
|
data = list(range(256)) * 3
|
||||||
self.assertEqual(im2.getdata()[0], 255)
|
lut = numpy.array(data, dtype=numpy.uint8)
|
||||||
|
|
||||||
def test_no_resource_warning_for_numpy_array(self):
|
im = hopper()
|
||||||
# https://github.com/python-pillow/Pillow/issues/835
|
|
||||||
# Arrange
|
|
||||||
from numpy import array
|
|
||||||
|
|
||||||
test_file = "Tests/images/hopper.png"
|
im.point(lut)
|
||||||
with Image.open(test_file) as im:
|
|
||||||
|
|
||||||
# Act/Assert
|
|
||||||
pytest.warns(None, lambda: array(im))
|
def test_putdata():
|
||||||
|
# Shouldn't segfault
|
||||||
|
# See https://github.com/python-pillow/Pillow/issues/1008
|
||||||
|
|
||||||
|
im = Image.new("F", (150, 100))
|
||||||
|
arr = numpy.zeros((15000,), numpy.float32)
|
||||||
|
im.putdata(arr)
|
||||||
|
|
||||||
|
assert len(im.getdata()) == len(arr)
|
||||||
|
|
||||||
|
|
||||||
|
def test_roundtrip_eye():
|
||||||
|
for dtype in (
|
||||||
|
numpy.bool,
|
||||||
|
numpy.bool8,
|
||||||
|
numpy.int8,
|
||||||
|
numpy.int16,
|
||||||
|
numpy.int32,
|
||||||
|
numpy.uint8,
|
||||||
|
numpy.uint16,
|
||||||
|
numpy.uint32,
|
||||||
|
numpy.float,
|
||||||
|
numpy.float32,
|
||||||
|
numpy.float64,
|
||||||
|
):
|
||||||
|
arr = numpy.eye(10, dtype=dtype)
|
||||||
|
numpy.testing.assert_array_equal(arr, numpy.array(Image.fromarray(arr)))
|
||||||
|
|
||||||
|
|
||||||
|
def test_zero_size():
|
||||||
|
# Shouldn't cause floating point exception
|
||||||
|
# See https://github.com/python-pillow/Pillow/issues/2259
|
||||||
|
|
||||||
|
im = Image.fromarray(numpy.empty((0, 0), dtype=numpy.uint8))
|
||||||
|
|
||||||
|
assert im.size == (0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bool():
|
||||||
|
# https://github.com/python-pillow/Pillow/issues/2044
|
||||||
|
a = numpy.zeros((10, 2), dtype=numpy.bool)
|
||||||
|
a[0][0] = True
|
||||||
|
|
||||||
|
im2 = Image.fromarray(a)
|
||||||
|
assert im2.getdata()[0] == 255
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_resource_warning_for_numpy_array():
|
||||||
|
# https://github.com/python-pillow/Pillow/issues/835
|
||||||
|
# Arrange
|
||||||
|
from numpy import array
|
||||||
|
|
||||||
|
test_file = "Tests/images/hopper.png"
|
||||||
|
with Image.open(test_file) as im:
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
pytest.warns(None, lambda: array(im))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import pytest
|
||||||
from PIL.PdfParser import (
|
from PIL.PdfParser import (
|
||||||
IndirectObjectDef,
|
IndirectObjectDef,
|
||||||
IndirectReference,
|
IndirectReference,
|
||||||
|
@ -14,127 +15,105 @@ from PIL.PdfParser import (
|
||||||
pdf_repr,
|
pdf_repr,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
|
||||||
|
def test_text_encode_decode():
|
||||||
|
assert encode_text("abc") == b"\xFE\xFF\x00a\x00b\x00c"
|
||||||
|
assert decode_text(b"\xFE\xFF\x00a\x00b\x00c") == "abc"
|
||||||
|
assert decode_text(b"abc") == "abc"
|
||||||
|
assert decode_text(b"\x1B a \x1C") == "\u02D9 a \u02DD"
|
||||||
|
|
||||||
|
|
||||||
class TestPdfParser(PillowTestCase):
|
def test_indirect_refs():
|
||||||
def test_text_encode_decode(self):
|
assert IndirectReference(1, 2) == IndirectReference(1, 2)
|
||||||
self.assertEqual(encode_text("abc"), b"\xFE\xFF\x00a\x00b\x00c")
|
assert IndirectReference(1, 2) != IndirectReference(1, 3)
|
||||||
self.assertEqual(decode_text(b"\xFE\xFF\x00a\x00b\x00c"), "abc")
|
assert IndirectReference(1, 2) != IndirectObjectDef(1, 2)
|
||||||
self.assertEqual(decode_text(b"abc"), "abc")
|
assert IndirectReference(1, 2) != (1, 2)
|
||||||
self.assertEqual(decode_text(b"\x1B a \x1C"), "\u02D9 a \u02DD")
|
assert IndirectObjectDef(1, 2) == IndirectObjectDef(1, 2)
|
||||||
|
assert IndirectObjectDef(1, 2) != IndirectObjectDef(1, 3)
|
||||||
|
assert IndirectObjectDef(1, 2) != IndirectReference(1, 2)
|
||||||
|
assert IndirectObjectDef(1, 2) != (1, 2)
|
||||||
|
|
||||||
def test_indirect_refs(self):
|
|
||||||
self.assertEqual(IndirectReference(1, 2), IndirectReference(1, 2))
|
|
||||||
self.assertNotEqual(IndirectReference(1, 2), IndirectReference(1, 3))
|
|
||||||
self.assertNotEqual(IndirectReference(1, 2), IndirectObjectDef(1, 2))
|
|
||||||
self.assertNotEqual(IndirectReference(1, 2), (1, 2))
|
|
||||||
self.assertEqual(IndirectObjectDef(1, 2), IndirectObjectDef(1, 2))
|
|
||||||
self.assertNotEqual(IndirectObjectDef(1, 2), IndirectObjectDef(1, 3))
|
|
||||||
self.assertNotEqual(IndirectObjectDef(1, 2), IndirectReference(1, 2))
|
|
||||||
self.assertNotEqual(IndirectObjectDef(1, 2), (1, 2))
|
|
||||||
|
|
||||||
def test_parsing(self):
|
def test_parsing():
|
||||||
self.assertEqual(PdfParser.interpret_name(b"Name#23Hash"), b"Name#Hash")
|
assert PdfParser.interpret_name(b"Name#23Hash") == b"Name#Hash"
|
||||||
self.assertEqual(
|
assert PdfParser.interpret_name(b"Name#23Hash", as_text=True) == "Name#Hash"
|
||||||
PdfParser.interpret_name(b"Name#23Hash", as_text=True), "Name#Hash"
|
assert PdfParser.get_value(b"1 2 R ", 0) == (IndirectReference(1, 2), 5)
|
||||||
)
|
assert PdfParser.get_value(b"true[", 0) == (True, 4)
|
||||||
self.assertEqual(
|
assert PdfParser.get_value(b"false%", 0) == (False, 5)
|
||||||
PdfParser.get_value(b"1 2 R ", 0), (IndirectReference(1, 2), 5)
|
assert PdfParser.get_value(b"null<", 0) == (None, 4)
|
||||||
)
|
assert PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0) == (123, 15)
|
||||||
self.assertEqual(PdfParser.get_value(b"true[", 0), (True, 4))
|
assert PdfParser.get_value(b"<901FA3>", 0) == (b"\x90\x1F\xA3", 8)
|
||||||
self.assertEqual(PdfParser.get_value(b"false%", 0), (False, 5))
|
assert PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3) == (b"\x90\x1F\xA0", 17)
|
||||||
self.assertEqual(PdfParser.get_value(b"null<", 0), (None, 4))
|
assert PdfParser.get_value(b"(asd)", 0) == (b"asd", 5)
|
||||||
self.assertEqual(PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0), (123, 15))
|
assert PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0) == (b"asd(qwe)zxc", 13)
|
||||||
self.assertEqual(PdfParser.get_value(b"<901FA3>", 0), (b"\x90\x1F\xA3", 8))
|
assert PdfParser.get_value(b"(Two \\\nwords.)", 0) == (b"Two words.", 14)
|
||||||
self.assertEqual(
|
assert PdfParser.get_value(b"(Two\nlines.)", 0) == (b"Two\nlines.", 12)
|
||||||
PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3), (b"\x90\x1F\xA0", 17)
|
assert PdfParser.get_value(b"(Two\r\nlines.)", 0) == (b"Two\nlines.", 13)
|
||||||
)
|
assert PdfParser.get_value(b"(Two\\nlines.)", 0) == (b"Two\nlines.", 13)
|
||||||
self.assertEqual(PdfParser.get_value(b"(asd)", 0), (b"asd", 5))
|
assert PdfParser.get_value(b"(One\\(paren).", 0) == (b"One(paren", 12)
|
||||||
self.assertEqual(
|
assert PdfParser.get_value(b"(One\\)paren).", 0) == (b"One)paren", 12)
|
||||||
PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0), (b"asd(qwe)zxc", 13)
|
assert PdfParser.get_value(b"(\\0053)", 0) == (b"\x053", 7)
|
||||||
)
|
assert PdfParser.get_value(b"(\\053)", 0) == (b"\x2B", 6)
|
||||||
self.assertEqual(
|
assert PdfParser.get_value(b"(\\53)", 0) == (b"\x2B", 5)
|
||||||
PdfParser.get_value(b"(Two \\\nwords.)", 0), (b"Two words.", 14)
|
assert PdfParser.get_value(b"(\\53a)", 0) == (b"\x2Ba", 6)
|
||||||
)
|
assert PdfParser.get_value(b"(\\1111)", 0) == (b"\x491", 7)
|
||||||
self.assertEqual(PdfParser.get_value(b"(Two\nlines.)", 0), (b"Two\nlines.", 12))
|
assert PdfParser.get_value(b" 123 (", 0) == (123, 4)
|
||||||
self.assertEqual(
|
assert round(abs(PdfParser.get_value(b" 123.4 %", 0)[0] - 123.4), 7) == 0
|
||||||
PdfParser.get_value(b"(Two\r\nlines.)", 0), (b"Two\nlines.", 13)
|
assert PdfParser.get_value(b" 123.4 %", 0)[1] == 6
|
||||||
)
|
with pytest.raises(PdfFormatError):
|
||||||
self.assertEqual(
|
PdfParser.get_value(b"]", 0)
|
||||||
PdfParser.get_value(b"(Two\\nlines.)", 0), (b"Two\nlines.", 13)
|
d = PdfParser.get_value(b"<</Name (value) /N /V>>", 0)[0]
|
||||||
)
|
assert isinstance(d, PdfDict)
|
||||||
self.assertEqual(PdfParser.get_value(b"(One\\(paren).", 0), (b"One(paren", 12))
|
assert len(d) == 2
|
||||||
self.assertEqual(PdfParser.get_value(b"(One\\)paren).", 0), (b"One)paren", 12))
|
assert d.Name == "value"
|
||||||
self.assertEqual(PdfParser.get_value(b"(\\0053)", 0), (b"\x053", 7))
|
assert d[b"Name"] == b"value"
|
||||||
self.assertEqual(PdfParser.get_value(b"(\\053)", 0), (b"\x2B", 6))
|
assert d.N == PdfName("V")
|
||||||
self.assertEqual(PdfParser.get_value(b"(\\53)", 0), (b"\x2B", 5))
|
a = PdfParser.get_value(b"[/Name (value) /N /V]", 0)[0]
|
||||||
self.assertEqual(PdfParser.get_value(b"(\\53a)", 0), (b"\x2Ba", 6))
|
assert isinstance(a, list)
|
||||||
self.assertEqual(PdfParser.get_value(b"(\\1111)", 0), (b"\x491", 7))
|
assert len(a) == 4
|
||||||
self.assertEqual(PdfParser.get_value(b" 123 (", 0), (123, 4))
|
assert a[0] == PdfName("Name")
|
||||||
self.assertAlmostEqual(PdfParser.get_value(b" 123.4 %", 0)[0], 123.4)
|
s = PdfParser.get_value(
|
||||||
self.assertEqual(PdfParser.get_value(b" 123.4 %", 0)[1], 6)
|
b"<</Name (value) /Length 5>>\nstream\nabcde\nendstream<<...", 0
|
||||||
self.assertRaises(PdfFormatError, PdfParser.get_value, b"]", 0)
|
)[0]
|
||||||
d = PdfParser.get_value(b"<</Name (value) /N /V>>", 0)[0]
|
assert isinstance(s, PdfStream)
|
||||||
self.assertIsInstance(d, PdfDict)
|
assert s.dictionary.Name == "value"
|
||||||
self.assertEqual(len(d), 2)
|
assert s.decode() == b"abcde"
|
||||||
self.assertEqual(d.Name, "value")
|
for name in ["CreationDate", "ModDate"]:
|
||||||
self.assertEqual(d[b"Name"], b"value")
|
for date, value in {
|
||||||
self.assertEqual(d.N, PdfName("V"))
|
b"20180729214124": "20180729214124",
|
||||||
a = PdfParser.get_value(b"[/Name (value) /N /V]", 0)[0]
|
b"D:20180729214124": "20180729214124",
|
||||||
self.assertIsInstance(a, list)
|
b"D:2018072921": "20180729210000",
|
||||||
self.assertEqual(len(a), 4)
|
b"D:20180729214124Z": "20180729214124",
|
||||||
self.assertEqual(a[0], PdfName("Name"))
|
b"D:20180729214124+08'00'": "20180729134124",
|
||||||
s = PdfParser.get_value(
|
b"D:20180729214124-05'00'": "20180730024124",
|
||||||
b"<</Name (value) /Length 5>>\nstream\nabcde\nendstream<<...", 0
|
}.items():
|
||||||
)[0]
|
d = PdfParser.get_value(b"<</" + name.encode() + b" (" + date + b")>>", 0)[
|
||||||
self.assertIsInstance(s, PdfStream)
|
0
|
||||||
self.assertEqual(s.dictionary.Name, "value")
|
]
|
||||||
self.assertEqual(s.decode(), b"abcde")
|
assert time.strftime("%Y%m%d%H%M%S", getattr(d, name)) == value
|
||||||
for name in ["CreationDate", "ModDate"]:
|
|
||||||
for date, value in {
|
|
||||||
b"20180729214124": "20180729214124",
|
|
||||||
b"D:20180729214124": "20180729214124",
|
|
||||||
b"D:2018072921": "20180729210000",
|
|
||||||
b"D:20180729214124Z": "20180729214124",
|
|
||||||
b"D:20180729214124+08'00'": "20180729134124",
|
|
||||||
b"D:20180729214124-05'00'": "20180730024124",
|
|
||||||
}.items():
|
|
||||||
d = PdfParser.get_value(
|
|
||||||
b"<</" + name.encode() + b" (" + date + b")>>", 0
|
|
||||||
)[0]
|
|
||||||
self.assertEqual(time.strftime("%Y%m%d%H%M%S", getattr(d, name)), value)
|
|
||||||
|
|
||||||
def test_pdf_repr(self):
|
|
||||||
self.assertEqual(bytes(IndirectReference(1, 2)), b"1 2 R")
|
def test_pdf_repr():
|
||||||
self.assertEqual(bytes(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj")
|
assert bytes(IndirectReference(1, 2)) == b"1 2 R"
|
||||||
self.assertEqual(bytes(PdfName(b"Name#Hash")), b"/Name#23Hash")
|
assert bytes(IndirectObjectDef(*IndirectReference(1, 2))) == b"1 2 obj"
|
||||||
self.assertEqual(bytes(PdfName("Name#Hash")), b"/Name#23Hash")
|
assert bytes(PdfName(b"Name#Hash")) == b"/Name#23Hash"
|
||||||
self.assertEqual(
|
assert bytes(PdfName("Name#Hash")) == b"/Name#23Hash"
|
||||||
bytes(PdfDict({b"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>"
|
assert bytes(PdfDict({b"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>"
|
||||||
)
|
assert bytes(PdfDict({"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>"
|
||||||
self.assertEqual(
|
assert pdf_repr(IndirectReference(1, 2)) == b"1 2 R"
|
||||||
bytes(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>"
|
assert pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))) == b"1 2 obj"
|
||||||
)
|
assert pdf_repr(PdfName(b"Name#Hash")) == b"/Name#23Hash"
|
||||||
self.assertEqual(pdf_repr(IndirectReference(1, 2)), b"1 2 R")
|
assert pdf_repr(PdfName("Name#Hash")) == b"/Name#23Hash"
|
||||||
self.assertEqual(
|
assert (
|
||||||
pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj"
|
pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>"
|
||||||
)
|
)
|
||||||
self.assertEqual(pdf_repr(PdfName(b"Name#Hash")), b"/Name#23Hash")
|
assert (
|
||||||
self.assertEqual(pdf_repr(PdfName("Name#Hash")), b"/Name#23Hash")
|
pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})) == b"<<\n/Name 1 2 R\n>>"
|
||||||
self.assertEqual(
|
)
|
||||||
pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})),
|
assert pdf_repr(123) == b"123"
|
||||||
b"<<\n/Name 1 2 R\n>>",
|
assert pdf_repr(True) == b"true"
|
||||||
)
|
assert pdf_repr(False) == b"false"
|
||||||
self.assertEqual(
|
assert pdf_repr(None) == b"null"
|
||||||
pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>"
|
assert pdf_repr(b"a)/b\\(c") == br"(a\)/b\\\(c)"
|
||||||
)
|
assert pdf_repr([123, True, {"a": PdfName(b"b")}]) == b"[ 123 true <<\n/a /b\n>> ]"
|
||||||
self.assertEqual(pdf_repr(123), b"123")
|
assert pdf_repr(PdfBinary(b"\x90\x1F\xA0")) == b"<901FA0>"
|
||||||
self.assertEqual(pdf_repr(True), b"true")
|
|
||||||
self.assertEqual(pdf_repr(False), b"false")
|
|
||||||
self.assertEqual(pdf_repr(None), b"null")
|
|
||||||
self.assertEqual(pdf_repr(b"a)/b\\(c"), br"(a\)/b\\\(c)")
|
|
||||||
self.assertEqual(
|
|
||||||
pdf_repr([123, True, {"a": PdfName(b"b")}]), b"[ 123 true <<\n/a /b\n>> ]"
|
|
||||||
)
|
|
||||||
self.assertEqual(pdf_repr(PdfBinary(b"\x90\x1F\xA0")), b"<901FA0>")
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user