Merge branch 'master' into imaging-copy-palette-info

This commit is contained in:
Alexander 2017-09-19 20:51:52 +03:00
commit bca70a743d
29 changed files with 549 additions and 312 deletions

View File

@ -4,6 +4,30 @@ Changelog (Pillow)
4.3.0 (unreleased) 4.3.0 (unreleased)
------------------ ------------------
- Fix ValueError in Exif/Tiff IFD #2719
[wiredfool]
- Use pathlib2 for Path objects on Python < 3.4 #2291
[asergi]
- Export only required properties in unsafe_ptrs #2740
[homm]
- Alpha composite fixes #2709
[homm]
- Faster Transpose operations, added 'Transverse' option #2730
[homm]
- Deprecate ImageOps undocumented functions gaussian_blur, gblur, unsharp_mask, usm and box_blur in favor of ImageFilter implementations #2735
[homm]
- Dependencies: Updated freetype to 2.8.1 #2741
[radarhere]
- Bug: Player skipped first image #2742
[radarhere]
- Faster filter operations for Kernel, Gaussian, and Unsharp Mask filters #2679 - Faster filter operations for Kernel, Gaussian, and Unsharp Mask filters #2679
[homm] [homm]

View File

@ -123,6 +123,16 @@ try:
except ImportError: except ImportError:
HAS_CFFI = False HAS_CFFI = False
try:
from pathlib import Path
HAS_PATHLIB = True
except ImportError:
try:
from pathlib2 import Path
HAS_PATHLIB = True
except ImportError:
HAS_PATHLIB = False
def isImageType(t): def isImageType(t):
""" """
@ -150,6 +160,7 @@ ROTATE_90 = 2
ROTATE_180 = 3 ROTATE_180 = 3
ROTATE_270 = 4 ROTATE_270 = 4
TRANSPOSE = 5 TRANSPOSE = 5
TRANSVERSE = 6
# transforms # transforms
AFFINE = 0 AFFINE = 0
@ -1403,9 +1414,9 @@ class Image(object):
Performance Note: Not currently implemented in-place in the core layer. Performance Note: Not currently implemented in-place in the core layer.
""" """
if not isinstance(source, tuple): if not isinstance(source, (list, tuple)):
raise ValueError("Source must be a tuple") raise ValueError("Source must be a tuple")
if not isinstance(dest, tuple): if not isinstance(dest, (list, tuple)):
raise ValueError("Destination must be a tuple") raise ValueError("Destination must be a tuple")
if not len(source) in (2, 4): if not len(source) in (2, 4):
raise ValueError("Source must be a 2 or 4-tuple") raise ValueError("Source must be a 2 or 4-tuple")
@ -1429,7 +1440,7 @@ class Image(object):
box = dest + (dest[0] + overlay.width, dest[1] + overlay.height) box = dest + (dest[0] + overlay.width, dest[1] + overlay.height)
# destination image. don't copy if we're using the whole image. # destination image. don't copy if we're using the whole image.
if dest == (0,0) + self.size: if box == (0,0) + self.size:
background = self background = self
else: else:
background = self.crop(box) background = self.crop(box)
@ -1874,11 +1885,9 @@ class Image(object):
if isPath(fp): if isPath(fp):
filename = fp filename = fp
open_fp = True open_fp = True
elif sys.version_info >= (3, 4): elif HAS_PATHLIB and isinstance(fp, Path):
from pathlib import Path filename = str(fp)
if isinstance(fp, Path): open_fp = True
filename = str(fp)
open_fp = True
if not filename and hasattr(fp, "name") and isPath(fp.name): if not filename and hasattr(fp, "name") and isPath(fp.name):
# only set the name for metadata purposes # only set the name for metadata purposes
filename = fp.name filename = fp.name
@ -2173,8 +2182,8 @@ class Image(object):
:param method: One of :py:attr:`PIL.Image.FLIP_LEFT_RIGHT`, :param method: One of :py:attr:`PIL.Image.FLIP_LEFT_RIGHT`,
:py:attr:`PIL.Image.FLIP_TOP_BOTTOM`, :py:attr:`PIL.Image.ROTATE_90`, :py:attr:`PIL.Image.FLIP_TOP_BOTTOM`, :py:attr:`PIL.Image.ROTATE_90`,
:py:attr:`PIL.Image.ROTATE_180`, :py:attr:`PIL.Image.ROTATE_270` or :py:attr:`PIL.Image.ROTATE_180`, :py:attr:`PIL.Image.ROTATE_270`,
:py:attr:`PIL.Image.TRANSPOSE`. :py:attr:`PIL.Image.TRANSPOSE` or :py:attr:`PIL.Image.TRANSVERSE`.
:returns: Returns a flipped or rotated copy of this image. :returns: Returns a flipped or rotated copy of this image.
""" """
@ -2515,13 +2524,8 @@ def open(fp, mode="r"):
filename = "" filename = ""
if isPath(fp): if isPath(fp):
filename = fp filename = fp
else: elif HAS_PATHLIB and isinstance(fp, Path):
try: filename = str(fp.resolve())
from pathlib import Path
if isinstance(fp, Path):
filename = str(fp.resolve())
except ImportError:
pass
if filename: if filename:
fp = builtins.open(filename, "rb") fp = builtins.open(filename, "rb")

View File

@ -160,6 +160,26 @@ class GaussianBlur(MultibandFilter):
return image.gaussian_blur(self.radius) return image.gaussian_blur(self.radius)
class BoxBlur(MultibandFilter):
"""Blurs the image by setting each pixel to the average value of the pixels
in a square box extending radius pixels in each direction.
Supports float radius of arbitrary size. Uses an optimized implementation
which runs in linear time relative to the size of the image
for any radius value.
:param radius: Size of the box in one direction. Radius 0 does not blur,
returns an identical image. Radius 1 takes 1 pixel
in each direction, i.e. 9 pixels in total.
"""
name = "BoxBlur"
def __init__(self, radius):
self.radius = radius
def filter(self, image):
return image.box_blur(self.radius)
class UnsharpMask(MultibandFilter): class UnsharpMask(MultibandFilter):
"""Unsharp mask filter. """Unsharp mask filter.

View File

@ -21,6 +21,7 @@ from . import Image
from ._util import isStringType from ._util import isStringType
import operator import operator
import functools import functools
import warnings
# #
@ -437,6 +438,13 @@ def solarize(image, threshold=128):
def gaussian_blur(im, radius=None): def gaussian_blur(im, radius=None):
""" PIL_usm.gblur(im, [radius])""" """ PIL_usm.gblur(im, [radius])"""
warnings.warn(
'PIL.ImageOps.gaussian_blur is deprecated. '
'Use PIL.ImageFilter.GaussianBlur instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
if radius is None: if radius is None:
radius = 5.0 radius = 5.0
@ -444,12 +452,30 @@ def gaussian_blur(im, radius=None):
return im.im.gaussian_blur(radius) return im.im.gaussian_blur(radius)
gblur = gaussian_blur
def gblur(im, radius=None):
""" PIL_usm.gblur(im, [radius])"""
warnings.warn(
'PIL.ImageOps.gblur is deprecated. '
'Use PIL.ImageFilter.GaussianBlur instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
return gaussian_blur(im, radius)
def unsharp_mask(im, radius=None, percent=None, threshold=None): def unsharp_mask(im, radius=None, percent=None, threshold=None):
""" PIL_usm.usm(im, [radius, percent, threshold])""" """ PIL_usm.usm(im, [radius, percent, threshold])"""
warnings.warn(
'PIL.ImageOps.unsharp_mask is deprecated. '
'Use PIL.ImageFilter.UnsharpMask instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
if radius is None: if radius is None:
radius = 5.0 radius = 5.0
if percent is None: if percent is None:
@ -461,7 +487,18 @@ def unsharp_mask(im, radius=None, percent=None, threshold=None):
return im.im.unsharp_mask(radius, percent, threshold) return im.im.unsharp_mask(radius, percent, threshold)
usm = unsharp_mask
def usm(im, radius=None, percent=None, threshold=None):
""" PIL_usm.usm(im, [radius, percent, threshold])"""
warnings.warn(
'PIL.ImageOps.usm is deprecated. '
'Use PIL.ImageFilter.UnsharpMask instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
return unsharp_mask(im, radius, percent, threshold)
def box_blur(image, radius): def box_blur(image, radius):
@ -478,6 +515,13 @@ def box_blur(image, radius):
in each direction, i.e. 9 pixels in total. in each direction, i.e. 9 pixels in total.
:return: An image. :return: An image.
""" """
warnings.warn(
'PIL.ImageOps.box_blur is deprecated. '
'Use PIL.ImageFilter.BoxBlur instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
image.load() image.load()
return image._new(image.im.box_blur(radius)) return image._new(image.im.box_blur(radius))

View File

@ -49,8 +49,7 @@ class PyAccess(object):
self.image8 = ffi.cast('unsigned char **', vals['image8']) self.image8 = ffi.cast('unsigned char **', vals['image8'])
self.image32 = ffi.cast('int **', vals['image32']) self.image32 = ffi.cast('int **', vals['image32'])
self.image = ffi.cast('unsigned char **', vals['image']) self.image = ffi.cast('unsigned char **', vals['image'])
self.xsize = vals['xsize'] self.xsize, self.ysize = img.im.size
self.ysize = vals['ysize']
# Keep pointer to im object to prevent dereferencing. # Keep pointer to im object to prevent dereferencing.
self._im = img.im self._im = img.im

View File

@ -550,11 +550,28 @@ class ImageFileDirectory_v2(collections.MutableMapping):
dest = self._tags_v1 if legacy_api else self._tags_v2 dest = self._tags_v1 if legacy_api else self._tags_v2
if info.length == 1: # Three branches:
if legacy_api and self.tagtype[tag] in [5, 10]: # Spec'd length == 1, Actual length 1, store as element
# Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
# No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
# Don't mess with the legacy api, since it's frozen.
if ((info.length == 1) or
(info.length is None and len(values) == 1 and not legacy_api)):
# Don't mess with the legacy api, since it's frozen.
if legacy_api and self.tagtype[tag] in [5, 10]: # rationals
values = values, values = values,
dest[tag], = values try:
dest[tag], = values
except ValueError:
# We've got a builtin tag with 1 expected entry
warnings.warn(
"Metadata Warning, tag %s had too many entries: %s, expected 1" % (
tag, len(values)))
dest[tag] = values[0]
else: else:
# Spec'd length > 1 or undefined
# Unspec'd, and length > 1
dest[tag] = values dest[tag] = values
def __delitem__(self, tag): def __delitem__(self, tag):
@ -1011,8 +1028,10 @@ class TiffImageFile(ImageFile.ImageFile):
args = rawmode, "" args = rawmode, ""
if JPEGTABLES in self.tag_v2: if JPEGTABLES in self.tag_v2:
# Hack to handle abbreviated JPEG headers # Hack to handle abbreviated JPEG headers
# FIXME This will fail with more than one value # Definition of JPEGTABLES is that the count
self.tile_prefix, = self.tag_v2[JPEGTABLES] # is the number of bytes in the tables datastream
# so, it should always be 1 in our tag info
self.tile_prefix = self.tag_v2[JPEGTABLES]
elif compression == "packbits": elif compression == "packbits":
args = rawmode args = rawmode
elif compression == "tiff_lzw": elif compression == "tiff_lzw":

View File

@ -23,7 +23,7 @@ from collections import namedtuple
class TagInfo(namedtuple("_TagInfo", "value name type length enum")): class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
__slots__ = [] __slots__ = []
def __new__(cls, value=None, name="unknown", type=None, length=0, enum=None): def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None):
return super(TagInfo, cls).__new__( return super(TagInfo, cls).__new__(
cls, value, name, type, length, enum or {}) cls, value, name, type, length, enum or {})
@ -142,6 +142,8 @@ TAGS_V2 = {
341: ("SMaxSampleValue", DOUBLE, 0), 341: ("SMaxSampleValue", DOUBLE, 0),
342: ("TransferRange", SHORT, 6), 342: ("TransferRange", SHORT, 6),
347: ("JPEGTables", UNDEFINED, 1),
# obsolete JPEG tags # obsolete JPEG tags
512: ("JPEGProc", SHORT, 1), 512: ("JPEGProc", SHORT, 1),
513: ("JPEGInterchangeFormat", LONG, 1), 513: ("JPEGInterchangeFormat", LONG, 1),
@ -158,7 +160,10 @@ TAGS_V2 = {
531: ("YCbCrPositioning", SHORT, 1), 531: ("YCbCrPositioning", SHORT, 1),
532: ("ReferenceBlackWhite", LONG, 0), 532: ("ReferenceBlackWhite", LONG, 0),
700: ('XMP', BYTE, 1),
33432: ("Copyright", ASCII, 1), 33432: ("Copyright", ASCII, 1),
34377: ('PhotoshopInfo', BYTE, 1),
# FIXME add more tags here # FIXME add more tags here
34665: ("ExifIFD", SHORT, 1), 34665: ("ExifIFD", SHORT, 1),
@ -188,8 +193,8 @@ TAGS_V2 = {
50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}), 50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
50780: ("BestQualityScale", RATIONAL, 1), 50780: ("BestQualityScale", RATIONAL, 1),
50838: ("ImageJMetaDataByteCounts", LONG, 1), 50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one
50839: ("ImageJMetaData", UNDEFINED, 1) 50839: ("ImageJMetaData", UNDEFINED, 1) # see Issue #2006
} }
# Legacy Tags structure # Legacy Tags structure

View File

@ -22,13 +22,10 @@ from PIL import Image, ImageTk
class UI(tkinter.Label): class UI(tkinter.Label):
def __init__(self, master, im): def __init__(self, master, im):
if isinstance(im, list): self.im = im
if isinstance(self.im, list):
# list of images # list of images
self.im = im[1:] im = self.im.pop(0)
im = self.im[0]
else:
# sequence
self.im = im
if im.mode == "1": if im.mode == "1":
self.image = ImageTk.BitmapImage(im, foreground="white") self.image = ImageTk.BitmapImage(im, foreground="white")

BIN
Tests/images/issue_2278.tif Normal file

Binary file not shown.

View File

@ -13,20 +13,6 @@ sample.putdata(sum([
], [])) ], []))
class ImageMock(object):
def __init__(self):
self.im = self
def load(self):
pass
def _new(self, im):
return im
def box_blur(self, radius, n):
return radius, n
class TestBoxBlurApi(PillowTestCase): class TestBoxBlurApi(PillowTestCase):
def test_imageops_box_blur(self): def test_imageops_box_blur(self):

View File

@ -56,7 +56,7 @@ class TestFileTiffMetadata(PillowTestCase):
loaded = Image.open(f) loaded = Image.open(f)
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),)) self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], len(bindata)) self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag[ImageJMetaData], bindata) self.assertEqual(loaded.tag[ImageJMetaData], bindata)
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata) self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
@ -69,6 +69,16 @@ class TestFileTiffMetadata(PillowTestCase):
loaded_double = loaded.tag[tag_ids['YawAngle']][0] loaded_double = loaded.tag[tag_ids['YawAngle']][0]
self.assertAlmostEqual(loaded_double, doubledata) self.assertAlmostEqual(loaded_double, doubledata)
# check with 2 element ImageJMetaDataByteCounts, issue #2006
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
img.save(f, tiffinfo=info)
loaded = Image.open(f)
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
def test_read_metadata(self): def test_read_metadata(self):
img = Image.open('Tests/images/hopper_g4.tif') img = Image.open('Tests/images/hopper_g4.tif')
@ -202,8 +212,8 @@ class TestFileTiffMetadata(PillowTestCase):
im.save(out, tiffinfo=info, compression='raw') im.save(out, tiffinfo=info, compression='raw')
reloaded = Image.open(out) reloaded = Image.open(out)
self.assertEqual(0, reloaded.tag_v2[41988][0].numerator) self.assertEqual(0, reloaded.tag_v2[41988].numerator)
self.assertEqual(0, reloaded.tag_v2[41988][0].denominator) self.assertEqual(0, reloaded.tag_v2[41988].denominator)
def test_expty_values(self): def test_expty_values(self):
data = io.BytesIO( data = io.BytesIO(
@ -220,6 +230,27 @@ class TestFileTiffMetadata(PillowTestCase):
self.fail("Should not be struct value error there.") self.fail("Should not be struct value error there.")
self.assertIn(33432, info) self.assertIn(33432, info)
def test_PhotoshopInfo(self):
im = Image.open('Tests/images/issue_2278.tif')
self.assertIsInstance(im.tag_v2[34377], bytes)
out = self.tempfile('temp.tiff')
im.save(out)
reloaded = Image.open(out)
self.assertIsInstance(reloaded.tag_v2[34377], bytes)
def test_too_many_entries(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()
# 277: ("SamplesPerPixel", SHORT, 1),
ifd._tagdata[277] = struct.pack('hh', 4,4)
ifd.tagtype[277] = TiffTags.SHORT
try:
self.assert_warning(UserWarning, lambda: ifd[277])
except ValueError:
self.fail("Invalid Metadata count should not cause a Value Error.")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -2,7 +2,6 @@ from helper import unittest, PillowTestCase, hopper
from PIL import Image from PIL import Image
import os import os
import sys
class TestImage(PillowTestCase): class TestImage(PillowTestCase):
@ -72,10 +71,9 @@ class TestImage(PillowTestCase):
def test_bad_mode(self): def test_bad_mode(self):
self.assertRaises(ValueError, Image.open, "filename", "bad mode") self.assertRaises(ValueError, Image.open, "filename", "bad mode")
@unittest.skipIf(sys.version_info < (3, 4), @unittest.skipUnless(Image.HAS_PATHLIB, "requires pathlib/pathlib2")
"pathlib only available in Python 3.4 or later")
def test_pathlib(self): def test_pathlib(self):
from pathlib import Path from PIL.Image import Path
im = Image.open(Path("Tests/images/hopper.jpg")) im = Image.open(Path("Tests/images/hopper.jpg"))
self.assertEqual(im.mode, "RGB") self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128)) self.assertEqual(im.size, (128, 128))

View File

@ -1,7 +1,6 @@
from helper import unittest, PillowTestCase, hopper from helper import unittest, PillowTestCase, hopper
from PIL import Image from PIL import Image, ImageFilter
from PIL import ImageFilter
class TestImageFilter(PillowTestCase): class TestImageFilter(PillowTestCase):
@ -9,10 +8,11 @@ class TestImageFilter(PillowTestCase):
def test_sanity(self): def test_sanity(self):
def filter(filter): def filter(filter):
im = hopper("L") for mode in ["L", "RGB", "CMYK"]:
out = im.filter(filter) im = hopper(mode)
self.assertEqual(out.mode, im.mode) out = im.filter(filter)
self.assertEqual(out.size, im.size) self.assertEqual(out.mode, im.mode)
self.assertEqual(out.size, im.size)
filter(ImageFilter.BLUR) filter(ImageFilter.BLUR)
filter(ImageFilter.CONTOUR) filter(ImageFilter.CONTOUR)
@ -28,9 +28,9 @@ class TestImageFilter(PillowTestCase):
filter(ImageFilter.MedianFilter) filter(ImageFilter.MedianFilter)
filter(ImageFilter.MinFilter) filter(ImageFilter.MinFilter)
filter(ImageFilter.ModeFilter) filter(ImageFilter.ModeFilter)
filter(ImageFilter.Kernel((3, 3), list(range(9))))
filter(ImageFilter.GaussianBlur) filter(ImageFilter.GaussianBlur)
filter(ImageFilter.GaussianBlur(5)) filter(ImageFilter.GaussianBlur(5))
filter(ImageFilter.BoxBlur(5))
filter(ImageFilter.UnsharpMask) filter(ImageFilter.UnsharpMask)
filter(ImageFilter.UnsharpMask(10)) filter(ImageFilter.UnsharpMask(10))

View File

@ -2,7 +2,7 @@ import helper
from helper import unittest, PillowTestCase from helper import unittest, PillowTestCase
from PIL.Image import (FLIP_LEFT_RIGHT, FLIP_TOP_BOTTOM, ROTATE_90, ROTATE_180, from PIL.Image import (FLIP_LEFT_RIGHT, FLIP_TOP_BOTTOM, ROTATE_90, ROTATE_180,
ROTATE_270, TRANSPOSE) ROTATE_270, TRANSPOSE, TRANSVERSE)
class TestImageTranspose(PillowTestCase): class TestImageTranspose(PillowTestCase):
@ -108,6 +108,22 @@ class TestImageTranspose(PillowTestCase):
for mode in ("L", "RGB"): for mode in ("L", "RGB"):
transpose(mode) transpose(mode)
def test_tranverse(self):
def transpose(mode):
im = self.hopper[mode]
out = im.transpose(TRANSVERSE)
self.assertEqual(out.mode, mode)
self.assertEqual(out.size, im.size[::-1])
x, y = im.size
self.assertEqual(im.getpixel((1, 1)), out.getpixel((y-2, x-2)))
self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((y-2, 1)))
self.assertEqual(im.getpixel((1, y-2)), out.getpixel((1, x-2)))
self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((1, 1)))
for mode in ("L", "RGB"):
transpose(mode)
def test_roundtrip(self): def test_roundtrip(self):
im = self.hopper['L'] im = self.hopper['L']
@ -124,6 +140,12 @@ class TestImageTranspose(PillowTestCase):
im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM)) im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM))
self.assert_image_equal( self.assert_image_equal(
im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT)) im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT))
self.assert_image_equal(
im.transpose(TRANSVERSE), transpose(ROTATE_90, FLIP_LEFT_RIGHT))
self.assert_image_equal(
im.transpose(TRANSVERSE), transpose(ROTATE_270, FLIP_TOP_BOTTOM))
self.assert_image_equal(
im.transpose(TRANSVERSE), transpose(ROTATE_180, TRANSPOSE))
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -12,15 +12,25 @@ class TestImageOpsUsm(PillowTestCase):
def test_ops_api(self): def test_ops_api(self):
i = ImageOps.gaussian_blur(im, 2.0) i = self.assert_warning(DeprecationWarning,
ImageOps.gaussian_blur, im, 2.0)
self.assertEqual(i.mode, "RGB") self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128)) self.assertEqual(i.size, (128, 128))
# i.save("blur.bmp")
i = ImageOps.unsharp_mask(im, 2.0, 125, 8) i = self.assert_warning(DeprecationWarning,
ImageOps.gblur, im, 2.0)
self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128))
i = self.assert_warning(DeprecationWarning,
ImageOps.unsharp_mask, im, 2.0, 125, 8)
self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128))
i = self.assert_warning(DeprecationWarning,
ImageOps.usm, im, 2.0, 125, 8)
self.assertEqual(i.mode, "RGB") self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128)) self.assertEqual(i.size, (128, 128))
# i.save("usm.bmp")
def test_filter_api(self): def test_filter_api(self):
@ -36,38 +46,38 @@ class TestImageOpsUsm(PillowTestCase):
def test_usm_formats(self): def test_usm_formats(self):
usm = ImageOps.unsharp_mask usm = ImageFilter.UnsharpMask
self.assertRaises(ValueError, usm, im.convert("1")) self.assertRaises(ValueError, im.convert("1").filter, usm)
usm(im.convert("L")) im.convert("L").filter(usm)
self.assertRaises(ValueError, usm, im.convert("I")) self.assertRaises(ValueError, im.convert("I").filter, usm)
self.assertRaises(ValueError, usm, im.convert("F")) self.assertRaises(ValueError, im.convert("F").filter, usm)
usm(im.convert("RGB")) im.convert("RGB").filter(usm)
usm(im.convert("RGBA")) im.convert("RGBA").filter(usm)
usm(im.convert("CMYK")) im.convert("CMYK").filter(usm)
self.assertRaises(ValueError, usm, im.convert("YCbCr")) self.assertRaises(ValueError, im.convert("YCbCr").filter, usm)
def test_blur_formats(self): def test_blur_formats(self):
blur = ImageOps.gaussian_blur blur = ImageFilter.GaussianBlur
self.assertRaises(ValueError, blur, im.convert("1")) self.assertRaises(ValueError, im.convert("1").filter, blur)
blur(im.convert("L")) blur(im.convert("L"))
self.assertRaises(ValueError, blur, im.convert("I")) self.assertRaises(ValueError, im.convert("I").filter, blur)
self.assertRaises(ValueError, blur, im.convert("F")) self.assertRaises(ValueError, im.convert("F").filter, blur)
blur(im.convert("RGB")) im.convert("RGB").filter(blur)
blur(im.convert("RGBA")) im.convert("RGBA").filter(blur)
blur(im.convert("CMYK")) im.convert("CMYK").filter(blur)
self.assertRaises(ValueError, blur, im.convert("YCbCr")) self.assertRaises(ValueError, im.convert("YCbCr").filter, blur)
def test_usm_accuracy(self): def test_usm_accuracy(self):
src = snakes.convert('RGB') src = snakes.convert('RGB')
i = src._new(ImageOps.unsharp_mask(src, 5, 1024, 0)) i = src.filter(ImageFilter.UnsharpMask(5, 1024, 0))
# Image should not be changed because it have only 0 and 255 levels. # Image should not be changed because it have only 0 and 255 levels.
self.assertEqual(i.tobytes(), src.tobytes()) self.assertEqual(i.tobytes(), src.tobytes())
def test_blur_accuracy(self): def test_blur_accuracy(self):
i = snakes._new(ImageOps.gaussian_blur(snakes, .4)) i = snakes.filter(ImageFilter.GaussianBlur(.4))
# These pixels surrounded with pixels with 255 intensity. # These pixels surrounded with pixels with 255 intensity.
# They must be very close to 255. # They must be very close to 255.
for x, y, c in [(1, 0, 1), (2, 0, 1), (7, 8, 1), (8, 8, 1), (2, 9, 1), for x, y, c in [(1, 0, 1), (2, 0, 1), (7, 8, 1), (8, 8, 1), (2, 9, 1),

View File

@ -1678,6 +1678,7 @@ _transpose(ImagingObject* self, PyObject* args)
case 2: /* rotate 90 */ case 2: /* rotate 90 */
case 4: /* rotate 270 */ case 4: /* rotate 270 */
case 5: /* transpose */ case 5: /* transpose */
case 6: /* transverse */
imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize); imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
break; break;
default: default:
@ -1705,6 +1706,9 @@ _transpose(ImagingObject* self, PyObject* args)
case 5: case 5:
(void) ImagingTranspose(imOut, imIn); (void) ImagingTranspose(imOut, imIn);
break; break;
case 6:
(void) ImagingTransverse(imOut, imIn);
break;
} }
return PyImagingNew(imOut); return PyImagingNew(imOut);
@ -3138,21 +3142,10 @@ _getattr_ptr(ImagingObject* self, void* closure)
static PyObject* static PyObject*
_getattr_unsafe_ptrs(ImagingObject* self, void* closure) _getattr_unsafe_ptrs(ImagingObject* self, void* closure)
{ {
return Py_BuildValue("(ss)(si)(si)(si)(si)(si)(sn)(sn)(sn)(sn)(sn)(si)(si)(sn)", return Py_BuildValue("(sn)(sn)(sn)",
"mode", self->image->mode,
"type", self->image->type,
"depth", self->image->depth,
"bands", self->image->bands,
"xsize", self->image->xsize,
"ysize", self->image->ysize,
"palette", self->image->palette,
"image8", self->image->image8, "image8", self->image->image8,
"image32", self->image->image32, "image32", self->image->image32,
"image", self->image->image, "image", self->image->image
"block", self->image->block,
"pixelsize", self->image->pixelsize,
"linesize", self->image->linesize,
"destroy", self->image->destroy
); );
}; };

View File

@ -38,6 +38,7 @@ image enhancement filters:
* **SHARPEN** * **SHARPEN**
.. autoclass:: PIL.ImageFilter.GaussianBlur .. autoclass:: PIL.ImageFilter.GaussianBlur
.. autoclass:: PIL.ImageFilter.BoxBlur
.. autoclass:: PIL.ImageFilter.UnsharpMask .. autoclass:: PIL.ImageFilter.UnsharpMask
.. autoclass:: PIL.ImageFilter.Kernel .. autoclass:: PIL.ImageFilter.Kernel
.. autoclass:: PIL.ImageFilter.RankFilter .. autoclass:: PIL.ImageFilter.RankFilter

View File

@ -4,13 +4,19 @@
Get One Channel From Image Get One Channel From Image
========================== ==========================
New method :py:meth:`PIL.Image.Image.getchannel` added. New method :py:meth:`PIL.Image.Image.getchannel` is added.
It returns single channel by index or name. For example, It returns single channel by index or name. For example,
``image.getchannel("A")`` will return alpha channel as separate image. ``image.getchannel("A")`` will return alpha channel as separate image.
``getchannel`` should work up to 6 times faster than ``image.split()[0]`` ``getchannel`` should work up to 6 times faster than ``image.split()[0]``
in previous Pillow versions. in previous Pillow versions.
Box Blur
========
New filter :py:class:`PIL.ImageFilter.BoxBlur` is added.
Partial Resampling Partial Resampling
================== ==================
@ -40,6 +46,22 @@ This release contains several performance improvements:
using a recent version of libjpeg-turbo. using a recent version of libjpeg-turbo.
TIFF Metadata Changes
=====================
* TIFF tags with unknown type/quantity now default to being bare
values if they are 1 element, where previously they would be a
single element tuple. This is only with the new api, not the legacy
api. This normalizes the handling of fields, so that the metadata
with inferred or image specified counts are handled the same as
metadata with count specified in the TIFF spec.
* The ``PhotoshopInfo``, ``XMP``, and ``JPEGTables`` tags now have a
defined type (bytes) and a count of 1.
* The ``ImageJMetaDataByteCounts`` tag now has an arbitrary number of
items, as there can be multiple items, one for UTF-8, and one for
UTF-16.
Core Image API Changes Core Image API Changes
====================== ======================

View File

@ -11,6 +11,7 @@
#include "Imaging.h" #include "Imaging.h"
#define PRECISION_BITS 7
typedef struct typedef struct
{ {
@ -47,13 +48,11 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
return NULL; return NULL;
for (y = 0; y < imDst->ysize; y++) { for (y = 0; y < imDst->ysize; y++) {
rgba8* dst = (rgba8*) imDst->image[y]; rgba8* dst = (rgba8*) imDst->image[y];
rgba8* src = (rgba8*) imSrc->image[y]; rgba8* src = (rgba8*) imSrc->image[y];
rgba8* out = (rgba8*) imOut->image[y]; rgba8* out = (rgba8*) imOut->image[y];
for (x = 0; x < imDst->xsize; x ++) { for (x = 0; x < imDst->xsize; x ++) {
if (src->a == 0) { if (src->a == 0) {
// Copy 4 bytes at once. // Copy 4 bytes at once.
*out = *dst; *out = *dst;
@ -62,25 +61,20 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
// Each variable has extra meaningful bits. // Each variable has extra meaningful bits.
// Divisions are rounded. // Divisions are rounded.
// This code uses trick from Paste.c:
// (a + (2 << (n-1)) - 1) / ((2 << n)-1)
// almost equivalent to:
// tmp = a + (2 << (n-1)), ((tmp >> n) + tmp) >> n
UINT32 tmpr, tmpg, tmpb; UINT32 tmpr, tmpg, tmpb;
UINT16 blend = dst->a * (255 - src->a); UINT32 blend = dst->a * (255 - src->a);
UINT16 outa255 = src->a * 255 + blend; UINT32 outa255 = src->a * 255 + blend;
// There we use 7 bits for precision. // There we use 7 bits for precision.
// We could use more, but we go beyond 32 bits. // We could use more, but we go beyond 32 bits.
UINT16 coef1 = src->a * 255 * 255 * 128 / outa255; UINT32 coef1 = src->a * 255 * 255 * (1<<PRECISION_BITS) / outa255;
UINT16 coef2 = 255 * 128 - coef1; UINT32 coef2 = 255 * (1<<PRECISION_BITS) - coef1;
tmpr = src->r * coef1 + dst->r * coef2 + (0x80 << 7); tmpr = src->r * coef1 + dst->r * coef2;
out->r = SHIFTFORDIV255(tmpr) >> 7; tmpg = src->g * coef1 + dst->g * coef2;
tmpg = src->g * coef1 + dst->g * coef2 + (0x80 << 7); tmpb = src->b * coef1 + dst->b * coef2;
out->g = SHIFTFORDIV255(tmpg) >> 7; out->r = SHIFTFORDIV255(tmpr + (0x80<<PRECISION_BITS)) >> PRECISION_BITS;
tmpb = src->b * coef1 + dst->b * coef2 + (0x80 << 7); out->g = SHIFTFORDIV255(tmpg + (0x80<<PRECISION_BITS)) >> PRECISION_BITS;
out->b = SHIFTFORDIV255(tmpb) >> 7; out->b = SHIFTFORDIV255(tmpb + (0x80<<PRECISION_BITS)) >> PRECISION_BITS;
out->a = SHIFTFORDIV255(outa255 + 0x80); out->a = SHIFTFORDIV255(outa255 + 0x80);
} }

View File

@ -84,7 +84,7 @@ ImagingSplit(Imaging imIn, Imaging bands[4])
} }
for (i = 0; i < imIn->bands; i++) { for (i = 0; i < imIn->bands; i++) {
bands[i] = ImagingNew("L", imIn->xsize, imIn->ysize); bands[i] = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
if ( ! bands[i]) { if ( ! bands[i]) {
for (j = 0; j < i; ++j) { for (j = 0; j < i; ++j) {
ImagingDelete(bands[j]); ImagingDelete(bands[j]);

View File

@ -19,41 +19,41 @@
#include "Imaging.h" #include "Imaging.h"
#define CHOP(operation, mode)\ #define CHOP(operation, mode)\
int x, y;\ int x, y;\
Imaging imOut;\ Imaging imOut;\
imOut = create(imIn1, imIn2, mode);\ imOut = create(imIn1, imIn2, mode);\
if (!imOut)\ if (!imOut)\
return NULL;\ return NULL;\
for (y = 0; y < imOut->ysize; y++) {\ for (y = 0; y < imOut->ysize; y++) {\
UINT8* out = (UINT8*) imOut->image[y];\ UINT8* out = (UINT8*) imOut->image[y];\
UINT8* in1 = (UINT8*) imIn1->image[y];\ UINT8* in1 = (UINT8*) imIn1->image[y];\
UINT8* in2 = (UINT8*) imIn2->image[y];\ UINT8* in2 = (UINT8*) imIn2->image[y];\
for (x = 0; x < imOut->linesize; x++) {\ for (x = 0; x < imOut->linesize; x++) {\
int temp = operation;\ int temp = operation;\
if (temp <= 0)\ if (temp <= 0)\
out[x] = 0;\ out[x] = 0;\
else if (temp >= 255)\ else if (temp >= 255)\
out[x] = 255;\ out[x] = 255;\
else\ else\
out[x] = temp;\ out[x] = temp;\
}\ }\
}\ }\
return imOut; return imOut;
#define CHOP2(operation, mode)\ #define CHOP2(operation, mode)\
int x, y;\ int x, y;\
Imaging imOut;\ Imaging imOut;\
imOut = create(imIn1, imIn2, mode);\ imOut = create(imIn1, imIn2, mode);\
if (!imOut)\ if (!imOut)\
return NULL;\ return NULL;\
for (y = 0; y < imOut->ysize; y++) {\ for (y = 0; y < imOut->ysize; y++) {\
UINT8* out = (UINT8*) imOut->image[y];\ UINT8* out = (UINT8*) imOut->image[y];\
UINT8* in1 = (UINT8*) imIn1->image[y];\ UINT8* in1 = (UINT8*) imIn1->image[y];\
UINT8* in2 = (UINT8*) imIn2->image[y];\ UINT8* in2 = (UINT8*) imIn2->image[y];\
for (x = 0; x < imOut->linesize; x++) {\ for (x = 0; x < imOut->linesize; x++) {\
out[x] = operation;\ out[x] = operation;\
}\ }\
}\ }\
return imOut; return imOut;
@ -64,15 +64,15 @@ create(Imaging im1, Imaging im2, char* mode)
if (!im1 || !im2 || im1->type != IMAGING_TYPE_UINT8 || if (!im1 || !im2 || im1->type != IMAGING_TYPE_UINT8 ||
(mode != NULL && (strcmp(im1->mode, "1") || strcmp(im2->mode, "1")))) (mode != NULL && (strcmp(im1->mode, "1") || strcmp(im2->mode, "1"))))
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
if (im1->type != im2->type || if (im1->type != im2->type ||
im1->bands != im2->bands) im1->bands != im2->bands)
return (Imaging) ImagingError_Mismatch(); return (Imaging) ImagingError_Mismatch();
xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize; xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize;
ysize = (im1->ysize < im2->ysize) ? im1->ysize : im2->ysize; ysize = (im1->ysize < im2->ysize) ? im1->ysize : im2->ysize;
return ImagingNew(im1->mode, xsize, ysize); return ImagingNewDirty(im1->mode, xsize, ysize);
} }
Imaging Imaging

View File

@ -37,7 +37,7 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality)
if (width < 0.0 || height < 0.0 || quality < 2) if (width < 0.0 || height < 0.0 || quality < 2)
return (Imaging) ImagingError_ValueError(NULL); return (Imaging) ImagingError_ValueError(NULL);
im = ImagingNew("L", xsize, ysize); im = ImagingNewDirty("L", xsize, ysize);
if (!im) if (!im)
return NULL; return NULL;
@ -81,7 +81,7 @@ ImagingEffectNoise(int xsize, int ysize, float sigma)
int nextok; int nextok;
double this, next; double this, next;
imOut = ImagingNew("L", xsize, ysize); imOut = ImagingNewDirty("L", xsize, ysize);
if (!imOut) if (!imOut)
return NULL; return NULL;
@ -90,7 +90,7 @@ ImagingEffectNoise(int xsize, int ysize, float sigma)
for (y = 0; y < imOut->ysize; y++) { for (y = 0; y < imOut->ysize; y++) {
UINT8* out = imOut->image8[y]; UINT8* out = imOut->image8[y];
for (x = 0; x < imOut->xsize; x++) { for (x = 0; x < imOut->xsize; x++) {
if (nextok) { if (nextok) {
this = next; this = next;
nextok = 0; nextok = 0;
@ -121,14 +121,14 @@ ImagingEffectSpread(Imaging imIn, int distance)
Imaging imOut; Imaging imOut;
int x, y; int x, y;
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
if (!imOut) if (!imOut)
return NULL; return NULL;
#define SPREAD(type, image)\ #define SPREAD(type, image)\
for (y = 0; y < imIn->ysize; y++)\ for (y = 0; y < imOut->ysize; y++)\
for (x = 0; x < imIn->xsize; x++) {\ for (x = 0; x < imOut->xsize; x++) {\
int xx = x + (rand() % distance) - distance/2;\ int xx = x + (rand() % distance) - distance/2;\
int yy = y + (rand() % distance) - distance/2;\ int yy = y + (rand() % distance) - distance/2;\
if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) {\ if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) {\

View File

@ -27,13 +27,6 @@
#include "Imaging.h" #include "Imaging.h"
#ifdef WORDS_BIGENDIAN
#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))
#endif
static inline UINT8 clip8(float in) static inline UINT8 clip8(float in)
{ {
if (in <= 0.0) if (in <= 0.0)
@ -91,29 +84,14 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
} }
/* This is work around bug in GCC prior 4.9 in 64 bit mode.
GCC generates code with partial dependency which 3 times slower.
See: http://stackoverflow.com/a/26588074/253146 */
#if defined(__x86_64__) && defined(__SSE__) && ! defined(__NO_INLINE__) && \
! defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
static float __attribute__((always_inline)) inline i2f(int v) {
float x;
__asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=X"(x) : "r"(v) );
return x;
}
#else
static float inline i2f(int v) { return (float) v; }
#endif
void void
ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel, ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel,
float offset) float offset)
{ {
#define KERNEL1x3(in0, x, kernel, d) ( \ #define KERNEL1x3(in0, x, kernel, d) ( \
i2f((UINT8) in0[x-d]) * (kernel)[0] + \ _i2f((UINT8) in0[x-d]) * (kernel)[0] + \
i2f((UINT8) in0[x]) * (kernel)[1] + \ _i2f((UINT8) in0[x]) * (kernel)[1] + \
i2f((UINT8) in0[x+d]) * (kernel)[2]) _i2f((UINT8) in0[x+d]) * (kernel)[2])
int x = 0, y = 0; int x = 0, y = 0;
@ -210,11 +188,11 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float* kernel,
float offset) float offset)
{ {
#define KERNEL1x5(in0, x, kernel, d) ( \ #define KERNEL1x5(in0, x, kernel, d) ( \
i2f((UINT8) in0[x-d-d]) * (kernel)[0] + \ _i2f((UINT8) in0[x-d-d]) * (kernel)[0] + \
i2f((UINT8) in0[x-d]) * (kernel)[1] + \ _i2f((UINT8) in0[x-d]) * (kernel)[1] + \
i2f((UINT8) in0[x]) * (kernel)[2] + \ _i2f((UINT8) in0[x]) * (kernel)[2] + \
i2f((UINT8) in0[x+d]) * (kernel)[3] + \ _i2f((UINT8) in0[x+d]) * (kernel)[3] + \
i2f((UINT8) in0[x+d+d]) * (kernel)[4]) _i2f((UINT8) in0[x+d+d]) * (kernel)[4])
int x = 0, y = 0; int x = 0, y = 0;

View File

@ -5,7 +5,8 @@
Rotating in chunks that fit in the cache can speed up rotation Rotating in chunks that fit in the cache can speed up rotation
8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough 8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough
that the overhead from the extra loops are not apparent. */ that the overhead from the extra loops are not apparent. */
#define ROTATE_CHUNK 128 #define ROTATE_CHUNK 512
#define ROTATE_SMALL_CHUNK 8
#define COORD(v) ((v) < 0.0 ? -1 : ((int)(v))) #define COORD(v) ((v) < 0.0 ? -1 : ((int)(v)))
#define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v))) #define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v)))
@ -26,30 +27,27 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn)
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define FLIP_LEFT_RIGHT(INT, image) \
for (y = 0; y < imIn->ysize; y++) { \
INT* in = imIn->image[y]; \
INT* out = imOut->image[y]; \
xr = imIn->xsize-1; \
for (x = 0; x < imIn->xsize; x++, xr--) \
out[xr] = in[x]; \
}
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) { if (imIn->image8) {
for (y = 0; y < imIn->ysize; y++) { FLIP_LEFT_RIGHT(UINT8, image8)
UINT8* in = (UINT8*) imIn->image8[y];
UINT8* out = (UINT8*) imOut->image8[y];
x = 0;
xr = imIn->xsize-1;
for (; x < imIn->xsize; x++, xr--)
out[xr] = in[x];
}
} else { } else {
for (y = 0; y < imIn->ysize; y++) { FLIP_LEFT_RIGHT(INT32, image32)
UINT32* in = (UINT32*) imIn->image32[y];
UINT32* out = (UINT32*) imOut->image32[y];
x = 0;
xr = imIn->xsize-1;
for (; x < imIn->xsize; x++, xr--)
out[xr] = in[x];
}
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
#undef FLIP_LEFT_RIGHT
return imOut; return imOut;
} }
@ -84,6 +82,7 @@ ImagingRotate90(Imaging imOut, Imaging imIn)
{ {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
int x, y, xx, yy, xr, xxsize, yysize; int x, y, xx, yy, xr, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
@ -92,15 +91,22 @@ ImagingRotate90(Imaging imOut, Imaging imIn)
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define ROTATE_90(image) \ #define ROTATE_90(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy++) { \ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
xr = imIn->xsize - 1 - x; \ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx++, xr--) { \ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
imOut->image[xr][yy] = imIn->image[yy][xx]; \ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
for (yyy = yy; yyy < yyysize; yyy++) { \
INT* in = imIn->image[yyy]; \
xr = imIn->xsize - 1 - xx; \
for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
imOut->image[xr][yyy] = in[xxx]; \
} \
} \
} \ } \
} \ } \
} \ } \
@ -109,9 +115,9 @@ ImagingRotate90(Imaging imOut, Imaging imIn)
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) if (imIn->image8)
ROTATE_90(image8) ROTATE_90(UINT8, image8)
else else
ROTATE_90(image32) ROTATE_90(INT32, image32)
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
@ -126,6 +132,7 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
{ {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
int x, y, xx, yy, xxsize, yysize; int x, y, xx, yy, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
@ -134,14 +141,21 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define TRANSPOSE(image) \ #define TRANSPOSE(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy++) { \ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx++) { \ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
imOut->image[xx][yy] = imIn->image[yy][xx]; \ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
for (yyy = yy; yyy < yyysize; yyy++) { \
INT* in = imIn->image[yyy]; \
for (xxx = xx; xxx < xxxsize; xxx++) { \
imOut->image[xxx][yyy] = in[xxx]; \
} \
} \
} \ } \
} \ } \
} \ } \
@ -150,9 +164,9 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) if (imIn->image8)
TRANSPOSE(image8) TRANSPOSE(UINT8, image8)
else else
TRANSPOSE(image32) TRANSPOSE(INT32, image32)
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
@ -162,6 +176,57 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
} }
Imaging
ImagingTransverse(Imaging imOut, Imaging imIn)
{
ImagingSectionCookie cookie;
int x, y, xr, yr, xx, yy, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
return (Imaging) ImagingError_ModeError();
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
return (Imaging) ImagingError_Mismatch();
ImagingCopyInfo(imOut, imIn);
#define TRANSVERSE(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
yr = imIn->ysize - 1 - yy; \
for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
INT* in = imIn->image[yyy]; \
xr = imIn->xsize - 1 - xx; \
for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
imOut->image[xr][yr] = in[xxx]; \
} \
} \
} \
} \
} \
}
ImagingSectionEnter(&cookie);
if (imIn->image8)
TRANSVERSE(UINT8, image8)
else
TRANSVERSE(INT32, image32)
ImagingSectionLeave(&cookie);
#undef TRANSVERSE
return imOut;
}
Imaging Imaging
ImagingRotate180(Imaging imOut, Imaging imIn) ImagingRotate180(Imaging imOut, Imaging imIn)
{ {
@ -175,20 +240,23 @@ ImagingRotate180(Imaging imOut, Imaging imIn)
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define ROTATE_180(image)\ #define ROTATE_180(INT, image) \
for (y = 0; y < imIn->ysize; y++, yr--) {\ for (y = 0; y < imIn->ysize; y++, yr--) { \
xr = imIn->xsize-1;\ INT* in = imIn->image[y]; \
for (x = 0; x < imIn->xsize; x++, xr--)\ INT* out = imOut->image[yr]; \
imOut->image[y][x] = imIn->image[yr][xr];\ xr = imIn->xsize-1; \
for (x = 0; x < imIn->xsize; x++, xr--) \
out[xr] = in[x]; \
} }
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
yr = imIn->ysize-1; yr = imIn->ysize-1;
if (imIn->image8) if (imIn->image8) {
ROTATE_180(image8) ROTATE_180(UINT8, image8)
else } else {
ROTATE_180(image32) ROTATE_180(INT32, image32)
}
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
@ -203,6 +271,7 @@ ImagingRotate270(Imaging imOut, Imaging imIn)
{ {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
int x, y, xx, yy, yr, xxsize, yysize; int x, y, xx, yy, yr, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
@ -211,15 +280,22 @@ ImagingRotate270(Imaging imOut, Imaging imIn)
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define ROTATE_270(image) \ #define ROTATE_270(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
yr = imIn->ysize - 1 - y; \ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (yy = y; yy < yysize; yy++, yr--) { \ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx++) { \ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
imOut->image[xx][yr] = imIn->image[yy][xx]; \ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
yr = imIn->ysize - 1 - yy; \
for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
INT* in = imIn->image[yyy]; \
for (xxx = xx; xxx < xxxsize; xxx++) { \
imOut->image[xxx][yr] = in[xxx]; \
} \
} \
} \ } \
} \ } \
} \ } \
@ -228,9 +304,9 @@ ImagingRotate270(Imaging imOut, Imaging imIn)
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) if (imIn->image8)
ROTATE_270(image8) ROTATE_270(UINT8, image8)
else else
ROTATE_270(image32) ROTATE_270(INT32, image32)
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);

View File

@ -20,7 +20,7 @@ extern "C" {
#ifndef M_PI #ifndef M_PI
#define M_PI 3.1415926535897932384626433832795 #define M_PI 3.1415926535897932384626433832795
#endif #endif
@ -29,18 +29,18 @@ extern "C" {
/* /*
* Image data organization: * Image data organization:
* *
* mode bytes byte order * mode bytes byte order
* ------------------------------- * -------------------------------
* 1 1 1 * 1 1 1
* L 1 L * L 1 L
* P 1 P * P 1 P
* I 4 I (32-bit integer, native byte order) * I 4 I (32-bit integer, native byte order)
* F 4 F (32-bit IEEE float, native byte order) * F 4 F (32-bit IEEE float, native byte order)
* RGB 4 R, G, B, - * RGB 4 R, G, B, -
* RGBA 4 R, G, B, A * RGBA 4 R, G, B, A
* CMYK 4 C, M, Y, K * CMYK 4 C, M, Y, K
* YCbCr 4 Y, Cb, Cr, - * YCbCr 4 Y, Cb, Cr, -
* Lab 4 L, a, b, - * Lab 4 L, a, b, -
* *
* experimental modes (incomplete): * experimental modes (incomplete):
* LA 4 L, -, -, A * LA 4 L, -, -, A
@ -78,26 +78,26 @@ typedef struct ImagingPaletteInstance* ImagingPalette;
struct ImagingMemoryInstance { struct ImagingMemoryInstance {
/* Format */ /* Format */
char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */
int type; /* Data type (IMAGING_TYPE_*) */ int type; /* Data type (IMAGING_TYPE_*) */
int depth; /* Depth (ignored in this version) */ int depth; /* Depth (ignored in this version) */
int bands; /* Number of bands (1, 2, 3, or 4) */ int bands; /* Number of bands (1, 2, 3, or 4) */
int xsize; /* Image dimension. */ int xsize; /* Image dimension. */
int ysize; int ysize;
/* Colour palette (for "P" images only) */ /* Colour palette (for "P" images only) */
ImagingPalette palette; ImagingPalette palette;
/* Data pointers */ /* Data pointers */
UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */ UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */
INT32 **image32; /* Set for 32-bit images (pixelsize=4). */ INT32 **image32; /* Set for 32-bit images (pixelsize=4). */
/* Internals */ /* Internals */
char **image; /* Actual raster data. */ char **image; /* Actual raster data. */
char *block; /* Set if data is allocated in a single block. */ char *block; /* Set if data is allocated in a single block. */
int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */ int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */
int linesize; /* Size of a line, in bytes (xsize * pixelsize) */ int linesize; /* Size of a line, in bytes (xsize * pixelsize) */
/* Virtual methods */ /* Virtual methods */
void (*destroy)(Imaging im); void (*destroy)(Imaging im);
@ -130,11 +130,11 @@ struct ImagingAccessInstance {
struct ImagingHistogramInstance { struct ImagingHistogramInstance {
/* Format */ /* Format */
char mode[IMAGING_MODE_LENGTH]; /* Band names (of corresponding source image) */ char mode[IMAGING_MODE_LENGTH]; /* Band names (of corresponding source image) */
int bands; /* Number of bands (1, 3, or 4) */ int bands; /* Number of bands (1, 3, or 4) */
/* Data */ /* Data */
long *histogram; /* Histogram (bands*256 longs) */ long *histogram; /* Histogram (bands*256 longs) */
}; };
@ -142,13 +142,13 @@ struct ImagingHistogramInstance {
struct ImagingPaletteInstance { struct ImagingPaletteInstance {
/* Format */ /* Format */
char mode[IMAGING_MODE_LENGTH]; /* Band names */ char mode[IMAGING_MODE_LENGTH]; /* Band names */
/* Data */ /* Data */
UINT8 palette[1024];/* Palette data (same format as image data) */ UINT8 palette[1024];/* Palette data (same format as image data) */
INT16* cache; /* Palette cache (used for predefined palettes) */ INT16* cache; /* Palette cache (used for predefined palettes) */
int keep_cache; /* This palette will be reused; keep cache */ int keep_cache; /* This palette will be reused; keep cache */
}; };
@ -170,8 +170,8 @@ extern Imaging ImagingNewMap(const char* filename, int readonly,
extern Imaging ImagingNewPrologue(const char *mode, extern Imaging ImagingNewPrologue(const char *mode,
int xsize, int ysize); int xsize, int ysize);
extern Imaging ImagingNewPrologueSubtype(const char *mode, extern Imaging ImagingNewPrologueSubtype(const char *mode,
int xsize, int ysize, int xsize, int ysize,
int structure_size); int structure_size);
extern void ImagingCopyPalette(Imaging destination, Imaging source); extern void ImagingCopyPalette(Imaging destination, Imaging source);
@ -181,8 +181,6 @@ extern void ImagingAccessInit(void);
extern ImagingAccess ImagingAccessNew(Imaging im); extern ImagingAccess ImagingAccessNew(Imaging im);
extern void _ImagingAccessDelete(Imaging im, ImagingAccess access); extern void _ImagingAccessDelete(Imaging im, ImagingAccess access);
#define ImagingAccessDelete(im, access) /* nop, for now */ #define ImagingAccessDelete(im, access) /* nop, for now */
/*#define ImagingAccessDelete(im, access) \
((access)->dynamic ? _ImagingAccessDelete((im), (access)), 0 : 0)) */
extern ImagingPalette ImagingPaletteNew(const char *mode); extern ImagingPalette ImagingPaletteNew(const char *mode);
extern ImagingPalette ImagingPaletteNewBrowser(void); extern ImagingPalette ImagingPaletteNewBrowser(void);
@ -191,10 +189,10 @@ extern void ImagingPaletteDelete(ImagingPalette palette);
extern int ImagingPaletteCachePrepare(ImagingPalette palette); extern int ImagingPaletteCachePrepare(ImagingPalette palette);
extern void ImagingPaletteCacheUpdate(ImagingPalette palette, extern void ImagingPaletteCacheUpdate(ImagingPalette palette,
int r, int g, int b); int r, int g, int b);
extern void ImagingPaletteCacheDelete(ImagingPalette palette); extern void ImagingPaletteCacheDelete(ImagingPalette palette);
#define ImagingPaletteCache(p, r, g, b)\ #define ImagingPaletteCache(p, r, g, b)\
p->cache[(r>>2) + (g>>2)*64 + (b>>2)*64*64] p->cache[(r>>2) + (g>>2)*64 + (b>>2)*64*64]
extern Imaging ImagingQuantize(Imaging im, int colours, int mode, int kmeans); extern Imaging ImagingQuantize(Imaging im, int colours, int mode, int kmeans);
@ -264,14 +262,14 @@ extern Imaging ImagingFilter(
extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn); extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn);
extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn); extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn);
extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius, extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius,
int passes); int passes);
extern Imaging ImagingGetBand(Imaging im, int band); extern Imaging ImagingGetBand(Imaging im, int band);
extern Imaging ImagingMerge(const char* mode, Imaging bands[4]); extern Imaging ImagingMerge(const char* mode, Imaging bands[4]);
extern int ImagingSplit(Imaging im, Imaging bands[4]); extern int ImagingSplit(Imaging im, Imaging bands[4]);
extern int ImagingGetBBox(Imaging im, int bbox[4]); extern int ImagingGetBBox(Imaging im, int bbox[4]);
typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem; typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem;
extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors, extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors,
int *colors); int *colors);
extern int ImagingGetExtrema(Imaging im, void *extrema); extern int ImagingGetExtrema(Imaging im, void *extrema);
extern int ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj); extern int ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj);
extern ImagingHistogram ImagingGetHistogram( extern ImagingHistogram ImagingGetHistogram(
@ -291,8 +289,9 @@ extern Imaging ImagingRankFilter(Imaging im, int size, int rank);
extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn);
extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn);
extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn);
extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]);
extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn);
extern Imaging ImagingTransverse(Imaging imOut, Imaging imIn);
extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]);
extern Imaging ImagingTransform( extern Imaging ImagingTransform(
Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1, Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1,
double *a, int filter, int fill); double *a, int filter, int fill);
@ -336,7 +335,7 @@ extern int ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1,
extern int ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1, extern int ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1,
const void* ink, int fill, int op); const void* ink, int fill, int op);
extern int ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, extern int ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1,
const void* ink, int op); const void* ink, int op);
extern int ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, extern int ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
const void* ink, int width, int op); const void* ink, int width, int op);
extern int ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1, extern int ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1,
@ -344,9 +343,9 @@ extern int ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1,
int op); int op);
extern int ImagingDrawPoint(Imaging im, int x, int y, const void* ink, int op); extern int ImagingDrawPoint(Imaging im, int x, int y, const void* ink, int op);
extern int ImagingDrawPolygon(Imaging im, int points, int *xy, extern int ImagingDrawPolygon(Imaging im, int points, int *xy,
const void* ink, int fill, int op); const void* ink, int fill, int op);
extern int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, extern int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1,
const void* ink, int fill, int op); const void* ink, int fill, int op);
/* Level 2 graphics (WORK IN PROGRESS) */ /* Level 2 graphics (WORK IN PROGRESS) */
extern ImagingOutline ImagingOutlineNew(void); extern ImagingOutline ImagingOutlineNew(void);
@ -358,7 +357,7 @@ extern int ImagingDrawOutline(Imaging im, ImagingOutline outline,
extern int ImagingOutlineMove(ImagingOutline outline, float x, float y); extern int ImagingOutlineMove(ImagingOutline outline, float x, float y);
extern int ImagingOutlineLine(ImagingOutline outline, float x, float y); extern int ImagingOutlineLine(ImagingOutline outline, float x, float y);
extern int ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, extern int ImagingOutlineCurve(ImagingOutline outline, float x1, float y1,
float x2, float y2, float x3, float y3); float x2, float y2, float x3, float y3);
extern int ImagingOutlineTransform(ImagingOutline outline, double a[6]); extern int ImagingOutlineTransform(ImagingOutline outline, double a[6]);
extern int ImagingOutlineClose(ImagingOutline outline); extern int ImagingOutlineClose(ImagingOutline outline);
@ -387,30 +386,30 @@ extern UINT32 ImagingCRC32(UINT32 crc, UINT8* buffer, int bytes);
/* Codecs */ /* Codecs */
typedef struct ImagingCodecStateInstance *ImagingCodecState; typedef struct ImagingCodecStateInstance *ImagingCodecState;
typedef int (*ImagingCodec)(Imaging im, ImagingCodecState state, typedef int (*ImagingCodec)(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingBcnDecode(Imaging im, ImagingCodecState state, extern int ImagingBcnDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingBitDecode(Imaging im, ImagingCodecState state, extern int ImagingBitDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingEpsEncode(Imaging im, ImagingCodecState state, extern int ImagingEpsEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingFliDecode(Imaging im, ImagingCodecState state, extern int ImagingFliDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingGifDecode(Imaging im, ImagingCodecState state, extern int ImagingGifDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingGifEncode(Imaging im, ImagingCodecState state, extern int ImagingGifEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingHexDecode(Imaging im, ImagingCodecState state, extern int ImagingHexDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#ifdef HAVE_LIBJPEG #ifdef HAVE_LIBJPEG
extern int ImagingJpegDecode(Imaging im, ImagingCodecState state, extern int ImagingJpegDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingJpegDecodeCleanup(ImagingCodecState state); extern int ImagingJpegDecodeCleanup(ImagingCodecState state);
extern int ImagingJpegUseJCSExtensions(void); extern int ImagingJpegUseJCSExtensions(void);
extern int ImagingJpegEncode(Imaging im, ImagingCodecState state, extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#endif #endif
#ifdef HAVE_OPENJPEG #ifdef HAVE_OPENJPEG
extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state,
@ -421,45 +420,45 @@ extern int ImagingJpeg2KEncode(Imaging im, ImagingCodecState state,
extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state); extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state);
#endif #endif
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state, extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#ifdef HAVE_LIBTIFF #ifdef HAVE_LIBTIFF
extern int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, extern int ImagingLibTiffDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, extern int ImagingLibTiffEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#endif #endif
#ifdef HAVE_LIBMPEG #ifdef HAVE_LIBMPEG
extern int ImagingMpegDecode(Imaging im, ImagingCodecState state, extern int ImagingMpegDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#endif #endif
extern int ImagingMspDecode(Imaging im, ImagingCodecState state, extern int ImagingMspDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingPackbitsDecode(Imaging im, ImagingCodecState state, extern int ImagingPackbitsDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingPcdDecode(Imaging im, ImagingCodecState state, extern int ImagingPcdDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingPcxDecode(Imaging im, ImagingCodecState state, extern int ImagingPcxDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingPcxEncode(Imaging im, ImagingCodecState state, extern int ImagingPcxEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingRawDecode(Imaging im, ImagingCodecState state, extern int ImagingRawDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingRawEncode(Imaging im, ImagingCodecState state, extern int ImagingRawEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state, extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state, extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingXbmDecode(Imaging im, ImagingCodecState state, extern int ImagingXbmDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingXbmEncode(Imaging im, ImagingCodecState state, extern int ImagingXbmEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
extern int ImagingZipDecode(Imaging im, ImagingCodecState state, extern int ImagingZipDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingZipDecodeCleanup(ImagingCodecState state); extern int ImagingZipDecodeCleanup(ImagingCodecState state);
extern int ImagingZipEncode(Imaging im, ImagingCodecState state, extern int ImagingZipEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingZipEncodeCleanup(ImagingCodecState state); extern int ImagingZipEncodeCleanup(ImagingCodecState state);
#endif #endif
@ -503,12 +502,12 @@ extern Py_ssize_t _imaging_tell_pyFd(PyObject *fd);
/* Errcodes */ /* Errcodes */
#define IMAGING_CODEC_END 1 #define IMAGING_CODEC_END 1
#define IMAGING_CODEC_OVERRUN -1 #define IMAGING_CODEC_OVERRUN -1
#define IMAGING_CODEC_BROKEN -2 #define IMAGING_CODEC_BROKEN -2
#define IMAGING_CODEC_UNKNOWN -3 #define IMAGING_CODEC_UNKNOWN -3
#define IMAGING_CODEC_CONFIG -8 #define IMAGING_CODEC_CONFIG -8
#define IMAGING_CODEC_MEMORY -9 #define IMAGING_CODEC_MEMORY -9

View File

@ -28,3 +28,18 @@
#define PREBLEND(mask, in1, in2, tmp1)\ #define PREBLEND(mask, in1, in2, tmp1)\
(MULDIV255(in1, (255 - mask), tmp1) + in2) (MULDIV255(in1, (255 - mask), tmp1) + in2)
/* This is to work around a bug in GCC prior 4.9 in 64 bit mode.
GCC generates code with partial dependency which is 3 times slower.
See: http://stackoverflow.com/a/26588074/253146 */
#if defined(__x86_64__) && defined(__SSE__) && ! defined(__NO_INLINE__) && \
! defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
static float __attribute__((always_inline)) inline _i2f(int v) {
float x;
__asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=X"(x) : "r"(v) );
return x;
}
#else
static float inline _i2f(int v) { return (float) v; }
#endif

View File

@ -26,11 +26,11 @@ ImagingModeFilter(Imaging im, int size)
int histogram[256]; int histogram[256];
if (!im || im->bands != 1 || im->type != IMAGING_TYPE_UINT8) if (!im || im->bands != 1 || im->type != IMAGING_TYPE_UINT8)
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
imOut = ImagingNew(im->mode, im->xsize, im->ysize); imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
if (!imOut) if (!imOut)
return NULL; return NULL;
size = size / 2; size = size / 2;

View File

@ -1642,11 +1642,11 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
if (result > 0) { if (result > 0) {
imOut = ImagingNew("P", im->xsize, im->ysize); imOut = ImagingNewDirty("P", im->xsize, im->ysize);
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
for (i = y = 0; y < im->ysize; y++) for (i = y = 0; y < im->ysize; y++)
for (x=0; x < im->xsize; x++) for (x = 0; x < im->xsize; x++)
imOut->image8[y][x] = (unsigned char) newData[i++]; imOut->image8[y][x] = (unsigned char) newData[i++];
free(newData); free(newData);

View File

@ -34,9 +34,9 @@ libs = {
'dir': 'tiff-4.0.8', 'dir': 'tiff-4.0.8',
}, },
'freetype': { 'freetype': {
'url': 'https://download.savannah.gnu.org/releases/freetype/freetype-2.8.tar.gz', 'url': 'https://download.savannah.gnu.org/releases/freetype/freetype-2.8.1.tar.gz',
'filename': PILLOW_DEPENDS_DIR + 'freetype-2.8.tar.gz', 'filename': PILLOW_DEPENDS_DIR + 'freetype-2.8.1.tar.gz',
'dir': 'freetype-2.8', 'dir': 'freetype-2.8.1',
}, },
'lcms': { 'lcms': {
'url': SF_MIRROR+'/project/lcms/lcms/2.7/lcms2-2.7.zip', 'url': SF_MIRROR+'/project/lcms/lcms/2.7/lcms2-2.7.zip',