Merge branch 'master' of https://github.com/python-pillow/Pillow into jpegdpi

This commit is contained in:
Arjen Nienhuis 2016-08-27 18:50:46 +02:00
commit d5a99bf685
44 changed files with 662 additions and 140 deletions

View File

@ -4,12 +4,63 @@ Changelog (Pillow)
3.4.0 (unreleased)
------------------
- Resampling lookups, trailing empty coefficients, precision #2008
[homm]
- Add (un)packing between RGBA and BGRa #2057
[arjennienhuis]
- Added return for J2k (and fpx) Load to return a pixel access object #2061
[wiredfool]
- Skip failing numpy tests on Pypy <= 5.3.1 #2090
[arjennienhuis]
- Show warning when trying to save RGBA image as JPEG #2010
[homm]
- Respect pixel centers during transform #2022
[homm]
- TOC for supported file formats #2056
[polarize]
- Fix conversion of bit images to numpy arrays Fixes #350, #2058
[matthew-brett]
- Add ImageOps.scale to expand or contract a PIL image by a factor #2011
[vlmath]
- Flake8 fixes #2050
[hugovk]
- Updated freetype to 2.6.5 on Appveyor builds #2035
[radarhere]
- PCX encoder fixes #2023, pr #2041
[homm]
- Docs: Windows console prompts are > #2031
[techtonik]
- Expose Pillow package version as PIL.__version__ #2027
[techtonik]
- Add Box and Hamming filters for resampling #1959
[homm]
- Retain a reference to core image object in PyAccess #2009
[homm]
3.3.1 (2016-08-18)
------------------
- Fix C90 compilation error for Tcl / Tk rewrite #2033
[matthew-brett]
- Fix image loading when rotating by 0 deg #2052
[homm]
3.3.0 (2016-07-01)
------------------

View File

@ -216,7 +216,7 @@ class FpxImageFile(ImageFile.ImageFile):
self.fp = self.ole.openstream(self.stream[:2] +
["Subimage 0000 Data"])
ImageFile.ImageFile.load(self)
return ImageFile.ImageFile.load(self)
#
# --------------------------------------------------------------------

View File

@ -246,7 +246,7 @@ else:
_MODE_CONV = {
# official modes
"1": ('|b1', None), # broken
"1": ('|b1', None), # Bits need to be extended to bytes
"L": ('|u1', None),
"LA": ('|u1', 2),
"I": (_ENDIAN + 'i4', None),
@ -615,17 +615,21 @@ class Image(object):
self.save(b, 'PNG')
return b.getvalue()
def __getattr__(self, name):
if name == "__array_interface__":
# numpy array interface support
new = {}
shape, typestr = _conv_type_shape(self)
new['shape'] = shape
new['typestr'] = typestr
@property
def __array_interface__(self):
# numpy array interface support
new = {}
shape, typestr = _conv_type_shape(self)
new['shape'] = shape
new['typestr'] = typestr
new['version'] = 3
if self.mode == '1':
# Binary images need to be extended from bits to bytes
# See: https://github.com/python-pillow/Pillow/issues/350
new['data'] = self.tobytes('raw', 'L')
else:
new['data'] = self.tobytes()
new['version'] = 3
return new
raise AttributeError(name)
return new
def __getstate__(self):
return [
@ -1877,7 +1881,7 @@ class Image(object):
xs = float(x1 - x0) / w
ys = float(y1 - y0) / h
method = AFFINE
data = (xs, 0, x0 + xs/2, 0, ys, y0 + ys/2)
data = (xs, 0, x0, 0, ys, y0)
elif method == PERSPECTIVE:
data = data[0:8]

View File

@ -178,6 +178,27 @@ def crop(image, border=0):
)
def scale(image, factor, resample=Image.NEAREST):
"""
Returns a rescaled image by a specific factor given in parameter.
A factor greater than 1 expands the image, between 0 and 1 contracts the
image.
:param factor: The expansion factor, as a float.
:param resample: An optional resampling filter. Same values possible as
in the PIL.Image.resize function.
:returns: An :py:class:`~PIL.Image.Image` object.
"""
if factor == 1:
return image.copy()
elif factor <= 0:
raise ValueError("the factor must be greater than 0")
else:
size = (int(round(factor * image.width)),
int(round(factor * image.height)))
return image.resize(size, resample)
def deform(image, deformer, resample=Image.BILINEAR):
"""
Deform the image.

View File

@ -207,7 +207,7 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
t3 = (t[3][0], self.reduce, self.layers, t[3][3], t[3][4])
self.tile = [(t[0], (0, 0) + self.size, t[2], t3)]
ImageFile.ImageFile.load(self)
return ImageFile.ImageFile.load(self)
def _accept(prefix):

View File

@ -583,6 +583,14 @@ def _save(im, fp, filename):
except KeyError:
raise IOError("cannot write mode %s as JPEG" % im.mode)
if im.mode == 'RGBA':
warnings.warn(
'You are saving RGBA image as JPEG. The alpha channel will be '
'discarded. This conversion is deprecated and will be disabled '
'in Pillow 3.7. Please, convert the image to RGB explicitly.',
DeprecationWarning
)
info = im.encoderinfo
dpi = info.get("dpi", (0, 0))

View File

@ -14,6 +14,8 @@
VERSION = '1.1.7' # PIL version
PILLOW_VERSION = '3.4.0.dev0' # Pillow
__version__ = PILLOW_VERSION
_plugins = ['BmpImagePlugin',
'BufrStubImagePlugin',
'CurImagePlugin',

View File

@ -1,6 +1,7 @@
from PIL import Image
from helper import unittest, PillowTestCase
class TestJ2kEncodeOverflow(PillowTestCase):
def test_j2k_overflow(self):
@ -12,7 +13,7 @@ class TestJ2kEncodeOverflow(PillowTestCase):
except IOError as err:
self.assertTrue(True, "IOError is expected")
except Exception as err:
self.assertTrue(False, "Expected IOError, got %s" %type(err))
self.assertTrue(False, "Expected IOError, got %s" % type(err))
if __name__ == '__main__':
unittest.main()

View File

@ -99,7 +99,7 @@ class PillowTestCase(unittest.TestCase):
" average pixel value difference %.4f > epsilon %.4f" % (
ave_diff, epsilon))
def assert_warning(self, warn_class, func):
def assert_warning(self, warn_class, func, *args, **kwargs):
import warnings
result = None
@ -108,7 +108,7 @@ class PillowTestCase(unittest.TestCase):
warnings.simplefilter("always")
# Hopefully trigger a warning.
result = func()
result = func(*args, **kwargs)
# Verify some things.
self.assertGreaterEqual(len(w), 1)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -77,6 +77,5 @@ class TestFileBmp(PillowTestCase):
self.assert_image_equal(im, target)
if __name__ == '__main__':
unittest.main()

View File

@ -450,6 +450,25 @@ class TestFileJpeg(PillowTestCase):
# Assert
self.assertEqual(im.format, "JPEG")
def test_save_correct_modes(self):
out = BytesIO()
for mode in ['1', 'L', 'RGB', 'RGBX', 'CMYK', 'YCbCr']:
img = Image.new(mode, (20, 20))
img.save(out, "JPEG")
def test_save_wrong_modes(self):
out = BytesIO()
for mode in ['LA', 'La', 'RGBa', 'P']:
img = Image.new(mode, (20, 20))
self.assertRaises(IOError, img.save, out, "JPEG")
def test_save_modes_with_warnings(self):
# ref https://github.com/python-pillow/Pillow/issues/2005
out = BytesIO()
for mode in ['RGBA']:
img = Image.new(mode, (20, 20))
self.assert_warning(DeprecationWarning, img.save, out, "JPEG")
if __name__ == '__main__':
unittest.main()

View File

@ -34,7 +34,8 @@ class TestFileJpeg2k(PillowTestCase):
self.assertRegexpMatches(Image.core.jp2klib_version, '\d+\.\d+\.\d+$')
im = Image.open('Tests/images/test-card-lossless.jp2')
im.load()
px = im.load()
self.assertEqual(px[0,0], (0, 0, 0))
self.assertEqual(im.mode, 'RGB')
self.assertEqual(im.size, (640, 480))
self.assertEqual(im.format, 'JPEG2000')

View File

@ -170,7 +170,8 @@ class TestFileLibTiff(LibTiffTestCase):
'RowsPerStrip',
'StripOffsets']
for field in requested_fields:
self.assertTrue(field in reloaded, "%s not in metadata" % field)
self.assertTrue(field in reloaded,
"%s not in metadata" % field)
def test_additional_metadata(self):
# these should not crash. Seriously dummy data, most of it doesn't make
@ -183,7 +184,8 @@ class TestFileLibTiff(LibTiffTestCase):
in TiffTags.LIBTIFF_CORE]
if info.type is not None)
# Exclude ones that have special meaning that we're already testing them
# Exclude ones that have special meaning
# that we're already testing them
im = Image.open('Tests/images/hopper_g4.tif')
for tag in im.tag_v2.keys():
try:
@ -422,8 +424,8 @@ class TestFileLibTiff(LibTiffTestCase):
def test_gray_semibyte_per_pixel(self):
test_files = (
(
24.8,#epsilon
(#group
24.8, # epsilon
( # group
"Tests/images/tiff_gray_2_4_bpp/hopper2.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2R.tif",
@ -431,8 +433,8 @@ class TestFileLibTiff(LibTiffTestCase):
)
),
(
7.3,#epsilon
(#group
7.3, # epsilon
( # group
"Tests/images/tiff_gray_2_4_bpp/hopper4.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4R.tif",
@ -504,6 +506,5 @@ class TestFileLibTiff(LibTiffTestCase):
im.save(outfile)
if __name__ == '__main__':
unittest.main()

View File

@ -1,6 +1,6 @@
from helper import unittest, PillowTestCase, hopper
from PIL import Image, PcxImagePlugin
from PIL import Image, ImageFile, PcxImagePlugin
class TestFilePcx(PillowTestCase):
@ -46,6 +46,84 @@ class TestFilePcx(PillowTestCase):
# Make sure all pixels are either 0 or 255.
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447*144)
def test_1px_width(self):
im = Image.new('L', (1, 256))
px = im.load()
for y in range(256):
px[0, y] = y
self._roundtrip(im)
def test_large_count(self):
im = Image.new('L', (256, 1))
px = im.load()
for x in range(256):
px[x, 0] = x // 67 * 67
self._roundtrip(im)
def _test_buffer_overflow(self, im, size=1024):
_last = ImageFile.MAXBLOCK
ImageFile.MAXBLOCK = size
try:
self._roundtrip(im)
finally:
ImageFile.MAXBLOCK = _last
def test_break_in_count_overflow(self):
im = Image.new('L', (256, 5))
px = im.load()
for y in range(4):
for x in range(256):
px[x, y] = x % 128
self._test_buffer_overflow(im)
def test_break_one_in_loop(self):
im = Image.new('L', (256, 5))
px = im.load()
for y in range(5):
for x in range(256):
px[x, y] = x % 128
self._test_buffer_overflow(im)
def test_break_many_in_loop(self):
im = Image.new('L', (256, 5))
px = im.load()
for y in range(4):
for x in range(256):
px[x, y] = x % 128
for x in range(8):
px[x, 4] = 16
self._test_buffer_overflow(im)
def test_break_one_at_end(self):
im = Image.new('L', (256, 5))
px = im.load()
for y in range(5):
for x in range(256):
px[x, y] = x % 128
px[0, 3] = 128 + 64
self._test_buffer_overflow(im)
def test_break_many_at_end(self):
im = Image.new('L', (256, 5))
px = im.load()
for y in range(5):
for x in range(256):
px[x, y] = x % 128
for x in range(4):
px[x * 2, 3] = 128 + 64
px[x + 256 - 4, 3] = 0
self._test_buffer_overflow(im)
def test_break_padding(self):
im = Image.new('L', (257, 5))
px = im.load()
for y in range(5):
for x in range(257):
px[x, y] = x % 128
for x in range(5):
px[x, 3] = 0
self._test_buffer_overflow(im)
if __name__ == '__main__':
unittest.main()

View File

@ -313,7 +313,7 @@ class TestFilePng(PillowTestCase):
# -14: malformed chunk
for offset in (-10, -13, -14):
with open(TEST_PNG_FILE,'rb') as f:
with open(TEST_PNG_FILE, 'rb') as f:
test_file = f.read()[:offset]
im = Image.open(BytesIO(test_file))
@ -347,7 +347,6 @@ class TestFilePng(PillowTestCase):
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False
def test_roundtrip_dpi(self):
# Check dpi roundtripping

View File

@ -105,6 +105,7 @@ class TestCffiPutPixel(TestImagePutPixel):
def setUp(self):
try:
import cffi
assert cffi # silence warning
except ImportError:
self.skipTest("No cffi")
@ -115,6 +116,7 @@ class TestCffiGetPixel(TestImageGetPixel):
def setUp(self):
try:
import cffi
assert cffi # silence warning
except ImportError:
self.skipTest("No cffi")
@ -125,6 +127,7 @@ class TestCffi(AccessTest):
def setUp(self):
try:
import cffi
assert cffi # silence warning
except ImportError:
self.skipTest("No cffi")
@ -229,7 +232,7 @@ class TestCffi(AccessTest):
# Do not save references to the image, only to the access object
px = Image.new('L', (size, 1), 0).load()
for i in range(size):
# pixels can contain garbarge if image is released
# pixels can contain garbage if image is released
self.assertEqual(px[i, 0], 0)

View File

@ -25,13 +25,26 @@ class TestImageArray(PillowTestCase):
self.assertEqual(test("RGBX"), (3, (100, 128, 4), '|u1', 51200))
def test_fromarray(self):
class Wrapper(object):
""" Class with API matching Image.fromarray """
def __init__(self, img, arr_params):
self.img = img
self.__array_interface__ = arr_params
def tobytes(self):
return self.img.tobytes()
def test(mode):
i = im.convert(mode)
a = i.__array_interface__
a["strides"] = 1 # pretend it's non-contigous
i.__array_interface__ = a # patch in new version of attribute
out = Image.fromarray(i)
# Make wrapper instance for image, new array interface
wrapped = Wrapper(i, a)
out = Image.fromarray(wrapped)
return out.mode, out.size, list(i.getdata()) == list(out.getdata())
# self.assertEqual(test("1"), ("1", (128, 100), True))
self.assertEqual(test("L"), ("L", (128, 100), True))
self.assertEqual(test("I"), ("I", (128, 100), True))

View File

@ -20,13 +20,13 @@ class TestImageGetData(PillowTestCase):
return data[0], len(data), len(list(data))
self.assertEqual(getdata("1"), (0, 960, 960))
self.assertEqual(getdata("L"), (25, 960, 960))
self.assertEqual(getdata("I"), (25, 960, 960))
self.assertEqual(getdata("F"), (25.0, 960, 960))
self.assertEqual(getdata("RGB"), (((20, 20, 70), 960, 960)))
self.assertEqual(getdata("RGBA"), ((20, 20, 70, 255), 960, 960))
self.assertEqual(getdata("CMYK"), ((235, 235, 185, 0), 960, 960))
self.assertEqual(getdata("YCbCr"), ((25, 153, 123), 960, 960))
self.assertEqual(getdata("L"), (16, 960, 960))
self.assertEqual(getdata("I"), (16, 960, 960))
self.assertEqual(getdata("F"), (16.0, 960, 960))
self.assertEqual(getdata("RGB"), (((11, 13, 52), 960, 960)))
self.assertEqual(getdata("RGBA"), ((11, 13, 52, 255), 960, 960))
self.assertEqual(getdata("CMYK"), ((244, 242, 203, 0), 960, 960))
self.assertEqual(getdata("YCbCr"), ((16, 147, 123), 960, 960))
if __name__ == '__main__':

View File

@ -320,5 +320,22 @@ class CoreResamplePassesTest(PillowTestCase):
self.assertEqual(Image.core.getcount(), count + 2)
class CoreResampleCoefficientsTest(PillowTestCase):
def test_reduce(self):
test_color = 254
# print ''
for size in range(400000, 400010, 2):
# print '\r', size,
i = Image.new('L', (size, 1), 0)
draw = ImageDraw.Draw(i)
draw.rectangle((0, 0, i.size[0] // 2 - 1, 0), test_color)
px = i.resize((5, i.size[1]), Image.BICUBIC).load()
if px[2, 0] != test_color // 2:
self.assertEqual(test_color // 2, px[2, 0])
# print '\r>', size, test_color // 2, px[2, 0]
if __name__ == '__main__':
unittest.main()

View File

@ -1,3 +1,5 @@
import math
from helper import unittest, PillowTestCase, hopper
from PIL import Image
@ -98,7 +100,7 @@ class TestImageTransform(PillowTestCase):
def test_alpha_premult_resize(self):
def op(im, sz):
return im.resize(sz, Image.LINEAR)
return im.resize(sz, Image.BILINEAR)
self._test_alpha_premult(op)
@ -139,5 +141,117 @@ class TestImageTransform(PillowTestCase):
self.test_mesh()
class TestImageTransformAffine(PillowTestCase):
transform = Image.AFFINE
def _test_image(self):
im = hopper('RGB')
return im.crop((10, 20, im.width - 10, im.height - 20))
def _test_rotate(self, deg, transpose):
im = self._test_image()
angle = - math.radians(deg)
matrix = [
round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0,
round(-math.sin(angle), 15), round(math.cos(angle), 15), 0.0,
0, 0]
matrix[2] = (1 - matrix[0] - matrix[1]) * im.width / 2
matrix[5] = (1 - matrix[3] - matrix[4]) * im.height / 2
if transpose is not None:
transposed = im.transpose(transpose)
else:
transposed = im
for resample in [Image.NEAREST, Image.BILINEAR, Image.BICUBIC]:
transformed = im.transform(transposed.size, self.transform,
matrix, resample)
self.assert_image_equal(transposed, transformed)
def test_rotate_0_deg(self):
self._test_rotate(0, None)
def test_rotate_90_deg(self):
self._test_rotate(90, Image.ROTATE_90)
def test_rotate_180_deg(self):
self._test_rotate(180, Image.ROTATE_180)
def test_rotate_270_deg(self):
self._test_rotate(270, Image.ROTATE_270)
def _test_resize(self, scale, epsilonscale):
im = self._test_image()
size_up = int(round(im.width * scale)), int(round(im.height * scale))
matrix_up = [
1 / scale, 0, 0,
0, 1 / scale, 0,
0, 0]
matrix_down = [
scale, 0, 0,
0, scale, 0,
0, 0]
for resample, epsilon in [(Image.NEAREST, 0),
(Image.BILINEAR, 2), (Image.BICUBIC, 1)]:
transformed = im.transform(
size_up, self.transform, matrix_up, resample)
transformed = transformed.transform(
im.size, self.transform, matrix_down, resample)
self.assert_image_similar(transformed, im, epsilon * epsilonscale)
def test_resize_1_1x(self):
self._test_resize(1.1, 6.9)
def test_resize_1_5x(self):
self._test_resize(1.5, 5.5)
def test_resize_2_0x(self):
self._test_resize(2.0, 5.5)
def test_resize_2_3x(self):
self._test_resize(2.3, 3.7)
def test_resize_2_5x(self):
self._test_resize(2.5, 3.7)
def _test_translate(self, x, y, epsilonscale):
im = self._test_image()
size_up = int(round(im.width + x)), int(round(im.height + y))
matrix_up = [
1, 0, -x,
0, 1, -y,
0, 0]
matrix_down = [
1, 0, x,
0, 1, y,
0, 0]
for resample, epsilon in [(Image.NEAREST, 0),
(Image.BILINEAR, 1.5), (Image.BICUBIC, 1)]:
transformed = im.transform(
size_up, self.transform, matrix_up, resample)
transformed = transformed.transform(
im.size, self.transform, matrix_down, resample)
self.assert_image_similar(transformed, im, epsilon * epsilonscale)
def test_translate_0_1(self):
self._test_translate(.1, 0, 3.7)
def test_translate_0_6(self):
self._test_translate(.6, 0, 9.1)
def test_translate_50(self):
self._test_translate(50, 50, 0)
class TestImageTransformPerspective(TestImageTransformAffine):
# Repeat all tests for AFFINE transormations with PERSPECTIVE
transform = Image.PERSPECTIVE
if __name__ == '__main__':
unittest.main()

View File

@ -78,6 +78,22 @@ class TestImageOps(PillowTestCase):
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))
if __name__ == '__main__':
unittest.main()

View File

@ -5,6 +5,7 @@ from PIL import ImagePath, Image
import array
import struct
class TestImagePath(PillowTestCase):
def test_path(self):
@ -61,7 +62,6 @@ class TestImagePath(PillowTestCase):
p = ImagePath.Path(arr.tostring())
self.assertEqual(list(p), [(0.0, 1.0)])
def test_overflow_segfault(self):
try:
# post patch, this fails with a memory error

View File

@ -56,7 +56,7 @@ class TestImageSequence(PillowTestCase):
im = Image.open('Tests/images/multipage.tiff')
firstFrame = None
for frame in ImageSequence.Iterator(im):
if firstFrame == None:
if firstFrame is None:
firstFrame = frame.copy()
pass
for frame in ImageSequence.Iterator(im):

View File

@ -8,6 +8,7 @@ except (OSError, ImportError) as v:
# Skipped via setUp()
pass
class TestImageTk(PillowTestCase):
def setUp(self):
@ -24,7 +25,7 @@ class TestImageTk(PillowTestCase):
im2 = Image.open(TEST_PNG)
with open(TEST_PNG, 'rb') as fp:
data = fp.read()
kw = {"file":TEST_JPG, "data":data}
kw = {"file": TEST_JPG, "data": data}
# Test "file"
im = ImageTk._get_image_from_kw(kw)

View File

@ -57,7 +57,10 @@ if sys.platform.startswith('win32'):
DeleteObject.argtypes = [ctypes.wintypes.HGDIOBJ]
CreateDIBSection = ctypes.windll.gdi32.CreateDIBSection
CreateDIBSection.argtypes = [ctypes.wintypes.HDC, ctypes.c_void_p, ctypes.c_uint, ctypes.POINTER(ctypes.c_void_p), ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD]
CreateDIBSection.argtypes = [ctypes.wintypes.HDC, ctypes.c_void_p,
ctypes.c_uint,
ctypes.POINTER(ctypes.c_void_p),
ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD]
CreateDIBSection.restype = ctypes.wintypes.HBITMAP
def serialize_dib(bi, pixels):
@ -99,7 +102,8 @@ if sys.platform.startswith('win32'):
hdc = CreateCompatibleDC(None)
# print('hdc:',hex(hdc))
pixels = ctypes.c_void_p()
dib = CreateDIBSection(hdc, ctypes.byref(hdr), DIB_RGB_COLORS, ctypes.byref(pixels), None, 0)
dib = CreateDIBSection(hdc, ctypes.byref(hdr), DIB_RGB_COLORS,
ctypes.byref(pixels), None, 0)
SelectObject(hdc, dib)
imdib.expose(hdc)

View File

@ -10,11 +10,11 @@ class TestLibPack(PillowTestCase):
def test_pack(self):
def pack(mode, rawmode):
def pack(mode, rawmode, in_data=(1, 2, 3, 4)):
if len(mode) == 1:
im = Image.new(mode, (1, 1), 1)
im = Image.new(mode, (1, 1), in_data[0])
else:
im = Image.new(mode, (1, 1), (1, 2, 3, 4)[:len(mode)])
im = Image.new(mode, (1, 1), in_data[:len(mode)])
if py3:
return list(im.tobytes("raw", rawmode))
@ -47,6 +47,8 @@ class TestLibPack(PillowTestCase):
self.assertEqual(pack("RGBX", "RGBX"), [1, 2, 3, 4]) # 4->255?
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])
self.assertEqual(pack("RGBa", "RGBa"), [1, 2, 3, 4])
self.assertEqual(pack("RGBa", "BGRa"), [3, 2, 1, 4])
@ -122,7 +124,9 @@ class TestLibPack(PillowTestCase):
self.assertEqual(unpack("RGB", "XBGR", 4), (4, 3, 2))
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))

View File

@ -1,4 +1,5 @@
from __future__ import print_function
import sys
from helper import unittest, PillowTestCase, hopper
from PIL import Image
@ -6,18 +7,29 @@ from PIL import Image
try:
import site
import numpy
assert site # silence warning
assert numpy # silence warning
except ImportError:
# Skip via setUp()
pass
TEST_IMAGE_SIZE = (10, 10)
# Numpy on pypy as of pypy 5.3.1 is corrupting the numpy.array(Image)
# call such that it's returning a object of type numpy.ndarray, but
# the repr is that of a PIL.Image. Size and shape are 1 and (), not the
# size and shape of the array. This causes failures in several tests.
SKIP_NUMPY_ON_PYPY = hasattr(sys, 'pypy_version_info') and (
sys.pypy_version_info <= (5,3,1,'final',0))
class TestNumpy(PillowTestCase):
def setUp(self):
try:
import site
import numpy
assert site # silence warning
assert numpy # silence warning
except ImportError:
self.skipTest("ImportError")
@ -100,6 +112,7 @@ class TestNumpy(PillowTestCase):
self.assert_image(Image.fromarray(a[:, :, 1]), "L", TEST_IMAGE_SIZE)
def _test_img_equals_nparray(self, img, np):
self.assertGreaterEqual(len(np.shape), 2)
np_size = np.shape[1], np.shape[0]
self.assertEqual(img.size, np_size)
px = img.load()
@ -107,12 +120,22 @@ class TestNumpy(PillowTestCase):
for y in range(0, img.size[1], int(img.size[1]/10)):
self.assert_deep_equal(px[x, y], np[y, x])
@unittest.skipIf(SKIP_NUMPY_ON_PYPY, "numpy.array(Image) is flaky on PyPy")
def test_16bit(self):
img = Image.open('Tests/images/16bit.cropped.tif')
np_img = numpy.array(img)
self._test_img_equals_nparray(img, np_img)
self.assertEqual(np_img.dtype, numpy.dtype('<u2'))
def test_1bit(self):
# 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')
self.assertEqual(img.mode, '1')
arr_back = numpy.array(img)
numpy.testing.assert_array_equal(arr, arr_back)
def test_save_tiff_uint16(self):
'''
Open a single-channel uint16 greyscale image and verify that it can be saved without
@ -128,6 +151,7 @@ class TestNumpy(PillowTestCase):
im_good = Image.open(filename)
self.assert_image_equal(im_good, im_test)
@unittest.skipIf(SKIP_NUMPY_ON_PYPY, "numpy.array(Image) is flaky on PyPy")
def test_to_array(self):
def _to_array(mode, dtype):

View File

@ -371,7 +371,8 @@ int load_tkinter_funcs(void)
#if PY_VERSION_HEX >= 0x03000000
char *fname2char(PyObject *fname)
{
PyObject *bytes = PyUnicode_EncodeFSDefault(fname);
PyObject* bytes;
bytes = PyUnicode_EncodeFSDefault(fname);
if (bytes == NULL) {
return NULL;
}
@ -391,9 +392,10 @@ void *_dfunc(void *lib_handle, const char *func_name)
* Returns function pointer or NULL if not present.
*/
void* func;
/* Reset errors. */
dlerror();
void *func = dlsym(lib_handle, func_name);
func = dlsym(lib_handle, func_name);
if (func == NULL) {
const char *error = dlerror();
PyErr_SetString(PyExc_RuntimeError, error);

View File

@ -729,7 +729,7 @@ static cmsBool _calculate_rgb_primaries(CmsProfileObject* self, cmsCIEXYZTRIPLE*
/* http://littlecms2.blogspot.com/2009/07/less-is-more.html */
// double array of RGB values with max on each identitiy
// double array of RGB values with max on each identity
hXYZ = cmsCreateXYZProfile();
if (hXYZ == NULL)
return 0;

View File

@ -204,7 +204,7 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args)
}
state->bytes = (state->bits * state->xsize+7)/8;
}
/* malloc check ok, oveflow checked above */
/* malloc check ok, overflow checked above */
state->buffer = (UINT8*) malloc(state->bytes);
if (!state->buffer)
return PyErr_NoMemory();

View File

@ -16,6 +16,8 @@ explicitly.
Fully supported formats
-----------------------
.. contents::
BMP
^^^

View File

@ -51,11 +51,11 @@ supported Pythons in both 32 and 64-bit versions in wheel, egg, and
executable installers. These binaries have all of the optional
libraries included::
$ pip install Pillow
> pip install Pillow
or::
$ easy_install Pillow
> easy_install Pillow
OS X Installation
@ -282,7 +282,9 @@ Building on Linux
^^^^^^^^^^^^^^^^^
If you didn't build Python from source, make sure you have Python's
development libraries installed. In Debian or Ubuntu::
development libraries installed.
In Debian or Ubuntu::
$ sudo apt-get install python-dev python-setuptools
@ -294,6 +296,10 @@ In Fedora, the command is::
$ sudo dnf install python-devel redhat-rpm-config
Or for Python 3::
$ sudo dnf install python3-devel redhat-rpm-config
.. Note:: ``redhat-rpm-config`` is required on Fedora 23, but not earlier versions.
Prerequisites are installed on **Ubuntu 12.04 LTS** or **Raspian Wheezy

View File

@ -0,0 +1,15 @@
3.4.0
-----
New resizing filters
====================
Two new filters available for ``Image.resize()`` and ``Image.thumbnail()``
functions: ``BOX`` and ``HAMMING``. ``BOX`` is the high-performance filter with
two times shorter window than ``BILINEAR``. It can be used for image reduction
3 and more times and produces a more sharp result than ``BILINEAR``.
``HAMMING`` filter has the same performance as ``BILINEAR`` filter while
providing the image downscaling quality comparable to ``BICUBIC``.
Both new filters don't show good quality for the image upscaling.

View File

@ -6,6 +6,7 @@ Release Notes
.. toctree::
:maxdepth: 2
3.4.0
3.3.0
3.2.0
3.1.2

View File

@ -365,7 +365,7 @@ get_packer(ImagingEncoderObject* encoder, const char* mode,
pack = ImagingFindPacker(mode, rawmode, &bits);
if (!pack) {
Py_DECREF(encoder);
PyErr_SetString(PyExc_SystemError, "unknown raw mode");
PyErr_Format(PyExc_ValueError, "No packer found from %s to %s", mode, rawmode);
return -1;
}

View File

@ -240,7 +240,7 @@ ImagingRotate270(Imaging imOut, Imaging imIn)
/* transform primitives (ImagingTransformMap) */
static int
affine_transform(double* xin, double* yin, int x, int y, void* data)
affine_transform(double* xout, double* yout, int x, int y, void* data)
{
/* full moon tonight. your compiler will generate bogus code
for simple expressions, unless you reorganize the code, or
@ -250,28 +250,34 @@ affine_transform(double* xin, double* yin, int x, int y, void* data)
double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
xin[0] = a0*x + a1*y + a2;
yin[0] = a3*x + a4*y + a5;
double xin = x + 0.5;
double yin = y + 0.5;
xout[0] = a0*xin + a1*yin + a2;
yout[0] = a3*xin + a4*yin + a5;
return 1;
}
static int
perspective_transform(double* xin, double* yin, int x, int y, void* data)
perspective_transform(double* xout, double* yout, int x, int y, void* data)
{
double* a = (double*) data;
double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
double a6 = a[6]; double a7 = a[7];
xin[0] = (a0*x + a1*y + a2) / (a6*x + a7*y + 1);
yin[0] = (a3*x + a4*y + a5) / (a6*x + a7*y + 1);
double xin = x + 0.5;
double yin = y + 0.5;
xout[0] = (a0*xin + a1*yin + a2) / (a6*xin + a7*yin + 1);
yout[0] = (a3*xin + a4*yin + a5) / (a6*xin + a7*yin + 1);
return 1;
}
static int
quad_transform(double* xin, double* yin, int x, int y, void* data)
quad_transform(double* xout, double* yout, int x, int y, void* data)
{
/* quad warp: map quadrilateral to rectangle */
@ -279,8 +285,11 @@ quad_transform(double* xin, double* yin, int x, int y, void* data)
double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3];
double a4 = a[4]; double a5 = a[5]; double a6 = a[6]; double a7 = a[7];
xin[0] = a0 + a1*x + a2*y + a3*x*y;
yin[0] = a4 + a5*x + a6*y + a7*x*y;
double xin = x + 0.5;
double yin = y + 0.5;
xout[0] = a0 + a1*xin + a2*yin + a3*xin*yin;
yout[0] = a4 + a5*xin + a6*yin + a7*xin*yin;
return 1;
}
@ -691,8 +700,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
return (Imaging) ImagingError_MemoryError();
}
xo = a[2];
yo = a[5];
xo = a[2] + a[0] * 0.5;
yo = a[5] + a[4] * 0.5;
xmin = x1;
xmax = x0;
@ -771,8 +780,10 @@ affine_fixed(Imaging imOut, Imaging imIn,
/* use 16.16 fixed point arithmetics */
#define FIX(v) FLOOR((v)*65536.0 + 0.5)
a0 = FIX(a[0]); a1 = FIX(a[1]); a2 = FIX(a[2]);
a3 = FIX(a[3]); a4 = FIX(a[4]); a5 = FIX(a[5]);
a0 = FIX(a[0]); a1 = FIX(a[1]);
a3 = FIX(a[3]); a4 = FIX(a[4]);
a2 = FIX(a[2] + a[0] * 0.5 + a[1] * 0.5);
a5 = FIX(a[5] + a[3] * 0.5 + a[4] * 0.5);
#undef FIX
@ -835,9 +846,10 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
filterid, fill);
}
if (a[1] == 0 && a[3] == 0)
if (a[1] == 0 && a[3] == 0) {
/* Scaling */
return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
}
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
return (Imaging) ImagingError_ModeError();
@ -867,8 +879,8 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
xsize = (int) imIn->xsize;
ysize = (int) imIn->ysize;
xo = a[2];
yo = a[5];
xo = a[2] + a[1] * 0.5 + a[0] * 0.5;
yo = a[5] + a[4] * 0.5 + a[3] * 0.5;
#define AFFINE_TRANSFORM(pixel, image)\
for (y = y0; y < y1; y++) {\

View File

@ -72,6 +72,10 @@
#define C64L C64N
#endif
/* like (a * b + 127) / 255), but much faster on most platforms */
#define MULDIV255(a, b, tmp)\
(tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8))
static void
pack1(UINT8* out, const UINT8* in, int pixels)
{
@ -315,6 +319,21 @@ ImagingPackABGR(UINT8* out, const UINT8* in, int pixels)
}
}
void
ImagingPackBGRa(UINT8* out, const UINT8* in, int pixels)
{
int i;
/* BGRa, reversed bytes with premultiplied alpha */
for (i = 0; i < pixels; i++) {
int alpha = out[3] = in[A];
int tmp;
out[0] = MULDIV255(in[B], alpha, tmp);
out[1] = MULDIV255(in[G], alpha, tmp);
out[2] = MULDIV255(in[R], alpha, tmp);
out += 4; in += 4;
}
}
static void
packRGBL(UINT8* out, const UINT8* in, int pixels)
{
@ -525,6 +544,7 @@ static struct {
{"RGBA", "BGR", 24, ImagingPackBGR},
{"RGBA", "BGRA", 32, ImagingPackBGRA},
{"RGBA", "ABGR", 32, ImagingPackABGR},
{"RGBA", "BGRa", 32, ImagingPackBGRa},
{"RGBA", "R", 8, band0},
{"RGBA", "G", 8, band1},
{"RGBA", "B", 8, band2},

View File

@ -75,7 +75,7 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
(UINT8*) im->image[state->y + state->yoff] +
state->xoff * im->pixelsize, state->xsize);
state->y++;
state->y += 1;
state->count = 1;
state->LAST = state->buffer[0];
@ -91,7 +91,7 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* when we arrive here, "count" contains the number of
bytes having the value of "LAST" that we've already
seen */
while (state->x < planes * bytes_per_line) {
do {
/* If we're encoding an odd width file, and we've
got more than one plane, we need to pad each
color row with padding bytes at the end. Since
@ -103,22 +103,23 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
if (state->count == 63) {
/* this run is full; flush it */
if (bytes < 2)
if (bytes < 2) {
return ptr - buf;
*ptr++ = 0xff;
*ptr++ = state->LAST;
}
ptr[0] = 0xff;
ptr[1] = state->LAST;
ptr += 2;
bytes -= 2;
state->count = 0;
}
this = state->buffer[state->x];
if (this == state->LAST) {
/* extend the current run */
state->x++;
state->count++;
state->x += 1;
state->count += 1;
} else {
/* start a new run */
@ -126,15 +127,17 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
if (bytes < 1) {
return ptr - buf;
}
*ptr++ = state->LAST;
bytes--;
ptr[0] = state->LAST;
ptr += 1;
bytes -= 1;
} else {
if (state->count > 0) {
if (bytes < 2) {
return ptr - buf;
}
*ptr++ = 0xc0 | state->count;
*ptr++ = state->LAST;
ptr[0] = 0xc0 | state->count;
ptr[1] = state->LAST;
ptr += 2;
bytes -= 2;
}
}
@ -142,8 +145,7 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
state->LAST = this;
state->count = 1;
state->x++;
state->x += 1;
}
}
@ -152,33 +154,34 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
if (bytes < 1 + padding) {
return ptr - buf;
}
*ptr++ = state->LAST;
bytes--;
ptr[0] = state->LAST;
ptr += 1;
bytes -= 1;
} else {
if (state->count > 0) {
if (bytes < 2 + padding) {
return ptr - buf;
}
*ptr++ = 0xc0 | state->count;
*ptr++ = state->LAST;
ptr[0] = 0xc0 | state->count;
ptr[1] = state->LAST;
ptr += 2;
bytes -= 2;
}
}
if (bytes < padding) {
return ptr - buf;
}
/* add the padding */
for (i=0;i<padding;i++){
*ptr++=0;
bytes--;
for (i = 0; i < padding; i++) {
ptr[0] = 0;
ptr += 1;
bytes -= 1;
}
/* reset for the next color plane. */
if (state->x < planes * bytes_per_line) {
state->count = 1;
state->LAST = state->buffer[state->x];
state->x++;
state->x += 1;
}
}
} while (state->x < planes * bytes_per_line);
/* read next line */
state->state = FETCH;
break;

View File

@ -407,7 +407,7 @@ int quantize_octree(Pixel *pixelData,
/* remove the used fine colors from the coarse cube */
subtract_color_buckets(coarseCube, paletteBucketsFine, nFineColors);
/* did the substraction cleared one or more coarse bucket? */
/* did the subtraction cleared one or more coarse bucket? */
while (nCoarseColors > count_used_color_buckets(coarseCube)) {
/* then we can use the free buckets for fine colors */
nAlreadySubtracted = nFineColors;

View File

@ -80,18 +80,52 @@ static struct filter LANCZOS = { lanczos_filter, 3.0 };
#define PRECISION_BITS (32 - 8 - 2)
UINT8 _lookups[512] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};
UINT8 *lookups = &_lookups[128];
static inline UINT8 clip8(int in)
{
if (in >= (1 << PRECISION_BITS << 8))
return 255;
if (in <= 0)
return 0;
return (UINT8) (in >> PRECISION_BITS);
return lookups[in >> PRECISION_BITS];
}
int
ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
precompute_coeffs(int inSize, int outSize, struct filter *filterp,
int **xboundsp, double **kkp) {
double support, scale, filterscale;
double center, ww, ss;
@ -142,6 +176,16 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
k = &kk[xx * kmax];
for (x = 0; x < xmax; x++) {
double w = filterp->filter((x + xmin - center + 0.5) * ss);
if (w == 0) {
if (x == 0) {
x -= 1;
xmin += 1;
xmax -= 1;
} else if (x == xmax - 1) {
xmax -= 1;
}
continue;
}
k[x] = w;
ww += w;
}
@ -162,6 +206,32 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
}
int
normalize_coeffs_8bpc(int outSize, int kmax, double *prekk, INT32 **kkp)
{
int x;
INT32 *kk;
/* malloc check ok, overflow checked in precompute_coeffs */
kk = malloc(outSize * kmax * sizeof(INT32));
if ( ! kk) {
return 0;
}
for (x = 0; x < outSize * kmax; 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)
{
@ -170,28 +240,21 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
int ss0, ss1, ss2, ss3;
int xx, yy, x, kmax, xmin, xmax;
int *xbounds;
int *k, *kk;
INT32 *k, *kk;
double *prekk;
kmax = ImagingPrecompute(imIn->xsize, xsize, filterp, &xbounds, &prekk);
kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &prekk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
kk = malloc(xsize * kmax * sizeof(int));
if ( ! kk) {
kmax = normalize_coeffs_8bpc(xsize, kmax, prekk, &kk);
free(prekk);
if ( ! kmax) {
free(xbounds);
free(prekk);
return (Imaging) ImagingError_MemoryError();
}
for (x = 0; x < xsize * kmax; x++) {
kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS));
}
free(prekk);
imOut = ImagingNew(imIn->mode, xsize, imIn->ysize);
if ( ! imOut) {
free(kk);
@ -282,28 +345,21 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
int ss0, ss1, ss2, ss3;
int xx, yy, y, kmax, ymin, ymax;
int *xbounds;
int *k, *kk;
INT32 *k, *kk;
double *prekk;
kmax = ImagingPrecompute(imIn->ysize, ysize, filterp, &xbounds, &prekk);
kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &prekk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
kk = malloc(ysize * kmax * sizeof(int));
if ( ! kk) {
kmax = normalize_coeffs_8bpc(ysize, kmax, prekk, &kk);
free(prekk);
if ( ! kmax) {
free(xbounds);
free(prekk);
return (Imaging) ImagingError_MemoryError();
}
for (y = 0; y < ysize * kmax; y++) {
kk[y] = (int) (0.5 + prekk[y] * (1 << PRECISION_BITS));
}
free(prekk);
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
if ( ! imOut) {
free(kk);
@ -396,7 +452,7 @@ ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
int *xbounds;
double *k, *kk;
kmax = ImagingPrecompute(imIn->xsize, xsize, filterp, &xbounds, &kk);
kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &kk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}
@ -456,7 +512,7 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
int *xbounds;
double *k, *kk;
kmax = ImagingPrecompute(imIn->ysize, ysize, filterp, &xbounds, &kk);
kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &kk);
if ( ! kmax) {
return (Imaging) ImagingError_MemoryError();
}

View File

@ -747,6 +747,30 @@ unpackRGBa(UINT8* out, const UINT8* in, int pixels)
}
}
static void
unpackBGRa(UINT8* out, const UINT8* in, int pixels)
{
int i;
/* premultiplied BGRA */
for (i = 0; i < pixels; i++) {
int a = in[3];
if (!a)
out[R] = out[G] = out[B] = out[A] = 0;
else if (a == 255) {
out[R] = in[2];
out[G] = in[1];
out[B] = in[0];
out[A] = a;
} else {
out[R] = CLIP(in[2] * 255 / a);
out[G] = CLIP(in[1] * 255 / a);
out[B] = CLIP(in[0] * 255 / a);
out[A] = a;
}
out += 4; in += 4;
}
}
static void
unpackRGBAI(UINT8* out, const UINT8* in, int pixels)
{
@ -1206,6 +1230,7 @@ static struct {
{"RGBA", "LA;16B", 32, unpackRGBALA16B},
{"RGBA", "RGBA", 32, copy4},
{"RGBA", "RGBa", 32, unpackRGBa},
{"RGBA", "BGRa", 32, unpackBGRa},
{"RGBA", "RGBA;I", 32, unpackRGBAI},
{"RGBA", "RGBA;L", 32, unpackRGBAL},
{"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15},

View File

@ -28,9 +28,9 @@ libs = {
'dir': 'tiff-4.0.6',
},
'freetype': {
'url': 'http://download.savannah.gnu.org/releases/freetype/freetype-2.6.3.tar.gz',
'hash': 'md5:8b0c80b64042b7c39b9fa9debe6305c3',
'dir': 'freetype-2.6.3',
'url': 'http://download.savannah.gnu.org/releases/freetype/freetype-2.6.5.tar.gz',
'hash': 'md5:31b2276515d9ee1c7f37d9c9f4f3145a',
'dir': 'freetype-2.6.5',
},
'lcms': {
'url': SF_MIRROR+'/project/lcms/lcms/2.7/lcms2-2.7.zip',