Merge branch 'master' into fast-filters

This commit is contained in:
Alexander 2017-08-28 21:47:43 +03:00
commit ad4b42f5f4
17 changed files with 1111 additions and 370 deletions

View File

@ -4,6 +4,15 @@ Changelog (Pillow)
4.3.0 (unreleased)
------------------
- Region of interest (box) for resampling #2254
[homm]
- Basic support for Termux (android) in setup.py #2684
[wiredfool]
- Bug: Fix Image.fromarray for numpy.bool type. #2683
[wiredfool]
- CI: Add Fedora 24 and 26 to Docker tests
[wiredfool]
@ -31,6 +40,9 @@ Changelog (Pillow)
- Remove unused im.copy2 and core.copy methods #2657
[homm]
- Fast Image.merge() #2677
[homm]
- Fast Image.split() #2676
[homm]
@ -39,14 +51,14 @@ Changelog (Pillow)
- Storage cleanup #2654
[homm]
- FLI: Use frame count from FLI header #2674
[radarhere]
- Test: Test animated FLI file #2650
[hugovk]
- Bug: Fixed uninitalized memory in bc5 decoding #2648
- Bug: Fixed uninitialized memory in bc5 decoding #2648
[ifeherva]
- Moved SgiImagePlugin save error to before the start of write operations #2646
@ -75,13 +87,13 @@ Changelog (Pillow)
- Docs: Corrected alpha_composite args documentation #2627
[radarhere]
- Docs: added the description of the filename attribute to images.rst #2621
[dasdachs]
- Dependencies: Updated libimagequant to 2.10.1 #2616
[radarhere]
- PDF: Renamed parameter to not shadow built-in dict #2612
[kijeong]
@ -99,13 +111,13 @@ Changelog (Pillow)
- CI: Amazon Linux and Centos6 docker images added to TravisCI #2585
[wiredfool]
- Image.alpha_composite added #2595
[wiredfool]
- Complex Text Support #2576
[ShamsaHamed, Fahad-Alsaidi, wiredfool]
- Added threshold parameter to ImageDraw.floodfill #2599
[nediamond]
@ -117,19 +129,19 @@ Changelog (Pillow)
- Specify Pillow Version in one place #2517
[wiredfool]
- CI: Change the owner of the TRAVIS_BUILD_DIR, fixing broken docker runs #2587
[wiredfool]
- Fix truncated PNG loading for some images, Fix memory leak on truncated PNG images. #2541, #2598
[homm]
- Add decompression bomb check to Image.crop #2410
[wiredfool]
- ImageFile: Ensure that the `err_code` variable is initialized in case of exception. #2363
[alexkiro]
- Tiff: Support append_images for saving multipage TIFFs #2406
[blochl]
@ -144,16 +156,16 @@ Changelog (Pillow)
- Remove deprecated code #2549
[hugovk]
- Added append_images to PDF saving #2526
[radarhere]
- Remove unused function core image function new_array #2548
[hugovk]
- Remove unnecessary calls to dict.keys() #2551
[jdufresne]
- Add more ImageDraw.py tests and remove unused Draw.c code #2533
[hugovk]
@ -180,7 +192,7 @@ Changelog (Pillow)
- Remove 'not yet implemented' methods from PIL 1.1.4 #2538
[hugovk]
- Dependencies: Update FreeType to 2.8, LibTIFF to 4.0.8 and libimagequant to 2.9.1 #2535 #2537 #2540
[radarhere]

View File

@ -1676,7 +1676,7 @@ class Image(object):
return m_im
def resize(self, size, resample=NEAREST):
def resize(self, size, resample=NEAREST, box=None):
"""
Returns a resized copy of this image.
@ -1689,6 +1689,10 @@ class Image(object):
If omitted, or if the image has mode "1" or "P", it is
set :py:attr:`PIL.Image.NEAREST`.
See: :ref:`concept-filters`.
:param box: An optional 4-tuple of floats giving the region
of the source image which should be scaled.
The values should be within (0, 0, width, height) rectangle.
If omitted or None, the entire source is used.
:returns: An :py:class:`~PIL.Image.Image` object.
"""
@ -1697,22 +1701,28 @@ class Image(object):
):
raise ValueError("unknown resampling filter")
self.load()
size = tuple(size)
if self.size == size:
if box is None:
box = (0, 0) + self.size
else:
box = tuple(box)
if self.size == size and box == (0, 0) + self.size:
return self.copy()
if self.mode in ("1", "P"):
resample = NEAREST
if self.mode == 'LA':
return self.convert('La').resize(size, resample).convert('LA')
return self.convert('La').resize(size, resample, box).convert('LA')
if self.mode == 'RGBA':
return self.convert('RGBa').resize(size, resample).convert('RGBA')
return self.convert('RGBa').resize(size, resample, box).convert('RGBA')
return self._new(self.im.resize(size, resample))
self.load()
return self._new(self.im.resize(size, resample, box))
def rotate(self, angle, resample=NEAREST, expand=0, center=None,
translate=None):
@ -2425,7 +2435,7 @@ def fromqpixmap(im):
_fromarray_typemap = {
# (shape, typestr) => mode, rawmode
# first two members of shape are set to one
# ((1, 1), "|b1"): ("1", "1"), # broken
((1, 1), "|b1"): ("1", "1;8"),
((1, 1), "|u1"): ("L", "L"),
((1, 1), "|i1"): ("I", "I;8"),
((1, 1), "<u2"): ("I", "I;16"),
@ -2638,11 +2648,9 @@ def merge(mode, bands):
raise ValueError("mode mismatch")
if im.size != bands[0].size:
raise ValueError("size mismatch")
im = core.new(mode, bands[0].size)
for i in range(getmodebands(mode)):
bands[i].load()
im.putband(bands[i].im, i)
return bands[0]._new(im)
for band in bands:
band.load()
return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
# --------------------------------------------------------------------

View File

@ -133,6 +133,7 @@ class _PyAccess32_3(PyAccess):
pixel.r = min(color[0], 255)
pixel.g = min(color[1], 255)
pixel.b = min(color[2], 255)
pixel.a = 255
class _PyAccess32_4(PyAccess):

View File

@ -201,6 +201,17 @@ OPEN_INFO = {
(II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
(MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
(II, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"),
(MM, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16B"),
(II, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16L"),
(MM, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16B"),
(II, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16L"),
(MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16B"),
(II, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"),
(MM, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"),
(II, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16L"),
(MM, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16B"),
(II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
(MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
(II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
@ -230,7 +241,12 @@ OPEN_INFO = {
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
}
PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"]
PREFIXES = [
b"MM\x00\x2A", # Valid TIFF header with big-endian byte order
b"II\x2A\x00", # Valid TIFF header with little-endian byte order
b"MM\x2A\x00", # Invalid TIFF header, assume big-endian
b"II\x00\x2A", # Invalid TIFF header, assume little-endian
]
def _accept(prefix):

Binary file not shown.

View File

@ -51,6 +51,14 @@ class TestFileTiff(PillowTestCase):
self.assertEqual(im.tile, [('raw', (0, 0, 55, 43), 8, ('RGBa', 0, 1))])
im.load()
def test_16bit_RGBa_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGBa.tiff")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (100, 40))
self.assertEqual(im.tile, [('tiff_lzw', (0, 0, 100, 40), 50, 'RGBa;16B')])
im.load()
def test_gimp_tiff(self):
# Read TIFF JPEG images from GIMP [@PIL168]

View File

@ -1,4 +1,7 @@
from __future__ import print_function
from __future__ import division, print_function
from contextlib import contextmanager
from helper import unittest, PillowTestCase, hopper
from PIL import Image, ImageDraw
@ -300,24 +303,46 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
class CoreResamplePassesTest(PillowTestCase):
@contextmanager
def count(self, diff):
count = Image.core.getcount()
yield
self.assertEqual(Image.core.getcount() - count, diff)
def test_horizontal(self):
im = hopper('L')
count = Image.core.getcount()
im.resize((im.size[0] + 10, im.size[1]), Image.BILINEAR)
self.assertEqual(Image.core.getcount(), count + 1)
with self.count(1):
im.resize((im.size[0] - 10, im.size[1]), Image.BILINEAR)
def test_vertical(self):
im = hopper('L')
count = Image.core.getcount()
im.resize((im.size[0], im.size[1] + 10), Image.BILINEAR)
self.assertEqual(Image.core.getcount(), count + 1)
with self.count(1):
im.resize((im.size[0], im.size[1] - 10), Image.BILINEAR)
def test_both(self):
im = hopper('L')
count = Image.core.getcount()
im.resize((im.size[0] + 10, im.size[1] + 10), Image.BILINEAR)
self.assertEqual(Image.core.getcount(), count + 2)
with self.count(2):
im.resize((im.size[0] - 10, im.size[1] - 10), Image.BILINEAR)
def test_box_horizontal(self):
im = hopper('L')
box = (20, 0, im.size[0] - 20, im.size[1])
with self.count(1):
# the same size, but different box
with_box = im.resize(im.size, Image.BILINEAR, box)
with self.count(2):
cropped = im.crop(box).resize(im.size, Image.BILINEAR)
self.assert_image_similar(with_box, cropped, 0.1)
def test_box_vertical(self):
im = hopper('L')
box = (0, 20, im.size[0], im.size[1] - 20)
with self.count(1):
# the same size, but different box
with_box = im.resize(im.size, Image.BILINEAR, box)
with self.count(2):
cropped = im.crop(box).resize(im.size, Image.BILINEAR)
self.assert_image_similar(with_box, cropped, 0.1)
class CoreResampleCoefficientsTest(PillowTestCase):
def test_reduce(self):
@ -347,5 +372,92 @@ class CoreResampleCoefficientsTest(PillowTestCase):
self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) # fourth channel
class CoreResampleBoxTest(PillowTestCase):
def test_wrong_arguments(self):
im = hopper()
for resample in (Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING,
Image.BICUBIC, Image.LANCZOS):
im.resize((32, 32), resample, (0, 0, im.width, im.height))
im.resize((32, 32), resample, (20, 20, im.width, im.height))
im.resize((32, 32), resample, (20, 20, 20, 100))
im.resize((32, 32), resample, (20, 20, 100, 20))
with self.assertRaisesRegexp(TypeError, "must be sequence of length 4"):
im.resize((32, 32), resample, (im.width, im.height))
with self.assertRaisesRegexp(ValueError, "can't be negative"):
im.resize((32, 32), resample, (-20, 20, 100, 100))
with self.assertRaisesRegexp(ValueError, "can't be negative"):
im.resize((32, 32), resample, (20, -20, 100, 100))
with self.assertRaisesRegexp(ValueError, "can't be empty"):
im.resize((32, 32), resample, (20.1, 20, 20, 100))
with self.assertRaisesRegexp(ValueError, "can't be empty"):
im.resize((32, 32), resample, (20, 20.1, 100, 20))
with self.assertRaisesRegexp(ValueError, "can't be empty"):
im.resize((32, 32), resample, (20.1, 20.1, 20, 20))
with self.assertRaisesRegexp(ValueError, "can't exceed"):
im.resize((32, 32), resample, (0, 0, im.width + 1, im.height))
with self.assertRaisesRegexp(ValueError, "can't exceed"):
im.resize((32, 32), resample, (0, 0, im.width, im.height + 1))
def resize_tiled(self, im, dst_size, xtiles, ytiles):
def split_range(size, tiles):
scale = size / tiles
for i in range(tiles):
yield (int(round(scale * i)), int(round(scale * (i + 1))))
tiled = Image.new(im.mode, dst_size)
scale = (im.size[0] / tiled.size[0], im.size[1] / tiled.size[1])
for y0, y1 in split_range(dst_size[1], ytiles):
for x0, x1 in split_range(dst_size[0], xtiles):
box = (x0 * scale[0], y0 * scale[1],
x1 * scale[0], y1 * scale[1])
tile = im.resize((x1 - x0, y1 - y0), Image.BICUBIC, box)
tiled.paste(tile, (x0, y0))
return tiled
def test_tiles(self):
im = Image.open("Tests/images/flower.jpg")
assert im.size == (480, 360)
dst_size = (251, 188)
reference = im.resize(dst_size, Image.BICUBIC)
for tiles in [(1, 1), (3, 3), (9, 7), (100, 100)]:
tiled = self.resize_tiled(im, dst_size, *tiles)
self.assert_image_similar(reference, tiled, 0.01)
def test_subsample(self):
# This test shows advantages of the subpixel resizing
# after supersampling (e.g. during JPEG decoding).
im = Image.open("Tests/images/flower.jpg")
assert im.size == (480, 360)
dst_size = (48, 36)
# Reference is cropped image resized to destination
reference = im.crop((0, 0, 473, 353)).resize(dst_size, Image.BICUBIC)
# Image.BOX emulates supersampling (480 / 8 = 60, 360 / 8 = 45)
supersampled = im.resize((60, 45), Image.BOX)
with_box = supersampled.resize(dst_size, Image.BICUBIC,
(0, 0, 59.125, 44.125))
without_box = supersampled.resize(dst_size, Image.BICUBIC)
# error with box should be much smaller than without
self.assert_image_similar(reference, with_box, 6)
with self.assertRaisesRegexp(AssertionError, "difference 29\."):
self.assert_image_similar(reference, without_box, 5)
def test_formats(self):
for resample in [Image.NEAREST, Image.BILINEAR]:
for mode in ['RGB', 'L', 'RGBA', 'LA', 'I', '']:
im = hopper(mode)
box = (20, 20, im.size[0] - 20, im.size[1] - 20)
with_box = im.resize((32, 32), resample, box)
cropped = im.crop(box).resize((32, 32), resample)
self.assert_image_similar(cropped, with_box, 0.4)
if __name__ == '__main__':
unittest.main()

View File

@ -1,157 +1,503 @@
import sys
from helper import unittest, PillowTestCase, py3
from PIL import Image
X = 255
class TestLibPack(PillowTestCase):
def assert_pack(self, mode, rawmode, data, *pixels):
"""
data - either raw bytes with data or just number of bytes in rawmode.
"""
im = Image.new(mode, (len(pixels), 1))
for x, pixel in enumerate(pixels):
im.putpixel((x, 0), pixel)
def pack(self):
pass # not yet
if isinstance(data, (int)):
data_len = data * len(pixels)
data = bytes(bytearray(range(1, data_len + 1)))
def test_pack(self):
self.assertEqual(data, im.tobytes("raw", rawmode))
def pack(mode, rawmode, in_data=(1, 2, 3, 4)):
if len(mode) == 1:
im = Image.new(mode, (1, 1), in_data[0])
else:
im = Image.new(mode, (1, 1), in_data[:len(mode)])
def test_1(self):
self.assert_pack("1", "1", b'\x01', 0,0,0,0,0,0,0,X)
self.assert_pack("1", "1;I", b'\x01', X,X,X,X,X,X,X,0)
self.assert_pack("1", "1;R", b'\x01', X,0,0,0,0,0,0,0)
self.assert_pack("1", "1;IR", b'\x01', 0,X,X,X,X,X,X,X)
if py3:
return list(im.tobytes("raw", rawmode))
else:
return [ord(c) for c in im.tobytes("raw", rawmode)]
self.assert_pack("1", "1", b'\xaa', X,0,X,0,X,0,X,0)
self.assert_pack("1", "1;I", b'\xaa', 0,X,0,X,0,X,0,X)
self.assert_pack("1", "1;R", b'\xaa', 0,X,0,X,0,X,0,X)
self.assert_pack("1", "1;IR", b'\xaa', X,0,X,0,X,0,X,0)
order = 1 if Image._ENDIAN == '<' else -1
self.assert_pack("1", "L", b'\xff\x00\x00\xff\x00\x00', X,0,0,X,0,0)
self.assertEqual(pack("1", "1"), [128])
self.assertEqual(pack("1", "1;I"), [0])
self.assertEqual(pack("1", "1;R"), [1])
self.assertEqual(pack("1", "1;IR"), [0])
def test_L(self):
self.assert_pack("L", "L", 1, 1,2,3,4)
self.assertEqual(pack("L", "L"), [1])
def test_LA(self):
self.assert_pack("LA", "LA", 2, (1,2), (3,4), (5,6))
self.assert_pack("LA", "LA;L", 2, (1,4), (2,5), (3,6))
self.assertEqual(pack("I", "I"), [1, 0, 0, 0][::order])
def test_P(self):
self.assert_pack("P", "P;1", b'\xe4', 1, 1, 1, 0, 0, 255, 0, 0)
self.assert_pack("P", "P;2", b'\xe4', 3, 2, 1, 0)
self.assert_pack("P", "P;4", b'\x02\xef', 0, 2, 14, 15)
self.assert_pack("P", "P", 1, 1, 2, 3, 4)
self.assertEqual(pack("F", "F"), [0, 0, 128, 63][::order])
def test_PA(self):
self.assert_pack("PA", "PA", 2, (1,2), (3,4), (5,6))
self.assert_pack("PA", "PA;L", 2, (1,4), (2,5), (3,6))
self.assertEqual(pack("LA", "LA"), [1, 2])
def test_RGB(self):
self.assert_pack("RGB", "RGB", 3, (1,2,3), (4,5,6), (7,8,9))
self.assert_pack("RGB", "RGBX",
b'\x01\x02\x03\xff\x05\x06\x07\xff', (1,2,3), (5,6,7))
self.assert_pack("RGB", "XRGB",
b'\x00\x02\x03\x04\x00\x06\x07\x08', (2,3,4), (6,7,8))
self.assert_pack("RGB", "BGR", 3, (3,2,1), (6,5,4), (9,8,7))
self.assert_pack("RGB", "BGRX",
b'\x01\x02\x03\x00\x05\x06\x07\x00', (3,2,1), (7,6,5))
self.assert_pack("RGB", "XBGR",
b'\x00\x02\x03\x04\x00\x06\x07\x08', (4,3,2), (8,7,6))
self.assert_pack("RGB", "RGB;L", 3, (1,4,7), (2,5,8), (3,6,9))
self.assert_pack("RGB", "R", 1, (1,9,9), (2,9,9), (3,9,9))
self.assert_pack("RGB", "G", 1, (9,1,9), (9,2,9), (9,3,9))
self.assert_pack("RGB", "B", 1, (9,9,1), (9,9,2), (9,9,3))
self.assertEqual(pack("RGB", "RGB"), [1, 2, 3])
self.assertEqual(pack("RGB", "RGB;L"), [1, 2, 3])
self.assertEqual(pack("RGB", "BGR"), [3, 2, 1])
self.assertEqual(pack("RGB", "RGBX"), [1, 2, 3, 255]) # 255?
self.assertEqual(pack("RGB", "BGRX"), [3, 2, 1, 0])
self.assertEqual(pack("RGB", "XRGB"), [0, 1, 2, 3])
self.assertEqual(pack("RGB", "XBGR"), [0, 3, 2, 1])
def test_RGBA(self):
self.assert_pack("RGBA", "RGBA", 4,
(1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_pack("RGBA", "RGBA;L", 4,
(1,4,7,10), (2,5,8,11), (3,6,9,12))
self.assert_pack("RGBA", "RGB", 3, (1,2,3,14), (4,5,6,15), (7,8,9,16))
self.assert_pack("RGBA", "BGR", 3, (3,2,1,14), (6,5,4,15), (9,8,7,16))
self.assert_pack("RGBA", "BGRA", 4,
(3,2,1,4), (7,6,5,8), (11,10,9,12))
self.assert_pack("RGBA", "ABGR", 4,
(4,3,2,1), (8,7,6,5), (12,11,10,9))
self.assert_pack("RGBA", "BGRa", 4,
(191,127,63,4), (223,191,159,8), (233,212,191,12))
self.assert_pack("RGBA", "R", 1, (1,0,8,9), (2,0,8,9), (3,0,8,0))
self.assert_pack("RGBA", "G", 1, (6,1,8,9), (6,2,8,9), (6,3,8,9))
self.assert_pack("RGBA", "B", 1, (6,7,1,9), (6,7,2,0), (6,7,3,9))
self.assert_pack("RGBA", "A", 1, (6,7,0,1), (6,7,0,2), (0,7,0,3))
self.assertEqual(pack("RGBX", "RGBX"), [1, 2, 3, 4]) # 4->255?
def test_RGBa(self):
self.assert_pack("RGBa", "RGBa", 4,
(1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_pack("RGBa", "BGRa", 4,
(3,2,1,4), (7,6,5,8), (11,10,9,12))
self.assert_pack("RGBa", "aBGR", 4,
(4,3,2,1), (8,7,6,5), (12,11,10,9))
self.assertEqual(pack("RGBA", "RGBA"), [1, 2, 3, 4])
self.assertEqual(pack("RGBA", "BGRa"), [0, 0, 0, 4])
self.assertEqual(pack("RGBA", "BGRa", in_data=(20, 30, 40, 50)), [8, 6, 4, 50])
def test_RGBX(self):
self.assert_pack("RGBX", "RGBX", 4, (1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_pack("RGBX", "RGBX;L", 4, (1,4,7,10), (2,5,8,11), (3,6,9,12))
self.assert_pack("RGBX", "RGB", 3, (1,2,3,X), (4,5,6,X), (7,8,9,X))
self.assert_pack("RGBX", "BGR", 3, (3,2,1,X), (6,5,4,X), (9,8,7,X))
self.assert_pack("RGBX", "BGRX",
b'\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00',
(3,2,1,X), (7,6,5,X), (11,10,9,X))
self.assert_pack("RGBX", "XBGR",
b'\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c',
(4,3,2,X), (8,7,6,X), (12,11,10,X))
self.assert_pack("RGBX", "R", 1, (1,0,8,9), (2,0,8,9), (3,0,8,0))
self.assert_pack("RGBX", "G", 1, (6,1,8,9), (6,2,8,9), (6,3,8,9))
self.assert_pack("RGBX", "B", 1, (6,7,1,9), (6,7,2,0), (6,7,3,9))
self.assert_pack("RGBX", "X", 1, (6,7,0,1), (6,7,0,2), (0,7,0,3))
self.assertEqual(pack("RGBa", "RGBa"), [1, 2, 3, 4])
self.assertEqual(pack("RGBa", "BGRa"), [3, 2, 1, 4])
self.assertEqual(pack("RGBa", "aBGR"), [4, 3, 2, 1])
def test_CMYK(self):
self.assert_pack("CMYK", "CMYK", 4, (1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_pack("CMYK", "CMYK;I", 4,
(254,253,252,251), (250,249,248,247), (246,245,244,243))
self.assert_pack("CMYK", "CMYK;L", 4,
(1,4,7,10), (2,5,8,11), (3,6,9,12))
self.assert_pack("CMYK", "K", 1, (6,7,0,1), (6,7,0,2), (0,7,0,3))
self.assertEqual(pack("CMYK", "CMYK"), [1, 2, 3, 4])
self.assertEqual(pack("YCbCr", "YCbCr"), [1, 2, 3])
def test_YCbCr(self):
self.assert_pack("YCbCr", "YCbCr", 3, (1,2,3), (4,5,6), (7,8,9))
self.assert_pack("YCbCr", "YCbCr;L", 3, (1,4,7), (2,5,8), (3,6,9))
self.assert_pack("YCbCr", "YCbCrX",
b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
(1,2,3), (5,6,7), (9,10,11))
self.assert_pack("YCbCr", "YCbCrK",
b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
(1,2,3), (5,6,7), (9,10,11))
self.assert_pack("YCbCr", "Y", 1, (1,0,8,9), (2,0,8,9), (3,0,8,0))
self.assert_pack("YCbCr", "Cb", 1, (6,1,8,9), (6,2,8,9), (6,3,8,9))
self.assert_pack("YCbCr", "Cr", 1, (6,7,1,9), (6,7,2,0), (6,7,3,9))
def test_unpack(self):
def test_LAB(self):
self.assert_pack("LAB", "LAB", 3,
(1,130,131), (4,133,134), (7,136,137))
self.assert_pack("LAB", "L", 1, (1,9,9), (2,9,9), (3,9,9))
self.assert_pack("LAB", "A", 1, (9,1,9), (9,2,9), (9,3,9))
self.assert_pack("LAB", "B", 1, (9,9,1), (9,9,2), (9,9,3))
def unpack(mode, rawmode, bytes_):
im = None
def test_HSV(self):
self.assert_pack("HSV", "HSV", 3, (1,2,3), (4,5,6), (7,8,9))
self.assert_pack("HSV", "H", 1, (1,9,9), (2,9,9), (3,9,9))
self.assert_pack("HSV", "S", 1, (9,1,9), (9,2,9), (9,3,9))
self.assert_pack("HSV", "V", 1, (9,9,1), (9,9,2), (9,9,3))
if py3:
data = bytes(range(1, bytes_+1))
else:
data = ''.join(chr(i) for i in range(1, bytes_+1))
def test_I(self):
self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304)
self.assert_pack("I", "I;32S",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
0x01000083, -2097151999)
im = Image.frombytes(mode, (1, 1), data, "raw", rawmode, 0, 1)
if sys.byteorder == 'little':
self.assert_pack("I", "I", 4, 0x04030201, 0x08070605)
self.assert_pack("I", "I;32NS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
0x01000083, -2097151999)
else:
self.assert_pack("I", "I", 4, 0x01020304, 0x05060708)
self.assert_pack("I", "I;32NS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
-2097151999, 0x01000083)
return im.getpixel((0, 0))
def test_F_float(self):
self.assert_pack("F", "F;32F", 4,
1.539989614439558e-36, 4.063216068939723e-34)
def unpack_1(mode, rawmode, value):
assert mode == "1"
im = None
if sys.byteorder == 'little':
self.assert_pack("F", "F", 4,
1.539989614439558e-36, 4.063216068939723e-34)
self.assert_pack("F", "F;32NF", 4,
1.539989614439558e-36, 4.063216068939723e-34)
else:
self.assert_pack("F", "F", 4,
2.387939260590663e-38, 6.301941157072183e-36)
self.assert_pack("F", "F;32NF", 4,
2.387939260590663e-38, 6.301941157072183e-36)
if py3:
im = Image.frombytes(
mode, (8, 1), bytes([value]), "raw", rawmode, 0, 1)
else:
im = Image.frombytes(
mode, (8, 1), chr(value), "raw", rawmode, 0, 1)
return tuple(im.getdata())
class TestLibUnpack(PillowTestCase):
def assert_unpack(self, mode, rawmode, data, *pixels):
"""
data - either raw bytes with data or just number of bytes in rawmode.
"""
if isinstance(data, (int)):
data_len = data * len(pixels)
data = bytes(bytearray(range(1, data_len + 1)))
X = 255
im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1)
self.assertEqual(unpack_1("1", "1", 1), (0, 0, 0, 0, 0, 0, 0, X))
self.assertEqual(unpack_1("1", "1;I", 1), (X, X, X, X, X, X, X, 0))
self.assertEqual(unpack_1("1", "1;R", 1), (X, 0, 0, 0, 0, 0, 0, 0))
self.assertEqual(unpack_1("1", "1;IR", 1), (0, X, X, X, X, X, X, X))
for x, pixel in enumerate(pixels):
self.assertEqual(pixel, im.getpixel((x, 0)))
self.assertEqual(unpack_1("1", "1", 170), (X, 0, X, 0, X, 0, X, 0))
self.assertEqual(unpack_1("1", "1;I", 170), (0, X, 0, X, 0, X, 0, X))
self.assertEqual(unpack_1("1", "1;R", 170), (0, X, 0, X, 0, X, 0, X))
self.assertEqual(unpack_1("1", "1;IR", 170), (X, 0, X, 0, X, 0, X, 0))
def test_1(self):
self.assert_unpack("1", "1", b'\x01', 0, 0, 0, 0, 0, 0, 0, X)
self.assert_unpack("1", "1;I", b'\x01', X, X, X, X, X, X, X, 0)
self.assert_unpack("1", "1;R", b'\x01', X, 0, 0, 0, 0, 0, 0, 0)
self.assert_unpack("1", "1;IR", b'\x01', 0, X, X, X, X, X, X, X)
self.assertEqual(unpack("L", "L;2", 1), 0)
self.assertEqual(unpack("L", "L;4", 1), 0)
self.assertEqual(unpack("L", "L", 1), 1)
self.assertEqual(unpack("L", "L;I", 1), 254)
self.assertEqual(unpack("L", "L;R", 1), 128)
self.assertEqual(unpack("L", "L;16", 2), 2) # little endian
self.assertEqual(unpack("L", "L;16B", 2), 1) # big endian
self.assert_unpack("1", "1", b'\xaa', X, 0, X, 0, X, 0, X, 0)
self.assert_unpack("1", "1;I", b'\xaa', 0, X, 0, X, 0, X, 0, X)
self.assert_unpack("1", "1;R", b'\xaa', 0, X, 0, X, 0, X, 0, X)
self.assert_unpack("1", "1;IR", b'\xaa', X, 0, X, 0, X, 0, X, 0)
self.assertEqual(unpack("LA", "LA", 2), (1, 2))
self.assertEqual(unpack("LA", "LA;L", 2), (1, 2))
self.assert_unpack("1", "1;8", b'\x00\x01\x02\xff', 0, X, X, X)
self.assertEqual(unpack("RGB", "RGB", 3), (1, 2, 3))
self.assertEqual(unpack("RGB", "RGB;L", 3), (1, 2, 3))
self.assertEqual(unpack("RGB", "RGB;R", 3), (128, 64, 192))
self.assertEqual(unpack("RGB", "RGB;16B", 6), (1, 3, 5)) # ?
self.assertEqual(unpack("RGB", "BGR", 3), (3, 2, 1))
self.assertEqual(unpack("RGB", "RGB;15", 2), (8, 131, 0))
self.assertEqual(unpack("RGB", "BGR;15", 2), (0, 131, 8))
self.assertEqual(unpack("RGB", "RGB;16", 2), (8, 64, 0))
self.assertEqual(unpack("RGB", "BGR;16", 2), (0, 64, 8))
self.assertEqual(unpack("RGB", "RGB;4B", 2), (17, 0, 34))
def test_L(self):
self.assert_unpack("L", "L;2", b'\xe4', 255, 170, 85, 0)
self.assert_unpack("L", "L;2I", b'\xe4', 0, 85, 170, 255)
self.assert_unpack("L", "L;2R", b'\xe4', 0, 170, 85, 255)
self.assert_unpack("L", "L;2IR", b'\xe4', 255, 85, 170, 0)
self.assertEqual(unpack("RGB", "RGBX", 4), (1, 2, 3))
self.assertEqual(unpack("RGB", "BGRX", 4), (3, 2, 1))
self.assertEqual(unpack("RGB", "XRGB", 4), (2, 3, 4))
self.assertEqual(unpack("RGB", "XBGR", 4), (4, 3, 2))
self.assert_unpack("L", "L;4", b'\x02\xef', 0, 34, 238, 255)
self.assert_unpack("L", "L;4I", b'\x02\xef', 255, 221, 17, 0)
self.assert_unpack("L", "L;4R", b'\x02\xef', 68, 0, 255, 119)
self.assert_unpack("L", "L;4IR", b'\x02\xef', 187, 255, 0, 136)
self.assertEqual(unpack("RGBA", "RGBA", 4), (1, 2, 3, 4))
self.assertEqual(unpack("RGBA", "RGBa", 4), (63, 127, 191, 4))
self.assertEqual(unpack("RGBA", "BGRA", 4), (3, 2, 1, 4))
self.assertEqual(unpack("RGBA", "BGRa", 4), (191, 127, 63, 4))
self.assertEqual(unpack("RGBA", "ARGB", 4), (2, 3, 4, 1))
self.assertEqual(unpack("RGBA", "ABGR", 4), (4, 3, 2, 1))
self.assertEqual(unpack("RGBA", "RGBA;15", 2), (8, 131, 0, 0))
self.assertEqual(unpack("RGBA", "BGRA;15", 2), (0, 131, 8, 0))
self.assertEqual(unpack("RGBA", "RGBA;4B", 2), (17, 0, 34, 0))
self.assert_unpack("L", "L", 1, 1, 2, 3, 4)
self.assert_unpack("L", "L;I", 1, 254, 253, 252, 251)
self.assert_unpack("L", "L;R", 1, 128, 64, 192, 32)
self.assert_unpack("L", "L;16", 2, 2, 4, 6, 8)
self.assert_unpack("L", "L;16B", 2, 1, 3, 5, 7)
self.assertEqual(unpack("RGBa", "RGBa", 4), (1, 2, 3, 4))
self.assertEqual(unpack("RGBa", "BGRa", 4), (3, 2, 1, 4))
self.assertEqual(unpack("RGBa", "aRGB", 4), (2, 3, 4, 1))
self.assertEqual(unpack("RGBa", "aBGR", 4), (4, 3, 2, 1))
def test_LA(self):
self.assert_unpack("LA", "LA", 2, (1, 2), (3, 4), (5, 6))
self.assert_unpack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6))
self.assertEqual(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255?
self.assertEqual(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255))
self.assertEqual(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255))
self.assertEqual(unpack("RGBX", "XBGR", 4), (4, 3, 2, 255))
self.assertEqual(unpack("RGBX", "RGB;15", 2), (8, 131, 0, 255))
self.assertEqual(unpack("RGBX", "BGR;15", 2), (0, 131, 8, 255))
self.assertEqual(unpack("RGBX", "RGB;4B", 2), (17, 0, 34, 255))
def test_P(self):
self.assert_unpack("P", "P;1", b'\xe4', 1, 1, 1, 0, 0, 1, 0, 0)
self.assert_unpack("P", "P;2", b'\xe4', 3, 2, 1, 0)
# self.assert_unpack("P", "P;2L", b'\xe4', 1, 1, 1, 0) # erroneous?
self.assert_unpack("P", "P;4", b'\x02\xef', 0, 2, 14, 15)
# self.assert_unpack("P", "P;4L", b'\x02\xef', 2, 10, 10, 0) # erroneous?
self.assert_unpack("P", "P", 1, 1, 2, 3, 4)
self.assert_unpack("P", "P;R", 1, 128, 64, 192, 32)
self.assertEqual(unpack("CMYK", "CMYK", 4), (1, 2, 3, 4))
self.assertEqual(unpack("CMYK", "CMYK;I", 4), (254, 253, 252, 251))
def test_PA(self):
self.assert_unpack("PA", "PA", 2, (1, 2), (3, 4), (5, 6))
self.assert_unpack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6))
self.assertRaises(ValueError, lambda: unpack("L", "L", 0))
self.assertRaises(ValueError, lambda: unpack("RGB", "RGB", 2))
self.assertRaises(ValueError, lambda: unpack("CMYK", "CMYK", 2))
def test_RGB(self):
self.assert_unpack("RGB", "RGB", 3, (1,2,3), (4,5,6), (7,8,9))
self.assert_unpack("RGB", "RGB;L", 3, (1,4,7), (2,5,8), (3,6,9))
self.assert_unpack("RGB", "RGB;R", 3, (128,64,192), (32,160,96))
self.assert_unpack("RGB", "RGB;16L", 6, (2,4,6), (8,10,12))
self.assert_unpack("RGB", "RGB;16B", 6, (1,3,5), (7,9,11))
self.assert_unpack("RGB", "BGR", 3, (3,2,1), (6,5,4), (9,8,7))
self.assert_unpack("RGB", "RGB;15", 2, (8,131,0), (24,0,8))
self.assert_unpack("RGB", "BGR;15", 2, (0,131,8), (8,0,24))
self.assert_unpack("RGB", "RGB;16", 2, (8,64,0), (24,129,0))
self.assert_unpack("RGB", "BGR;16", 2, (0,64,8), (0,129,24))
self.assert_unpack("RGB", "RGB;4B", 2, (17,0,34), (51,0,68))
self.assert_unpack("RGB", "RGBX", 4, (1,2,3), (5,6,7), (9,10,11))
self.assert_unpack("RGB", "RGBX;L", 4, (1,4,7), (2,5,8), (3,6,9))
self.assert_unpack("RGB", "BGRX", 4, (3,2,1), (7,6,5), (11,10,9))
self.assert_unpack("RGB", "XRGB", 4, (2,3,4), (6,7,8), (10,11,12))
self.assert_unpack("RGB", "XBGR", 4, (4,3,2), (8,7,6), (12,11,10))
self.assert_unpack("RGB", "YCC;P",
b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data
(127,102,0), (192,227,0), (213,255,170), (98,255,133))
self.assert_unpack("RGB", "R", 1, (1,0,0), (2,0,0), (3,0,0))
self.assert_unpack("RGB", "G", 1, (0,1,0), (0,2,0), (0,3,0))
self.assert_unpack("RGB", "B", 1, (0,0,1), (0,0,2), (0,0,3))
def test_RGBA(self):
self.assert_unpack("RGBA", "LA", 2, (1,1,1,2), (3,3,3,4), (5,5,5,6))
self.assert_unpack("RGBA", "LA;16B", 4,
(1,1,1,3), (5,5,5,7), (9,9,9,11))
self.assert_unpack("RGBA", "RGBA", 4,
(1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_unpack("RGBA", "RGBa", 4,
(63,127,191,4), (159,191,223,8), (191,212,233,12))
self.assert_unpack("RGBA", "RGBa",
b'\x01\x02\x03\x00\x10\x20\x30\xff',
(0,0,0,0), (16,32,48,255))
self.assert_unpack("RGBA", "RGBa;16L", 8,
(63,127,191,8), (159,191,223,16), (191,212,233,24))
self.assert_unpack("RGBA", "RGBa;16L",
b'\x88\x01\x88\x02\x88\x03\x88\x00'
b'\x88\x10\x88\x20\x88\x30\x88\xff',
(0,0,0,0), (16,32,48,255))
self.assert_unpack("RGBA", "RGBa;16B", 8,
(36,109,182,7), (153,187,221,15), (188,210,232,23))
self.assert_unpack("RGBA", "RGBa;16B",
b'\x01\x88\x02\x88\x03\x88\x00\x88'
b'\x10\x88\x20\x88\x30\x88\xff\x88',
(0,0,0,0), (16,32,48,255))
self.assert_unpack("RGBA", "BGRa", 4,
(191,127,63,4), (223,191,159,8), (233,212,191,12))
self.assert_unpack("RGBA", "BGRa",
b'\x01\x02\x03\x00\x10\x20\x30\xff',
(0,0,0,0), (48,32,16,255))
self.assert_unpack("RGBA", "RGBA;I", 4,
(254,253,252,4), (250,249,248,8), (246,245,244,12))
self.assert_unpack("RGBA", "RGBA;L", 4,
(1,4,7,10), (2,5,8,11), (3,6,9,12))
self.assert_unpack("RGBA", "RGBA;15", 2, (8,131,0,0), (24,0,8,0))
self.assert_unpack("RGBA", "BGRA;15", 2, (0,131,8,0), (8,0,24,0))
self.assert_unpack("RGBA", "RGBA;4B", 2, (17,0,34,0), (51,0,68,0))
self.assert_unpack("RGBA", "RGBA;16L", 8, (2,4,6,8), (10,12,14,16))
self.assert_unpack("RGBA", "RGBA;16B", 8, (1,3,5,7), (9,11,13,15))
self.assert_unpack("RGBA", "BGRA", 4,
(3,2,1,4), (7,6,5,8), (11,10,9,12))
self.assert_unpack("RGBA", "ARGB", 4,
(2,3,4,1), (6,7,8,5), (10,11,12,9))
self.assert_unpack("RGBA", "ABGR", 4,
(4,3,2,1), (8,7,6,5), (12,11,10,9))
self.assert_unpack("RGBA", "YCCA;P",
b']bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11', # random data
(0,161,0,4), (255,255,255,237), (27,158,0,206), (0,118,0,17))
self.assert_unpack("RGBA", "R", 1, (1,0,0,0), (2,0,0,0), (3,0,0,0))
self.assert_unpack("RGBA", "G", 1, (0,1,0,0), (0,2,0,0), (0,3,0,0))
self.assert_unpack("RGBA", "B", 1, (0,0,1,0), (0,0,2,0), (0,0,3,0))
self.assert_unpack("RGBA", "A", 1, (0,0,0,1), (0,0,0,2), (0,0,0,3))
def test_RGBa(self):
self.assert_unpack("RGBa", "RGBa", 4,
(1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_unpack("RGBa", "BGRa", 4,
(3,2,1,4), (7,6,5,8), (11,10,9,12))
self.assert_unpack("RGBa", "aRGB", 4,
(2,3,4,1), (6,7,8,5), (10,11,12,9))
self.assert_unpack("RGBa", "aBGR", 4,
(4,3,2,1), (8,7,6,5), (12,11,10,9))
def test_RGBX(self):
self.assert_unpack("RGBX", "RGB", 3, (1,2,3,X), (4,5,6,X), (7,8,9,X))
self.assert_unpack("RGBX", "RGB;L", 3, (1,4,7,X), (2,5,8,X), (3,6,9,X))
self.assert_unpack("RGBX", "RGB;16B", 6, (1,3,5,X), (7,9,11,X))
self.assert_unpack("RGBX", "BGR", 3, (3,2,1,X), (6,5,4,X), (9,8,7,X))
self.assert_unpack("RGBX", "RGB;15", 2, (8,131,0,X), (24,0,8,X))
self.assert_unpack("RGBX", "BGR;15", 2, (0,131,8,X), (8,0,24,X))
self.assert_unpack("RGBX", "RGB;4B", 2, (17,0,34,X), (51,0,68,X))
self.assert_unpack("RGBX", "RGBX", 4,
(1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_unpack("RGBX", "RGBX;L", 4,
(1,4,7,10), (2,5,8,11), (3,6,9,12))
self.assert_unpack("RGBX", "RGBX;16L", 8, (2,4,6,8), (10,12,14,16))
self.assert_unpack("RGBX", "RGBX;16B", 8, (1,3,5,7), (9,11,13,15))
self.assert_unpack("RGBX", "BGRX", 4, (3,2,1,X), (7,6,5,X), (11,10,9,X))
self.assert_unpack("RGBX", "XRGB", 4, (2,3,4,X), (6,7,8,X), (10,11,12,X))
self.assert_unpack("RGBX", "XBGR", 4, (4,3,2,X), (8,7,6,X), (12,11,10,X))
self.assert_unpack("RGBX", "YCC;P",
b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data
(127,102,0,X), (192,227,0,X), (213,255,170,X), (98,255,133,X))
self.assert_unpack("RGBX", "R", 1, (1,0,0,0), (2,0,0,0), (3,0,0,0))
self.assert_unpack("RGBX", "G", 1, (0,1,0,0), (0,2,0,0), (0,3,0,0))
self.assert_unpack("RGBX", "B", 1, (0,0,1,0), (0,0,2,0), (0,0,3,0))
self.assert_unpack("RGBX", "X", 1, (0,0,0,1), (0,0,0,2), (0,0,0,3))
def test_CMYK(self):
self.assert_unpack("CMYK", "CMYK", 4, (1,2,3,4), (5,6,7,8), (9,10,11,12))
self.assert_unpack("CMYK", "CMYK;I", 4,
(254,253,252,251), (250,249,248,247), (246,245,244,243))
self.assert_unpack("CMYK", "CMYK;L", 4,
(1,4,7,10), (2,5,8,11), (3,6,9,12))
self.assert_unpack("CMYK", "C", 1, (1,0,0,0), (2,0,0,0), (3,0,0,0))
self.assert_unpack("CMYK", "M", 1, (0,1,0,0), (0,2,0,0), (0,3,0,0))
self.assert_unpack("CMYK", "Y", 1, (0,0,1,0), (0,0,2,0), (0,0,3,0))
self.assert_unpack("CMYK", "K", 1, (0,0,0,1), (0,0,0,2), (0,0,0,3))
self.assert_unpack("CMYK", "C;I", 1,
(254,0,0,0), (253,0,0,0), (252,0,0,0))
self.assert_unpack("CMYK", "M;I", 1,
(0,254,0,0), (0,253,0,0), (0,252,0,0))
self.assert_unpack("CMYK", "Y;I", 1,
(0,0,254,0), (0,0,253,0), (0,0,252,0))
self.assert_unpack("CMYK", "K;I", 1,
(0,0,0,254), (0,0,0,253), (0,0,0,252))
def test_YCbCr(self):
self.assert_unpack("YCbCr", "YCbCr", 3, (1,2,3), (4,5,6), (7,8,9))
self.assert_unpack("YCbCr", "YCbCr;L", 3, (1,4,7), (2,5,8), (3,6,9))
self.assert_unpack("YCbCr", "YCbCrX", 4, (1,2,3), (5,6,7), (9,10,11))
self.assert_unpack("YCbCr", "YCbCrK", 4, (1,2,3), (5,6,7), (9,10,11))
def test_LAB(self):
self.assert_unpack("LAB", "LAB", 3,
(1,130,131), (4,133,134), (7,136,137))
self.assert_unpack("LAB", "L", 1, (1,0,0), (2,0,0), (3,0,0))
self.assert_unpack("LAB", "A", 1, (0,1,0), (0,2,0), (0,3,0))
self.assert_unpack("LAB", "B", 1, (0,0,1), (0,0,2), (0,0,3))
def test_HSV(self):
self.assert_unpack("HSV", "HSV", 3, (1,2,3), (4,5,6), (7,8,9))
self.assert_unpack("HSV", "H", 1, (1,0,0), (2,0,0), (3,0,0))
self.assert_unpack("HSV", "S", 1, (0,1,0), (0,2,0), (0,3,0))
self.assert_unpack("HSV", "V", 1, (0,0,1), (0,0,2), (0,0,3))
def test_I(self):
self.assert_unpack("I", "I;8", 1, 0x01, 0x02, 0x03, 0x04)
self.assert_unpack("I", "I;8S", b'\x01\x83', 1, -125)
self.assert_unpack("I", "I;16", 2, 0x0201, 0x0403)
self.assert_unpack("I", "I;16S", b'\x83\x01\x01\x83', 0x0183, -31999)
self.assert_unpack("I", "I;16B", 2, 0x0102, 0x0304)
self.assert_unpack("I", "I;16BS", b'\x83\x01\x01\x83', -31999, 0x0183)
self.assert_unpack("I", "I;32", 4, 0x04030201, 0x08070605)
self.assert_unpack("I", "I;32S",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
0x01000083, -2097151999)
self.assert_unpack("I", "I;32B", 4, 0x01020304, 0x05060708)
self.assert_unpack("I", "I;32BS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
-2097151999, 0x01000083)
if sys.byteorder == 'little':
self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605)
self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403)
self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', 0x0183, -31999)
self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605)
self.assert_unpack("I", "I;32NS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
0x01000083, -2097151999)
else:
self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708)
self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304)
self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', -31999, 0x0183)
self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708)
self.assert_unpack("I", "I;32NS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
-2097151999, 0x01000083)
def test_F_int(self):
self.assert_unpack("F", "F;8", 1, 0x01, 0x02, 0x03, 0x04)
self.assert_unpack("F", "F;8S", b'\x01\x83', 1, -125)
self.assert_unpack("F", "F;16", 2, 0x0201, 0x0403)
self.assert_unpack("F", "F;16S", b'\x83\x01\x01\x83', 0x0183, -31999)
self.assert_unpack("F", "F;16B", 2, 0x0102, 0x0304)
self.assert_unpack("F", "F;16BS", b'\x83\x01\x01\x83', -31999, 0x0183)
self.assert_unpack("F", "F;32", 4, 67305984, 134678016)
self.assert_unpack("F", "F;32S",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
16777348, -2097152000)
self.assert_unpack("F", "F;32B", 4, 0x01020304, 0x05060708)
self.assert_unpack("F", "F;32BS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
-2097152000, 16777348)
if sys.byteorder == 'little':
self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403)
self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', 0x0183, -31999)
self.assert_unpack("F", "F;32N", 4, 67305984, 134678016)
self.assert_unpack("F", "F;32NS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
16777348, -2097152000)
else:
self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304)
self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', -31999, 0x0183)
self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708)
self.assert_unpack("F", "F;32NS",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
-2097152000, 16777348)
def test_F_float(self):
self.assert_unpack("F", "F;32F", 4,
1.539989614439558e-36, 4.063216068939723e-34)
self.assert_unpack("F", "F;32BF", 4,
2.387939260590663e-38, 6.301941157072183e-36)
self.assert_unpack("F", "F;64F",
b'333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0', # by struct.pack
0.15000000596046448, -1234.5)
self.assert_unpack("F", "F;64BF",
b'?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00', # by struct.pack
0.15000000596046448, -1234.5)
if sys.byteorder == 'little':
self.assert_unpack("F", "F", 4,
1.539989614439558e-36, 4.063216068939723e-34)
self.assert_unpack("F", "F;32NF", 4,
1.539989614439558e-36, 4.063216068939723e-34)
self.assert_unpack("F", "F;64NF",
b'333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0',
0.15000000596046448, -1234.5)
else:
self.assert_unpack("F", "F", 4,
2.387939260590663e-38, 6.301941157072183e-36)
self.assert_unpack("F", "F;32NF", 4,
2.387939260590663e-38, 6.301941157072183e-36)
self.assert_unpack("F", "F;64NF",
b'?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00',
0.15000000596046448, -1234.5)
def test_I16(self):
self.assert_unpack("I;16", "I;16", 2, 0x0201, 0x0403, 0x0605)
self.assert_unpack("I;16B", "I;16B", 2, 0x0102, 0x0304, 0x0506)
self.assert_unpack("I;16L", "I;16L", 2, 0x0201, 0x0403, 0x0605)
self.assert_unpack("I;16", "I;12", 2, 0x0010, 0x0203, 0x0040)
if sys.byteorder == 'little':
self.assert_unpack("I;16", "I;16N", 2, 0x0201, 0x0403, 0x0605)
self.assert_unpack("I;16B", "I;16N", 2, 0x0201, 0x0403, 0x0605)
self.assert_unpack("I;16L", "I;16N", 2, 0x0201, 0x0403, 0x0605)
else:
self.assert_unpack("I;16", "I;16N", 2, 0x0102, 0x0304, 0x0506)
self.assert_unpack("I;16B", "I;16N", 2, 0x0102, 0x0304, 0x0506)
self.assert_unpack("I;16L", "I;16N", 2, 0x0102, 0x0304, 0x0506)
def test_value_error(self):
self.assertRaises(ValueError, self.assert_unpack, "L", "L", 0, 0)
self.assertRaises(ValueError, self.assert_unpack, "RGB", "RGB", 2, 0)
self.assertRaises(ValueError, self.assert_unpack, "CMYK", "CMYK", 2, 0)
if __name__ == '__main__':

View File

@ -39,7 +39,7 @@ class TestNumpy(PillowTestCase):
def to_image(dtype, bands=1, boolean=0):
if bands == 1:
if boolean:
data = [0, 1] * 50
data = [0, 255] * 50
else:
data = list(range(100))
a = numpy.array(data, dtype=dtype)
@ -58,9 +58,9 @@ class TestNumpy(PillowTestCase):
return i
# Check supported 1-bit integer formats
self.assertRaises(TypeError, lambda: to_image(numpy.bool))
self.assertRaises(TypeError, lambda: to_image(numpy.bool8))
self.assert_image(to_image(numpy.bool, 1, 1), '1', TEST_IMAGE_SIZE)
self.assert_image(to_image(numpy.bool8, 1, 1), '1', TEST_IMAGE_SIZE)
# Check supported 8-bit integer formats
self.assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
self.assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE)
@ -213,5 +213,13 @@ class TestNumpy(PillowTestCase):
self.assertEqual(im.size, (0, 0))
def test_bool(self):
# https://github.com/python-pillow/Pillow/issues/2044
a = numpy.zeros((10,2), dtype=numpy.bool)
a[0][0] = True
im2 = Image.fromarray(a)
self.assertEqual(im2.getdata()[0], 255)
if __name__ == '__main__':
unittest.main()

View File

@ -1507,24 +1507,43 @@ _resize(ImagingObject* self, PyObject* args)
int xsize, ysize;
int filter = IMAGING_TRANSFORM_NEAREST;
if (!PyArg_ParseTuple(args, "(ii)|i", &xsize, &ysize, &filter))
return NULL;
float box[4] = {0, 0, 0, 0};
imIn = self->image;
box[2] = imIn->xsize;
box[3] = imIn->ysize;
if (!PyArg_ParseTuple(args, "(ii)|i(ffff)", &xsize, &ysize, &filter,
&box[0], &box[1], &box[2], &box[3]))
return NULL;
if (xsize < 1 || ysize < 1) {
return ImagingError_ValueError("height and width must be > 0");
}
if (imIn->xsize == xsize && imIn->ysize == ysize) {
if (box[0] < 0 || box[1] < 0) {
return ImagingError_ValueError("box offset can't be negative");
}
if (box[2] > imIn->xsize || box[3] > imIn->ysize) {
return ImagingError_ValueError("box can't exceed original image size");
}
if (box[2] - box[0] < 0 || box[3] - box[1] < 0) {
return ImagingError_ValueError("box can't be empty");
}
if (box[0] == 0 && box[1] == 0 && box[2] == xsize && box[3] == ysize) {
imOut = ImagingCopy(imIn);
}
else if (filter == IMAGING_TRANSFORM_NEAREST) {
double a[6];
memset(a, 0, sizeof a);
a[0] = (double) imIn->xsize / xsize;
a[4] = (double) imIn->ysize / ysize;
a[0] = (double) (box[2] - box[0]) / xsize;
a[4] = (double) (box[3] - box[1]) / ysize;
a[2] = box[0];
a[5] = box[1];
imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
@ -1534,7 +1553,7 @@ _resize(ImagingObject* self, PyObject* args)
a, filter, 1);
}
else {
imOut = ImagingResample(imIn, xsize, ysize, filter);
imOut = ImagingResample(imIn, xsize, ysize, filter, box);
}
return PyImagingNew(imOut);
@ -1892,6 +1911,29 @@ _putband(ImagingObject* self, PyObject* args)
return Py_None;
}
static PyObject*
_merge(PyObject* self, PyObject* args)
{
char* mode;
ImagingObject *band0 = NULL;
ImagingObject *band1 = NULL;
ImagingObject *band2 = NULL;
ImagingObject *band3 = NULL;
Imaging bands[4] = {NULL, NULL, NULL, NULL};
if (!PyArg_ParseTuple(args, "sO!|O!O!O!", &mode,
&Imaging_Type, &band0, &Imaging_Type, &band1,
&Imaging_Type, &band2, &Imaging_Type, &band3))
return NULL;
if (band0) bands[0] = band0->image;
if (band1) bands[1] = band1->image;
if (band2) bands[2] = band2->image;
if (band3) bands[3] = band3->image;
return PyImagingNew(ImagingMerge(mode, bands));
}
static PyObject*
_split(ImagingObject* self, PyObject* args)
{
@ -3329,6 +3371,7 @@ static PyMethodDef functions[] = {
{"blend", (PyCFunction)_blend, 1},
{"fill", (PyCFunction)_fill, 1},
{"new", (PyCFunction)_new, 1},
{"merge", (PyCFunction)_merge, 1},
{"getcount", (PyCFunction)_getcount, 1},

5
depends/termux.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
pkg -y install python python-dev ndk-sysroot clang make \
libjpeg-turbo-dev

View File

@ -23,9 +23,9 @@
#ifdef WORDS_BIGENDIAN
#define MAKE_UINT32(u0, u1, u2, u3) (u3 | (u2<<8) | (u1<<16) | (u0<<24))
#define MAKE_UINT32(u0, u1, u2, u3) (u3 | (u2<<8) | (u1<<16) | (u0<<24))
#else
#define MAKE_UINT32(u0, u1, u2, u3) (u0 | (u1<<8) | (u2<<16) | (u3<<24))
#define MAKE_UINT32(u0, u1, u2, u3) (u0 | (u1<<8) | (u2<<16) | (u3<<24))
#endif
@ -234,3 +234,77 @@ ImagingFillBand(Imaging imOut, int band, int color)
return imOut;
}
Imaging
ImagingMerge(const char* mode, Imaging bands[4])
{
int i, x, y;
int bandsCount = 0;
Imaging imOut;
Imaging firstBand;
firstBand = bands[0];
if ( ! firstBand) {
return (Imaging) ImagingError_ValueError("wrong number of bands");
}
for (i = 0; i < 4; ++i) {
if ( ! bands[i]) {
break;
}
if (bands[i]->bands != 1) {
return (Imaging) ImagingError_ModeError();
}
if (bands[i]->xsize != firstBand->xsize
|| bands[i]->ysize != firstBand->ysize) {
return (Imaging) ImagingError_Mismatch();
}
}
bandsCount = i;
imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize);
if ( ! imOut)
return NULL;
if (imOut->bands != bandsCount) {
ImagingDelete(imOut);
return (Imaging) ImagingError_ValueError("wrong number of bands");
}
if (imOut->bands == 1)
return ImagingCopy2(imOut, firstBand);
if (imOut->bands == 2) {
for (y = 0; y < imOut->ysize; y++) {
UINT8* in0 = bands[0]->image8[y];
UINT8* in1 = bands[1]->image8[y];
UINT32* out = (UINT32*) imOut->image32[y];
for (x = 0; x < imOut->xsize; x++) {
out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]);
}
}
} else if (imOut->bands == 3) {
for (y = 0; y < imOut->ysize; y++) {
UINT8* in0 = bands[0]->image8[y];
UINT8* in1 = bands[1]->image8[y];
UINT8* in2 = bands[2]->image8[y];
UINT32* out = (UINT32*) imOut->image32[y];
for (x = 0; x < imOut->xsize; x++) {
out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0);
}
}
} else if (imOut->bands == 4) {
for (y = 0; y < imOut->ysize; y++) {
UINT8* in0 = bands[0]->image8[y];
UINT8* in1 = bands[1]->image8[y];
UINT8* in2 = bands[2]->image8[y];
UINT8* in3 = bands[3]->image8[y];
UINT32* out = (UINT32*) imOut->image32[y];
for (x = 0; x < imOut->xsize; x++) {
out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]);
}
}
}
return imOut;
}

View File

@ -266,6 +266,7 @@ extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn);
extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius,
int passes);
extern Imaging ImagingGetBand(Imaging im, int band);
extern Imaging ImagingMerge(const char* mode, Imaging bands[4]);
extern int ImagingSplit(Imaging im, Imaging bands[4]);
extern int ImagingGetBBox(Imaging im, int bbox[4]);
typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem;
@ -290,7 +291,7 @@ extern Imaging ImagingRankFilter(Imaging im, int size, int rank);
extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn);
extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn);
extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn);
extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter);
extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]);
extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn);
extern Imaging ImagingTransform(
Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1,

View File

@ -559,8 +559,8 @@ static struct {
/* true colour w. padding */
{"RGBX", "RGBX", 32, copy4},
{"RGBX", "RGBX;L", 32, packRGBXL},
{"RGBX", "RGB", 32, ImagingPackRGB},
{"RGBX", "BGR", 32, ImagingPackBGR},
{"RGBX", "RGB", 24, ImagingPackRGB},
{"RGBX", "BGR", 24, ImagingPackBGR},
{"RGBX", "BGRX", 32, ImagingPackBGRX},
{"RGBX", "XBGR", 32, ImagingPackXBGR},
{"RGBX", "R", 8, band0},

View File

@ -134,16 +134,16 @@ static inline UINT8 clip8(int in)
int
precompute_coeffs(int inSize, int outSize, struct filter *filterp,
int **xboundsp, double **kkp) {
precompute_coeffs(int inSize, float in0, float in1, int outSize,
struct filter *filterp, int **boundsp, double **kkp) {
double support, scale, filterscale;
double center, ww, ss;
int xx, x, kmax, xmin, xmax;
int *xbounds;
int xx, x, ksize, xmin, xmax;
int *bounds;
double *kk, *k;
/* prepare for horizontal stretch */
filterscale = scale = (double) inSize / outSize;
filterscale = scale = (double) (in1 - in0) / outSize;
if (filterscale < 1.0) {
filterscale = 1.0;
}
@ -152,27 +152,32 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp,
support = filterp->support * filterscale;
/* maximum number of coeffs */
kmax = (int) ceil(support) * 2 + 1;
ksize = (int) ceil(support) * 2 + 1;
// check for overflow
if (outSize > INT_MAX / (kmax * sizeof(double)))
if (outSize > INT_MAX / (ksize * sizeof(double))) {
ImagingError_MemoryError();
return 0;
}
/* coefficient buffer */
/* malloc check ok, overflow checked above */
kk = malloc(outSize * kmax * sizeof(double));
if ( ! kk)
kk = malloc(outSize * ksize * sizeof(double));
if ( ! kk) {
ImagingError_MemoryError();
return 0;
}
/* malloc check ok, kmax*sizeof(double) > 2*sizeof(int) */
xbounds = malloc(outSize * 2 * sizeof(int));
if ( ! xbounds) {
/* malloc check ok, ksize*sizeof(double) > 2*sizeof(int) */
bounds = malloc(outSize * 2 * sizeof(int));
if ( ! bounds) {
free(kk);
ImagingError_MemoryError();
return 0;
}
for (xx = 0; xx < outSize; xx++) {
center = (xx + 0.5) * scale;
center = in0 + (xx + 0.5) * scale;
ww = 0.0;
ss = 1.0 / filterscale;
// Round the value
@ -184,7 +189,7 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp,
if (xmax > inSize)
xmax = inSize;
xmax -= xmin;
k = &kk[xx * kmax];
k = &kk[xx * ksize];
for (x = 0; x < xmax; x++) {
double w = filterp->filter((x + xmin - center + 0.5) * ss);
k[x] = w;
@ -195,98 +200,75 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp,
k[x] /= ww;
}
// Remaining values should stay empty if they are used despite of xmax.
for (; x < kmax; x++) {
for (; x < ksize; x++) {
k[x] = 0;
}
xbounds[xx * 2 + 0] = xmin;
xbounds[xx * 2 + 1] = xmax;
bounds[xx * 2 + 0] = xmin;
bounds[xx * 2 + 1] = xmax;
}
*xboundsp = xbounds;
*boundsp = bounds;
*kkp = kk;
return kmax;
return ksize;
}
int
normalize_coeffs_8bpc(int outSize, int kmax, double *prekk, INT32 **kkp)
void
normalize_coeffs_8bpc(int outSize, int ksize, double *prekk)
{
int x;
INT32 *kk;
/* malloc check ok, overflow checked in precompute_coeffs */
kk = malloc(outSize * kmax * sizeof(INT32));
if ( ! kk) {
return 0;
}
// use the same buffer for normalized coefficients
kk = (INT32 *) prekk;
for (x = 0; x < outSize * kmax; x++) {
for (x = 0; x < outSize * ksize; x++) {
if (prekk[x] < 0) {
kk[x] = (int) (-0.5 + prekk[x] * (1 << PRECISION_BITS));
} else {
kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS));
}
}
*kkp = kk;
return kmax;
}
Imaging
ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
void
ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset,
int ksize, int *bounds, double *prekk)
{
ImagingSectionCookie cookie;
Imaging imOut;
int ss0, ss1, ss2, ss3;
int xx, yy, x, kmax, xmin, xmax;
int *xbounds;
int xx, yy, x, xmin, xmax;
INT32 *k, *kk;
double *prekk;
kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &prekk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
kmax = normalize_coeffs_8bpc(xsize, kmax, prekk, &kk);
free(prekk);
if ( ! kmax) {
free(xbounds);
return (Imaging) ImagingError_MemoryError();
}
imOut = ImagingNewDirty(imIn->mode, xsize, imIn->ysize);
if ( ! imOut) {
free(kk);
free(xbounds);
return NULL;
}
// use the same buffer for normalized coefficients
kk = (INT32 *) prekk;
normalize_coeffs_8bpc(imOut->xsize, ksize, prekk);
ImagingSectionEnter(&cookie);
if (imIn->image8) {
for (yy = 0; yy < imOut->ysize; yy++) {
for (xx = 0; xx < xsize; xx++) {
xmin = xbounds[xx * 2 + 0];
xmax = xbounds[xx * 2 + 1];
k = &kk[xx * kmax];
for (xx = 0; xx < imOut->xsize; xx++) {
xmin = bounds[xx * 2 + 0];
xmax = bounds[xx * 2 + 1];
k = &kk[xx * ksize];
ss0 = 1 << (PRECISION_BITS -1);
for (x = 0; x < xmax; x++)
ss0 += ((UINT8) imIn->image8[yy][x + xmin]) * k[x];
ss0 += ((UINT8) imIn->image8[yy + offset][x + xmin]) * k[x];
imOut->image8[yy][xx] = clip8(ss0);
}
}
} else if (imIn->type == IMAGING_TYPE_UINT8) {
if (imIn->bands == 2) {
for (yy = 0; yy < imOut->ysize; yy++) {
for (xx = 0; xx < xsize; xx++) {
xmin = xbounds[xx * 2 + 0];
xmax = xbounds[xx * 2 + 1];
k = &kk[xx * kmax];
for (xx = 0; xx < imOut->xsize; xx++) {
xmin = bounds[xx * 2 + 0];
xmax = bounds[xx * 2 + 1];
k = &kk[xx * ksize];
ss0 = ss3 = 1 << (PRECISION_BITS -1);
for (x = 0; x < xmax; x++) {
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x];
}
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
clip8(ss0), 0, 0, clip8(ss3));
@ -294,15 +276,15 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
}
} else if (imIn->bands == 3) {
for (yy = 0; yy < imOut->ysize; yy++) {
for (xx = 0; xx < xsize; xx++) {
xmin = xbounds[xx * 2 + 0];
xmax = xbounds[xx * 2 + 1];
k = &kk[xx * kmax];
for (xx = 0; xx < imOut->xsize; xx++) {
xmin = bounds[xx * 2 + 0];
xmax = bounds[xx * 2 + 1];
k = &kk[xx * ksize];
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
for (x = 0; x < xmax; x++) {
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
ss1 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 1]) * k[x];
ss2 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 2]) * k[x];
ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x];
ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x];
}
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
clip8(ss0), clip8(ss1), clip8(ss2), 0);
@ -310,16 +292,16 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
}
} else {
for (yy = 0; yy < imOut->ysize; yy++) {
for (xx = 0; xx < xsize; xx++) {
xmin = xbounds[xx * 2 + 0];
xmax = xbounds[xx * 2 + 1];
k = &kk[xx * kmax];
for (xx = 0; xx < imOut->xsize; xx++) {
xmin = bounds[xx * 2 + 0];
xmax = bounds[xx * 2 + 1];
k = &kk[xx * ksize];
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
for (x = 0; x < xmax; x++) {
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
ss1 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 1]) * k[x];
ss2 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 2]) * k[x];
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x];
ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x];
ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x];
}
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
@ -327,50 +309,29 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
}
}
}
ImagingSectionLeave(&cookie);
free(kk);
free(xbounds);
return imOut;
}
Imaging
ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
void
ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset,
int ksize, int *bounds, double *prekk)
{
ImagingSectionCookie cookie;
Imaging imOut;
int ss0, ss1, ss2, ss3;
int xx, yy, y, kmax, ymin, ymax;
int *xbounds;
int xx, yy, y, ymin, ymax;
INT32 *k, *kk;
double *prekk;
kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &prekk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
kmax = normalize_coeffs_8bpc(ysize, kmax, prekk, &kk);
free(prekk);
if ( ! kmax) {
free(xbounds);
return (Imaging) ImagingError_MemoryError();
}
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
if ( ! imOut) {
free(kk);
free(xbounds);
return NULL;
}
// use the same buffer for normalized coefficients
kk = (INT32 *) prekk;
normalize_coeffs_8bpc(imOut->ysize, ksize, prekk);
ImagingSectionEnter(&cookie);
if (imIn->image8) {
for (yy = 0; yy < ysize; yy++) {
k = &kk[yy * kmax];
ymin = xbounds[yy * 2 + 0];
ymax = xbounds[yy * 2 + 1];
for (yy = 0; yy < imOut->ysize; yy++) {
k = &kk[yy * ksize];
ymin = bounds[yy * 2 + 0];
ymax = bounds[yy * 2 + 1];
for (xx = 0; xx < imOut->xsize; xx++) {
ss0 = 1 << (PRECISION_BITS -1);
for (y = 0; y < ymax; y++)
@ -380,10 +341,10 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
}
} else if (imIn->type == IMAGING_TYPE_UINT8) {
if (imIn->bands == 2) {
for (yy = 0; yy < ysize; yy++) {
k = &kk[yy * kmax];
ymin = xbounds[yy * 2 + 0];
ymax = xbounds[yy * 2 + 1];
for (yy = 0; yy < imOut->ysize; yy++) {
k = &kk[yy * ksize];
ymin = bounds[yy * 2 + 0];
ymax = bounds[yy * 2 + 1];
for (xx = 0; xx < imOut->xsize; xx++) {
ss0 = ss3 = 1 << (PRECISION_BITS -1);
for (y = 0; y < ymax; y++) {
@ -395,10 +356,10 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
}
}
} else if (imIn->bands == 3) {
for (yy = 0; yy < ysize; yy++) {
k = &kk[yy * kmax];
ymin = xbounds[yy * 2 + 0];
ymax = xbounds[yy * 2 + 1];
for (yy = 0; yy < imOut->ysize; yy++) {
k = &kk[yy * ksize];
ymin = bounds[yy * 2 + 0];
ymax = bounds[yy * 2 + 1];
for (xx = 0; xx < imOut->xsize; xx++) {
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
for (y = 0; y < ymax; y++) {
@ -411,10 +372,10 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
}
}
} else {
for (yy = 0; yy < ysize; yy++) {
k = &kk[yy * kmax];
ymin = xbounds[yy * 2 + 0];
ymax = xbounds[yy * 2 + 1];
for (yy = 0; yy < imOut->ysize; yy++) {
k = &kk[yy * ksize];
ymin = bounds[yy * 2 + 0];
ymax = bounds[yy * 2 + 1];
for (xx = 0; xx < imOut->xsize; xx++) {
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
for (y = 0; y < ymax; y++) {
@ -429,47 +390,30 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
}
}
}
ImagingSectionLeave(&cookie);
free(kk);
free(xbounds);
return imOut;
}
Imaging
ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
void
ImagingResampleHorizontal_32bpc(Imaging imOut, Imaging imIn, int offset,
int ksize, int *bounds, double *kk)
{
ImagingSectionCookie cookie;
Imaging imOut;
double ss;
int xx, yy, x, kmax, xmin, xmax;
int *xbounds;
double *k, *kk;
kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &kk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
imOut = ImagingNewDirty(imIn->mode, xsize, imIn->ysize);
if ( ! imOut) {
free(kk);
free(xbounds);
return NULL;
}
int xx, yy, x, xmin, xmax;
double *k;
ImagingSectionEnter(&cookie);
switch(imIn->type) {
case IMAGING_TYPE_INT32:
for (yy = 0; yy < imOut->ysize; yy++) {
for (xx = 0; xx < xsize; xx++) {
xmin = xbounds[xx * 2 + 0];
xmax = xbounds[xx * 2 + 1];
k = &kk[xx * kmax];
for (xx = 0; xx < imOut->xsize; xx++) {
xmin = bounds[xx * 2 + 0];
xmax = bounds[xx * 2 + 1];
k = &kk[xx * ksize];
ss = 0.0;
for (x = 0; x < xmax; x++)
ss += IMAGING_PIXEL_I(imIn, x + xmin, yy) * k[x];
ss += IMAGING_PIXEL_I(imIn, x + xmin, yy + offset) * k[x];
IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
}
}
@ -477,55 +421,38 @@ ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
case IMAGING_TYPE_FLOAT32:
for (yy = 0; yy < imOut->ysize; yy++) {
for (xx = 0; xx < xsize; xx++) {
xmin = xbounds[xx * 2 + 0];
xmax = xbounds[xx * 2 + 1];
k = &kk[xx * kmax];
for (xx = 0; xx < imOut->xsize; xx++) {
xmin = bounds[xx * 2 + 0];
xmax = bounds[xx * 2 + 1];
k = &kk[xx * ksize];
ss = 0.0;
for (x = 0; x < xmax; x++)
ss += IMAGING_PIXEL_F(imIn, x + xmin, yy) * k[x];
ss += IMAGING_PIXEL_F(imIn, x + xmin, yy + offset) * k[x];
IMAGING_PIXEL_F(imOut, xx, yy) = ss;
}
}
break;
}
ImagingSectionLeave(&cookie);
free(kk);
free(xbounds);
return imOut;
}
Imaging
ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
void
ImagingResampleVertical_32bpc(Imaging imOut, Imaging imIn, int offset,
int ksize, int *bounds, double *kk)
{
ImagingSectionCookie cookie;
Imaging imOut;
double ss;
int xx, yy, y, kmax, ymin, ymax;
int *xbounds;
double *k, *kk;
kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &kk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
if ( ! imOut) {
free(kk);
free(xbounds);
return NULL;
}
int xx, yy, y, ymin, ymax;
double *k;
ImagingSectionEnter(&cookie);
switch(imIn->type) {
case IMAGING_TYPE_INT32:
for (yy = 0; yy < ysize; yy++) {
ymin = xbounds[yy * 2 + 0];
ymax = xbounds[yy * 2 + 1];
k = &kk[yy * kmax];
for (yy = 0; yy < imOut->ysize; yy++) {
ymin = bounds[yy * 2 + 0];
ymax = bounds[yy * 2 + 1];
k = &kk[yy * ksize];
for (xx = 0; xx < imOut->xsize; xx++) {
ss = 0.0;
for (y = 0; y < ymax; y++)
@ -536,10 +463,10 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
break;
case IMAGING_TYPE_FLOAT32:
for (yy = 0; yy < ysize; yy++) {
ymin = xbounds[yy * 2 + 0];
ymax = xbounds[yy * 2 + 1];
k = &kk[yy * kmax];
for (yy = 0; yy < imOut->ysize; yy++) {
ymin = bounds[yy * 2 + 0];
ymax = bounds[yy * 2 + 1];
k = &kk[yy * ksize];
for (xx = 0; xx < imOut->xsize; xx++) {
ss = 0.0;
for (y = 0; y < ymax; y++)
@ -549,22 +476,27 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
}
break;
}
ImagingSectionLeave(&cookie);
free(kk);
free(xbounds);
return imOut;
}
typedef void (*ResampleFunction)(Imaging imOut, Imaging imIn, int offset,
int ksize, int *bounds, double *kk);
Imaging
ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
ImagingResampleInner(Imaging imIn, int xsize, int ysize,
struct filter *filterp, float box[4],
ResampleFunction ResampleHorizontal,
ResampleFunction ResampleVertical);
Imaging
ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4])
{
Imaging imTemp = NULL;
Imaging imOut = NULL;
struct filter *filterp;
Imaging (*ResampleHorizontal)(Imaging imIn, int xsize, struct filter *filterp);
Imaging (*ResampleVertical)(Imaging imIn, int xsize, struct filter *filterp);
ResampleFunction ResampleHorizontal;
ResampleFunction ResampleVertical;
if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
return (Imaging) ImagingError_ModeError();
@ -613,23 +545,92 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
);
}
return ImagingResampleInner(imIn, xsize, ysize, filterp, box,
ResampleHorizontal, ResampleVertical);
}
Imaging
ImagingResampleInner(Imaging imIn, int xsize, int ysize,
struct filter *filterp, float box[4],
ResampleFunction ResampleHorizontal,
ResampleFunction ResampleVertical)
{
Imaging imTemp = NULL;
Imaging imOut = NULL;
int i;
int yroi_min, yroi_max;
int ksize_horiz, ksize_vert;
int *bounds_horiz, *bounds_vert;
double *kk_horiz, *kk_vert;
ksize_horiz = precompute_coeffs(imIn->xsize, box[0], box[2], xsize,
filterp, &bounds_horiz, &kk_horiz);
if ( ! ksize_horiz) {
return NULL;
}
ksize_vert = precompute_coeffs(imIn->ysize, box[1], box[3], ysize,
filterp, &bounds_vert, &kk_vert);
if ( ! ksize_vert) {
free(bounds_horiz);
free(kk_horiz);
return NULL;
}
// First used row in the source image
yroi_min = bounds_vert[0];
// Last used row in the source image
yroi_max = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1];
/* two-pass resize, first pass */
if (imIn->xsize != xsize) {
imTemp = ResampleHorizontal(imIn, xsize, filterp);
if ( ! imTemp)
if (box[0] || box[2] != xsize) {
// Shift bounds for vertical pass
for (i = 0; i < ysize; i++) {
bounds_vert[i * 2] -= yroi_min;
}
imTemp = ImagingNewDirty(imIn->mode, xsize, yroi_max - yroi_min);
if (imTemp) {
ResampleHorizontal(imTemp, imIn, yroi_min,
ksize_horiz, bounds_horiz, kk_horiz);
}
free(bounds_horiz);
free(kk_horiz);
if ( ! imTemp) {
free(bounds_vert);
free(kk_vert);
return NULL;
}
imOut = imIn = imTemp;
} else {
// Free in any case
free(bounds_horiz);
free(kk_horiz);
}
/* second pass */
if (imIn->ysize != ysize) {
/* imIn can be the original image or horizontally resampled one */
imOut = ResampleVertical(imIn, ysize, filterp);
if (box[1] || box[3] != ysize) {
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
if (imOut) {
/* imIn can be the original image or horizontally resampled one */
ResampleVertical(imOut, imIn, 0,
ksize_vert, bounds_vert, kk_vert);
}
/* it's safe to call ImagingDelete with empty value
if there was no previous step. */
if previous step was not performed. */
ImagingDelete(imTemp);
if ( ! imOut)
free(bounds_vert);
free(kk_vert);
if ( ! imOut) {
return NULL;
}
} else {
// Free in any case
free(bounds_vert);
free(kk_vert);
}
/* none of the previous steps are performed, copying */

View File

@ -185,6 +185,19 @@ unpack1IR(UINT8* out, const UINT8* in, int pixels)
}
}
static void
unpack18(UINT8* out, const UINT8* in, int pixels)
{
/* Unpack a '|b1' image, which is a numpy boolean.
1 == true, 0==false, in bytes */
int i;
for (i = 0; i < pixels; i++) {
out[i] = in[i] > 0 ? 255 : 0;
}
}
/* Unpack to "L" image */
@ -479,6 +492,20 @@ ImagingUnpackRGB(UINT8* out, const UINT8* in, int pixels)
}
}
void
unpackRGB16L(UINT8* out, const UINT8* in, int pixels)
{
int i;
/* 16-bit RGB triplets, little-endian order */
for (i = 0; i < pixels; i++) {
out[R] = in[1];
out[G] = in[3];
out[B] = in[5];
out[A] = 255;
out += 4; in += 6;
}
}
void
unpackRGB16B(UINT8* out, const UINT8* in, int pixels)
{
@ -723,6 +750,54 @@ unpackRGBALA16B(UINT8* out, const UINT8* in, int pixels)
}
}
static void
unpackRGBa16L(UINT8* out, const UINT8* in, int pixels)
{
int i;
/* premultiplied 16-bit RGBA, little-endian */
for (i = 0; i < pixels; i++) {
int a = in[7];
if (!a)
out[R] = out[G] = out[B] = out[A] = 0;
else if (a == 255) {
out[R] = in[1];
out[G] = in[3];
out[B] = in[5];
out[A] = a;
} else {
out[R] = CLIP(in[1] * 255 / a);
out[G] = CLIP(in[3] * 255 / a);
out[B] = CLIP(in[5] * 255 / a);
out[A] = a;
}
out += 4; in += 8;
}
}
static void
unpackRGBa16B(UINT8* out, const UINT8* in, int pixels)
{
int i;
/* premultiplied 16-bit RGBA, big-endian */
for (i = 0; i < pixels; i++) {
int a = in[6];
if (!a)
out[R] = out[G] = out[B] = out[A] = 0;
else if (a == 255) {
out[R] = in[0];
out[G] = in[2];
out[B] = in[4];
out[A] = a;
} else {
out[R] = CLIP(in[0] * 255 / a);
out[G] = CLIP(in[2] * 255 / a);
out[B] = CLIP(in[4] * 255 / a);
out[A] = a;
}
out += 4; in += 8;
}
}
static void
unpackRGBa(UINT8* out, const UINT8* in, int pixels)
{
@ -800,6 +875,20 @@ unpackRGBAL(UINT8* out, const UINT8* in, int pixels)
}
}
void
unpackRGBA16L(UINT8* out, const UINT8* in, int pixels)
{
int i;
/* 16-bit RGBA, little-endian order */
for (i = 0; i < pixels; i++) {
out[R] = in[1];
out[G] = in[3];
out[B] = in[5];
out[A] = in[7];
out += 4; in += 8;
}
}
void
unpackRGBA16B(UINT8* out, const UINT8* in, int pixels)
{
@ -1163,11 +1252,14 @@ static struct {
endian byte order (default is little endian); "L" line
interleave, "S" signed, "F" floating point */
/* exception: rawmodes "I" and "F" are always native endian byte order */
/* bilevel */
{"1", "1", 1, unpack1},
{"1", "1;I", 1, unpack1I},
{"1", "1;R", 1, unpack1R},
{"1", "1;IR", 1, unpack1IR},
{"1", "1;8", 1, unpack18},
/* greyscale */
{"L", "L;2", 2, unpackL2},
@ -1207,6 +1299,7 @@ static struct {
{"RGB", "RGB", 24, ImagingUnpackRGB},
{"RGB", "RGB;L", 24, unpackRGBL},
{"RGB", "RGB;R", 24, unpackRGBR},
{"RGB", "RGB;16L", 48, unpackRGB16L},
{"RGB", "RGB;16B", 48, unpackRGB16B},
{"RGB", "BGR", 24, ImagingUnpackBGR},
{"RGB", "RGB;15", 16, ImagingUnpackRGB15},
@ -1230,12 +1323,15 @@ static struct {
{"RGBA", "LA;16B", 32, unpackRGBALA16B},
{"RGBA", "RGBA", 32, copy4},
{"RGBA", "RGBa", 32, unpackRGBa},
{"RGBA", "RGBa;16L", 64, unpackRGBa16L},
{"RGBA", "RGBa;16B", 64, unpackRGBa16B},
{"RGBA", "BGRa", 32, unpackBGRa},
{"RGBA", "RGBA;I", 32, unpackRGBAI},
{"RGBA", "RGBA;L", 32, unpackRGBAL},
{"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15},
{"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15},
{"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B},
{"RGBA", "RGBA;16L", 64, unpackRGBA16L},
{"RGBA", "RGBA;16B", 64, unpackRGBA16B},
{"RGBA", "BGRA", 32, unpackBGRA},
{"RGBA", "ARGB", 32, unpackARGB},
@ -1263,6 +1359,8 @@ static struct {
{"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
{"RGBX", "RGBX", 32, copy4},
{"RGBX", "RGBX;L", 32, unpackRGBAL},
{"RGBX", "RGBX;16L", 64, unpackRGBA16L},
{"RGBX", "RGBX;16B", 64, unpackRGBA16B},
{"RGBX", "BGRX", 32, ImagingUnpackBGRX},
{"RGBX", "XRGB", 24, ImagingUnpackXRGB},
{"RGBX", "XBGR", 32, ImagingUnpackXBGR},

View File

@ -365,6 +365,14 @@ class pil_build_ext(build_ext):
# work ;-)
self.add_multiarch_paths()
# termux support for android.
# system libraries (zlib) are installed in /system/lib
# headers are at $PREFIX/include
# user libs are at $PREFIX/lib
if os.environ.get('ANDROID_ROOT', None):
_add_directory(library_dirs,
os.path.join(os.environ['ANDROID_ROOT'],'lib'))
elif sys.platform.startswith("gnu"):
self.add_multiarch_paths()