mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-14 03:21:44 +03:00
Merge branch 'master' into jpeg-loading-without-convertion
This commit is contained in:
commit
d8af3fc23a
|
@ -26,6 +26,8 @@ matrix:
|
||||||
- env: DOCKER="debian-stretch-x86"
|
- env: DOCKER="debian-stretch-x86"
|
||||||
- env: DOCKER="centos-6-amd64"
|
- env: DOCKER="centos-6-amd64"
|
||||||
- env: DOCKER="amazon-amd64"
|
- env: DOCKER="amazon-amd64"
|
||||||
|
- env: DOCKER="fedora-24-amd64"
|
||||||
|
- env: DOCKER="fedora-26-amd64"
|
||||||
|
|
||||||
dist: trusty
|
dist: trusty
|
||||||
|
|
||||||
|
|
72
CHANGES.rst
72
CHANGES.rst
|
@ -4,6 +4,78 @@ Changelog (Pillow)
|
||||||
4.3.0 (unreleased)
|
4.3.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Region of interest (box) for resampling #2254
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- Basic support for Termux (android) in setup.py #2684
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- Bug: Fix Image.fromarray for numpy.bool type. #2683
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- CI: Add Fedora 24 and 26 to Docker tests
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- JPEG: Fix ZeroDivisionError when EXIF contains invalid DPI (0/0). #2667
|
||||||
|
[vytisb]
|
||||||
|
|
||||||
|
- Depends: Updated openjpeg to 2.2.0 #2669
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Depends: Updated Tk Tcl to 8.6.7 #2668
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Depends: Updated libimagequant to 2.10.2 #2660
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Test: Added test for ImImagePlugin tell() #2675
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Test: Additional tests for SGIImagePlugin #2659
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- New Image.getchannel method #2661
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- Remove unused im.copy2 and core.copy methods #2657
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- Fast Image.merge() #2677
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- Fast Image.split() #2676
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- Fast image allocation #2655
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- Storage cleanup #2654
|
||||||
|
[homm]
|
||||||
|
|
||||||
|
- FLI: Use frame count from FLI header #2674
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Test: Test animated FLI file #2650
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Bug: Fixed uninitialized memory in bc5 decoding #2648
|
||||||
|
[ifeherva]
|
||||||
|
|
||||||
|
- Moved SgiImagePlugin save error to before the start of write operations #2646
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Move createfontdatachunk.py so isn't installed globally #2645
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Bug: Fix unexpected keyword argument 'align' #2641
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Add newlines to error message for clarity #2640
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Docs: Updated redirected URL #2637
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
- Bug: Fix JPEG DPI when EXIF is invalid #2632
|
- Bug: Fix JPEG DPI when EXIF is invalid #2632
|
||||||
[wiredfool]
|
[wiredfool]
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,9 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
s[20:22] == b"\x00\x00"): # reserved
|
s[20:22] == b"\x00\x00"): # reserved
|
||||||
raise SyntaxError("not an FLI/FLC file")
|
raise SyntaxError("not an FLI/FLC file")
|
||||||
|
|
||||||
|
# frames
|
||||||
|
self.__framecount = i16(s[6:8])
|
||||||
|
|
||||||
# image characteristics
|
# image characteristics
|
||||||
self.mode = "P"
|
self.mode = "P"
|
||||||
self.size = i16(s[8:10]), i16(s[10:12])
|
self.size = i16(s[8:10]), i16(s[10:12])
|
||||||
|
@ -56,7 +59,7 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
# animation speed
|
# animation speed
|
||||||
duration = i32(s[16:20])
|
duration = i32(s[16:20])
|
||||||
if magic == 0xAF11:
|
if magic == 0xAF11:
|
||||||
duration = (duration * 1000) / 70
|
duration = (duration * 1000) // 70
|
||||||
self.info["duration"] = duration
|
self.info["duration"] = duration
|
||||||
|
|
||||||
# look for palette
|
# look for palette
|
||||||
|
@ -86,8 +89,6 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
self.__frame = -1
|
self.__frame = -1
|
||||||
self.__fp = self.fp
|
self.__fp = self.fp
|
||||||
self.__rewind = self.fp.tell()
|
self.__rewind = self.fp.tell()
|
||||||
self._n_frames = None
|
|
||||||
self._is_animated = None
|
|
||||||
self.seek(0)
|
self.seek(0)
|
||||||
|
|
||||||
def _palette(self, palette, shift):
|
def _palette(self, palette, shift):
|
||||||
|
@ -110,44 +111,23 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
if self._n_frames is None:
|
return self.__framecount
|
||||||
current = self.tell()
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
self.seek(self.tell() + 1)
|
|
||||||
except EOFError:
|
|
||||||
self._n_frames = self.tell() + 1
|
|
||||||
self.seek(current)
|
|
||||||
return self._n_frames
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_animated(self):
|
def is_animated(self):
|
||||||
if self._is_animated is None:
|
return self.__framecount > 1
|
||||||
current = self.tell()
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.seek(1)
|
|
||||||
self._is_animated = True
|
|
||||||
except EOFError:
|
|
||||||
self._is_animated = False
|
|
||||||
|
|
||||||
self.seek(current)
|
|
||||||
return self._is_animated
|
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
if frame == self.__frame:
|
if frame == self.__frame:
|
||||||
return
|
return
|
||||||
if frame < self.__frame:
|
if frame < self.__frame:
|
||||||
self._seek(0)
|
self._seek(0)
|
||||||
|
if frame >= self.__framecount:
|
||||||
last_frame = self.__frame
|
|
||||||
for f in range(self.__frame + 1, frame + 1):
|
|
||||||
try:
|
|
||||||
self._seek(f)
|
|
||||||
except EOFError:
|
|
||||||
self.seek(last_frame)
|
|
||||||
raise EOFError("no more images in FLI file")
|
raise EOFError("no more images in FLI file")
|
||||||
|
|
||||||
|
for f in range(self.__frame + 1, frame + 1):
|
||||||
|
self._seek(f)
|
||||||
|
|
||||||
def _seek(self, frame):
|
def _seek(self, frame):
|
||||||
if frame == 0:
|
if frame == 0:
|
||||||
self.__frame = -1
|
self.__frame = -1
|
||||||
|
@ -176,6 +156,7 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
def tell(self):
|
def tell(self):
|
||||||
return self.__frame
|
return self.__frame
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# registry
|
# registry
|
||||||
|
|
||||||
|
|
68
PIL/Image.py
68
PIL/Image.py
|
@ -56,8 +56,9 @@ try:
|
||||||
from . import _imaging as core
|
from . import _imaging as core
|
||||||
if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None):
|
if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None):
|
||||||
raise ImportError("The _imaging extension was built for another "
|
raise ImportError("The _imaging extension was built for another "
|
||||||
"version of Pillow or PIL: Core Version: %s"
|
"version of Pillow or PIL:\n"
|
||||||
"Pillow Version: %s" %
|
"Core version: %s\n"
|
||||||
|
"Pillow version: %s" %
|
||||||
(getattr(core, 'PILLOW_VERSION', None),
|
(getattr(core, 'PILLOW_VERSION', None),
|
||||||
PILLOW_VERSION))
|
PILLOW_VERSION))
|
||||||
|
|
||||||
|
@ -1673,7 +1674,7 @@ class Image(object):
|
||||||
|
|
||||||
return m_im
|
return m_im
|
||||||
|
|
||||||
def resize(self, size, resample=NEAREST):
|
def resize(self, size, resample=NEAREST, box=None):
|
||||||
"""
|
"""
|
||||||
Returns a resized copy of this image.
|
Returns a resized copy of this image.
|
||||||
|
|
||||||
|
@ -1686,6 +1687,10 @@ class Image(object):
|
||||||
If omitted, or if the image has mode "1" or "P", it is
|
If omitted, or if the image has mode "1" or "P", it is
|
||||||
set :py:attr:`PIL.Image.NEAREST`.
|
set :py:attr:`PIL.Image.NEAREST`.
|
||||||
See: :ref:`concept-filters`.
|
See: :ref:`concept-filters`.
|
||||||
|
:param box: An optional 4-tuple of floats giving the region
|
||||||
|
of the source image which should be scaled.
|
||||||
|
The values should be within (0, 0, width, height) rectangle.
|
||||||
|
If omitted or None, the entire source is used.
|
||||||
:returns: An :py:class:`~PIL.Image.Image` object.
|
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1694,22 +1699,28 @@ class Image(object):
|
||||||
):
|
):
|
||||||
raise ValueError("unknown resampling filter")
|
raise ValueError("unknown resampling filter")
|
||||||
|
|
||||||
self.load()
|
|
||||||
|
|
||||||
size = tuple(size)
|
size = tuple(size)
|
||||||
if self.size == size:
|
|
||||||
|
if box is None:
|
||||||
|
box = (0, 0) + self.size
|
||||||
|
else:
|
||||||
|
box = tuple(box)
|
||||||
|
|
||||||
|
if self.size == size and box == (0, 0) + self.size:
|
||||||
return self.copy()
|
return self.copy()
|
||||||
|
|
||||||
if self.mode in ("1", "P"):
|
if self.mode in ("1", "P"):
|
||||||
resample = NEAREST
|
resample = NEAREST
|
||||||
|
|
||||||
if self.mode == 'LA':
|
if self.mode == 'LA':
|
||||||
return self.convert('La').resize(size, resample).convert('LA')
|
return self.convert('La').resize(size, resample, box).convert('LA')
|
||||||
|
|
||||||
if self.mode == 'RGBA':
|
if self.mode == 'RGBA':
|
||||||
return self.convert('RGBa').resize(size, resample).convert('RGBA')
|
return self.convert('RGBa').resize(size, resample, box).convert('RGBA')
|
||||||
|
|
||||||
return self._new(self.im.resize(size, resample))
|
self.load()
|
||||||
|
|
||||||
|
return self._new(self.im.resize(size, resample, box))
|
||||||
|
|
||||||
def rotate(self, angle, resample=NEAREST, expand=0, center=None,
|
def rotate(self, angle, resample=NEAREST, expand=0, center=None,
|
||||||
translate=None):
|
translate=None):
|
||||||
|
@ -1947,6 +1958,9 @@ class Image(object):
|
||||||
containing a copy of one of the original bands (red, green,
|
containing a copy of one of the original bands (red, green,
|
||||||
blue).
|
blue).
|
||||||
|
|
||||||
|
If you need only one band, :py:meth:`~PIL.Image.Image.getchannel`
|
||||||
|
method can be more convenient and faster.
|
||||||
|
|
||||||
:returns: A tuple containing bands.
|
:returns: A tuple containing bands.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1954,11 +1968,31 @@ class Image(object):
|
||||||
if self.im.bands == 1:
|
if self.im.bands == 1:
|
||||||
ims = [self.copy()]
|
ims = [self.copy()]
|
||||||
else:
|
else:
|
||||||
ims = []
|
ims = map(self._new, self.im.split())
|
||||||
for i in range(self.im.bands):
|
|
||||||
ims.append(self._new(self.im.getband(i)))
|
|
||||||
return tuple(ims)
|
return tuple(ims)
|
||||||
|
|
||||||
|
def getchannel(self, channel):
|
||||||
|
"""
|
||||||
|
Returns an image containing a single channel of the source image.
|
||||||
|
|
||||||
|
:param channel: What channel to return. Could be index
|
||||||
|
(0 for "R" channel of "RGB") or channel name
|
||||||
|
("A" for alpha channel of "RGBA").
|
||||||
|
:returns: An image in "L" mode.
|
||||||
|
|
||||||
|
.. versionadded:: 4.3.0
|
||||||
|
"""
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
if isStringType(channel):
|
||||||
|
try:
|
||||||
|
channel = self.getbands().index(channel)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(
|
||||||
|
'The image has no channel "{}"'.format(channel))
|
||||||
|
|
||||||
|
return self._new(self.im.getband(channel))
|
||||||
|
|
||||||
def tell(self):
|
def tell(self):
|
||||||
"""
|
"""
|
||||||
Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
|
Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
|
||||||
|
@ -2399,7 +2433,7 @@ def fromqpixmap(im):
|
||||||
_fromarray_typemap = {
|
_fromarray_typemap = {
|
||||||
# (shape, typestr) => mode, rawmode
|
# (shape, typestr) => mode, rawmode
|
||||||
# first two members of shape are set to one
|
# first two members of shape are set to one
|
||||||
# ((1, 1), "|b1"): ("1", "1"), # broken
|
((1, 1), "|b1"): ("1", "1;8"),
|
||||||
((1, 1), "|u1"): ("L", "L"),
|
((1, 1), "|u1"): ("L", "L"),
|
||||||
((1, 1), "|i1"): ("I", "I;8"),
|
((1, 1), "|i1"): ("I", "I;8"),
|
||||||
((1, 1), "<u2"): ("I", "I;16"),
|
((1, 1), "<u2"): ("I", "I;16"),
|
||||||
|
@ -2612,11 +2646,9 @@ def merge(mode, bands):
|
||||||
raise ValueError("mode mismatch")
|
raise ValueError("mode mismatch")
|
||||||
if im.size != bands[0].size:
|
if im.size != bands[0].size:
|
||||||
raise ValueError("size mismatch")
|
raise ValueError("size mismatch")
|
||||||
im = core.new(mode, bands[0].size)
|
for band in bands:
|
||||||
for i in range(getmodebands(mode)):
|
band.load()
|
||||||
bands[i].load()
|
return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
|
||||||
im.putband(bands[i].im, i)
|
|
||||||
return bands[0]._new(im)
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Contrast(_Enhance):
|
||||||
self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
|
self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
|
||||||
|
|
||||||
if 'A' in image.getbands():
|
if 'A' in image.getbands():
|
||||||
self.degenerate.putalpha(image.split()[-1])
|
self.degenerate.putalpha(image.getchannel('A'))
|
||||||
|
|
||||||
|
|
||||||
class Brightness(_Enhance):
|
class Brightness(_Enhance):
|
||||||
|
@ -82,7 +82,7 @@ class Brightness(_Enhance):
|
||||||
self.degenerate = Image.new(image.mode, image.size, 0)
|
self.degenerate = Image.new(image.mode, image.size, 0)
|
||||||
|
|
||||||
if 'A' in image.getbands():
|
if 'A' in image.getbands():
|
||||||
self.degenerate.putalpha(image.split()[-1])
|
self.degenerate.putalpha(image.getchannel('A'))
|
||||||
|
|
||||||
|
|
||||||
class Sharpness(_Enhance):
|
class Sharpness(_Enhance):
|
||||||
|
@ -97,4 +97,4 @@ class Sharpness(_Enhance):
|
||||||
self.degenerate = image.filter(ImageFilter.SMOOTH)
|
self.degenerate = image.filter(ImageFilter.SMOOTH)
|
||||||
|
|
||||||
if 'A' in image.getbands():
|
if 'A' in image.getbands():
|
||||||
self.degenerate.putalpha(image.split()[-1])
|
self.degenerate.putalpha(image.getchannel('A'))
|
||||||
|
|
|
@ -36,6 +36,7 @@ class _imagingft_not_installed(object):
|
||||||
def __getattr__(self, id):
|
def __getattr__(self, id):
|
||||||
raise ImportError("The _imagingft C module is not installed")
|
raise ImportError("The _imagingft C module is not installed")
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from . import _imagingft as core
|
from . import _imagingft as core
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -113,7 +114,6 @@ class ImageFont(object):
|
||||||
return self.font.getmask(text, mode)
|
return self.font.getmask(text, mode)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Wrapper for FreeType fonts. Application code should use the
|
# Wrapper for FreeType fonts. Application code should use the
|
||||||
# <b>truetype</b> factory function to create font objects.
|
# <b>truetype</b> factory function to create font objects.
|
||||||
|
@ -162,7 +162,7 @@ class FreeTypeFont(object):
|
||||||
def getmask(self, text, mode="", direction=None, features=None):
|
def getmask(self, text, mode="", direction=None, features=None):
|
||||||
return self.getmask2(text, mode, direction=direction, features=features)[0]
|
return self.getmask2(text, mode, direction=direction, features=features)[0]
|
||||||
|
|
||||||
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=None):
|
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=None, *args, **kwargs):
|
||||||
size, offset = self.font.getsize(text, direction, features)
|
size, offset = self.font.getsize(text, direction, features)
|
||||||
im = fill("L", size, 0)
|
im = fill("L", size, 0)
|
||||||
self.font.render(text, im.id, mode == "1", direction, features)
|
self.font.render(text, im.id, mode == "1", direction, features)
|
||||||
|
|
|
@ -131,9 +131,10 @@ def APP(self, marker):
|
||||||
# 1 dpcm = 2.54 dpi
|
# 1 dpcm = 2.54 dpi
|
||||||
dpi *= 2.54
|
dpi *= 2.54
|
||||||
self.info["dpi"] = dpi, dpi
|
self.info["dpi"] = dpi, dpi
|
||||||
except (KeyError, SyntaxError):
|
except (KeyError, SyntaxError, ZeroDivisionError):
|
||||||
# SyntaxError for invalid/unreadable exif
|
# SyntaxError for invalid/unreadable exif
|
||||||
# KeyError for dpi not included
|
# KeyError for dpi not included
|
||||||
|
# ZeroDivisionError for invalid dpi rational value
|
||||||
self.info["dpi"] = 72, 72
|
self.info["dpi"] = 72, 72
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,7 @@ class _PyAccess32_3(PyAccess):
|
||||||
pixel.r = min(color[0], 255)
|
pixel.r = min(color[0], 255)
|
||||||
pixel.g = min(color[1], 255)
|
pixel.g = min(color[1], 255)
|
||||||
pixel.b = min(color[2], 255)
|
pixel.b = min(color[2], 255)
|
||||||
|
pixel.a = 255
|
||||||
|
|
||||||
|
|
||||||
class _PyAccess32_4(PyAccess):
|
class _PyAccess32_4(PyAccess):
|
||||||
|
|
|
@ -104,6 +104,11 @@ def _save(im, fp, filename):
|
||||||
z = len(im.mode)
|
z = len(im.mode)
|
||||||
if dim == 1 or dim == 2:
|
if dim == 1 or dim == 2:
|
||||||
z = 1
|
z = 1
|
||||||
|
# assert we've got the right number of bands.
|
||||||
|
if len(im.getbands()) != z:
|
||||||
|
raise ValueError("incorrect number of bands in SGI write: %s vs %s" %
|
||||||
|
(z, len(im.getbands())))
|
||||||
|
|
||||||
# Minimum Byte value
|
# Minimum Byte value
|
||||||
pinmin = 0
|
pinmin = 0
|
||||||
# Maximum Byte value (255 = 8bits per pixel)
|
# Maximum Byte value (255 = 8bits per pixel)
|
||||||
|
@ -131,11 +136,6 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
fp.write(struct.pack('404s', b'')) # dummy
|
fp.write(struct.pack('404s', b'')) # dummy
|
||||||
|
|
||||||
# assert we've got the right number of bands.
|
|
||||||
if len(im.getbands()) != z:
|
|
||||||
raise ValueError("incorrect number of bands in SGI write: %s vs %s" %
|
|
||||||
(z, len(im.getbands())))
|
|
||||||
|
|
||||||
for channel in im.split():
|
for channel in im.split():
|
||||||
fp.write(channel.tobytes())
|
fp.write(channel.tobytes())
|
||||||
|
|
||||||
|
|
BIN
Tests/images/a.fli
Normal file
BIN
Tests/images/a.fli
Normal file
Binary file not shown.
BIN
Tests/images/exif-dpi-zerodivision.jpg
Normal file
BIN
Tests/images/exif-dpi-zerodivision.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
Tests/images/hopper_emboss.bmp
Normal file
BIN
Tests/images/hopper_emboss.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
Tests/images/hopper_emboss_more.bmp
Normal file
BIN
Tests/images/hopper_emboss_more.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
|
@ -4,17 +4,38 @@ from PIL import Image, FliImagePlugin
|
||||||
|
|
||||||
# created as an export of a palette image from Gimp2.6
|
# created as an export of a palette image from Gimp2.6
|
||||||
# save as...-> hopper.fli, default options.
|
# save as...-> hopper.fli, default options.
|
||||||
test_file = "Tests/images/hopper.fli"
|
static_test_file = "Tests/images/hopper.fli"
|
||||||
|
|
||||||
|
# From https://samples.libav.org/fli-flc/
|
||||||
|
animated_test_file = "Tests/images/a.fli"
|
||||||
|
|
||||||
|
|
||||||
class TestFileFli(PillowTestCase):
|
class TestFileFli(PillowTestCase):
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(static_test_file)
|
||||||
im.load()
|
im.load()
|
||||||
self.assertEqual(im.mode, "P")
|
self.assertEqual(im.mode, "P")
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "FLI")
|
self.assertEqual(im.format, "FLI")
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
|
im = Image.open(animated_test_file)
|
||||||
|
self.assertEqual(im.mode, "P")
|
||||||
|
self.assertEqual(im.size, (320, 200))
|
||||||
|
self.assertEqual(im.format, "FLI")
|
||||||
|
self.assertEqual(im.info["duration"], 71)
|
||||||
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
|
def test_tell(self):
|
||||||
|
# Arrange
|
||||||
|
im = Image.open(static_test_file)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
frame = im.tell()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(frame, 0)
|
||||||
|
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
@ -23,12 +44,16 @@ class TestFileFli(PillowTestCase):
|
||||||
lambda: FliImagePlugin.FliImageFile(invalid_file))
|
lambda: FliImagePlugin.FliImageFile(invalid_file))
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(static_test_file)
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
self.assertFalse(im.is_animated)
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
|
im = Image.open(animated_test_file)
|
||||||
|
self.assertEqual(im.n_frames, 384)
|
||||||
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
def test_eoferror(self):
|
def test_eoferror(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(animated_test_file)
|
||||||
|
|
||||||
n_frames = im.n_frames
|
n_frames = im.n_frames
|
||||||
while True:
|
while True:
|
||||||
|
@ -39,6 +64,33 @@ class TestFileFli(PillowTestCase):
|
||||||
except EOFError:
|
except EOFError:
|
||||||
self.assertLess(im.tell(), n_frames)
|
self.assertLess(im.tell(), n_frames)
|
||||||
|
|
||||||
|
def test_seek_outside(self):
|
||||||
|
# Test negative seek
|
||||||
|
im = Image.open(static_test_file)
|
||||||
|
im.seek(-1)
|
||||||
|
self.assertEqual(im.tell(), 0)
|
||||||
|
|
||||||
|
# Test seek past end of file
|
||||||
|
self.assertRaises(EOFError, lambda: im.seek(2))
|
||||||
|
|
||||||
|
def test_seek_tell(self):
|
||||||
|
im = Image.open(animated_test_file)
|
||||||
|
|
||||||
|
layer_number = im.tell()
|
||||||
|
self.assertEqual(layer_number, 0)
|
||||||
|
|
||||||
|
im.seek(0)
|
||||||
|
layer_number = im.tell()
|
||||||
|
self.assertEqual(layer_number, 0)
|
||||||
|
|
||||||
|
im.seek(1)
|
||||||
|
layer_number = im.tell()
|
||||||
|
self.assertEqual(layer_number, 1)
|
||||||
|
|
||||||
|
im.seek(2)
|
||||||
|
layer_number = im.tell()
|
||||||
|
self.assertEqual(layer_number, 2)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -15,6 +15,16 @@ class TestFileIm(PillowTestCase):
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "IM")
|
self.assertEqual(im.format, "IM")
|
||||||
|
|
||||||
|
def test_tell(self):
|
||||||
|
# Arrange
|
||||||
|
im = Image.open(TEST_IM)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
frame = im.tell()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(frame, 0)
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(TEST_IM)
|
im = Image.open(TEST_IM)
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
|
|
@ -535,6 +535,16 @@ class TestFileJpeg(PillowTestCase):
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertEqual(im.info.get("dpi"), (508, 508))
|
self.assertEqual(im.info.get("dpi"), (508, 508))
|
||||||
|
|
||||||
|
def test_dpi_exif_zero_division(self):
|
||||||
|
# Arrange
|
||||||
|
# This is photoshop-200dpi.jpg with EXIF resolution set to 0/0:
|
||||||
|
# exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg
|
||||||
|
im = Image.open("Tests/images/exif-dpi-zerodivision.jpg")
|
||||||
|
|
||||||
|
# Act / Assert
|
||||||
|
# This should return the default, and not raise a ZeroDivisionError
|
||||||
|
self.assertEqual(im.info.get("dpi"), (72, 72))
|
||||||
|
|
||||||
def test_no_dpi_in_exif(self):
|
def test_no_dpi_in_exif(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
|
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
|
||||||
|
|
|
@ -200,7 +200,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (162, 150))
|
self.assert_image(im, "RGBA", (162, 150))
|
||||||
|
|
||||||
# image has 124 unique alpha values
|
# image has 124 unique alpha values
|
||||||
self.assertEqual(len(im.split()[3].getcolors()), 124)
|
self.assertEqual(len(im.getchannel('A').getcolors()), 124)
|
||||||
|
|
||||||
def test_load_transparent_rgb(self):
|
def test_load_transparent_rgb(self):
|
||||||
test_file = "Tests/images/rgb_trns.png"
|
test_file = "Tests/images/rgb_trns.png"
|
||||||
|
@ -212,7 +212,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (64, 64))
|
self.assert_image(im, "RGBA", (64, 64))
|
||||||
|
|
||||||
# image has 876 transparent pixels
|
# image has 876 transparent pixels
|
||||||
self.assertEqual(im.split()[3].getcolors()[0][0], 876)
|
self.assertEqual(im.getchannel('A').getcolors()[0][0], 876)
|
||||||
|
|
||||||
def test_save_p_transparent_palette(self):
|
def test_save_p_transparent_palette(self):
|
||||||
in_file = "Tests/images/pil123p.png"
|
in_file = "Tests/images/pil123p.png"
|
||||||
|
@ -234,7 +234,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (162, 150))
|
self.assert_image(im, "RGBA", (162, 150))
|
||||||
|
|
||||||
# image has 124 unique alpha values
|
# image has 124 unique alpha values
|
||||||
self.assertEqual(len(im.split()[3].getcolors()), 124)
|
self.assertEqual(len(im.getchannel('A').getcolors()), 124)
|
||||||
|
|
||||||
def test_save_p_single_transparency(self):
|
def test_save_p_single_transparency(self):
|
||||||
in_file = "Tests/images/p_trns_single.png"
|
in_file = "Tests/images/p_trns_single.png"
|
||||||
|
@ -258,7 +258,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertEqual(im.getpixel((31, 31)), (0, 255, 52, 0))
|
self.assertEqual(im.getpixel((31, 31)), (0, 255, 52, 0))
|
||||||
|
|
||||||
# image has 876 transparent pixels
|
# image has 876 transparent pixels
|
||||||
self.assertEqual(im.split()[3].getcolors()[0][0], 876)
|
self.assertEqual(im.getchannel('A').getcolors()[0][0], 876)
|
||||||
|
|
||||||
def test_save_p_transparent_black(self):
|
def test_save_p_transparent_black(self):
|
||||||
# check if solid black image with full transparency
|
# check if solid black image with full transparency
|
||||||
|
@ -287,7 +287,7 @@ class TestFilePng(PillowTestCase):
|
||||||
|
|
||||||
# There are 559 transparent pixels.
|
# There are 559 transparent pixels.
|
||||||
im = im.convert('RGBA')
|
im = im.convert('RGBA')
|
||||||
self.assertEqual(im.split()[3].getcolors()[0][0], 559)
|
self.assertEqual(im.getchannel('A').getcolors()[0][0], 559)
|
||||||
|
|
||||||
def test_save_rgb_single_transparency(self):
|
def test_save_rgb_single_transparency(self):
|
||||||
in_file = "Tests/images/caption_6_33_22.png"
|
in_file = "Tests/images/caption_6_33_22.png"
|
||||||
|
|
|
@ -55,6 +55,22 @@ class TestFileSgi(PillowTestCase):
|
||||||
for mode in ('L', 'RGB', 'RGBA'):
|
for mode in ('L', 'RGB', 'RGBA'):
|
||||||
roundtrip(hopper(mode))
|
roundtrip(hopper(mode))
|
||||||
|
|
||||||
|
# Test 1 dimension for an L mode image
|
||||||
|
roundtrip(Image.new('L', (10, 1)))
|
||||||
|
|
||||||
|
def test_unsupported_mode(self):
|
||||||
|
im = hopper('LA')
|
||||||
|
out = self.tempfile('temp.sgi')
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, lambda: im.save(out, format='sgi'))
|
||||||
|
|
||||||
|
def test_incorrect_number_of_bands(self):
|
||||||
|
im = hopper('YCbCr')
|
||||||
|
im.mode = 'RGB'
|
||||||
|
out = self.tempfile('temp.sgi')
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, lambda: im.save(out, format='sgi'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -103,11 +103,11 @@ class TestFormatHSV(PillowTestCase):
|
||||||
# im.split()[0].show()
|
# im.split()[0].show()
|
||||||
# comparable.split()[0].show()
|
# comparable.split()[0].show()
|
||||||
|
|
||||||
self.assert_image_similar(im.split()[0], comparable.split()[0],
|
self.assert_image_similar(im.getchannel(0), comparable.getchannel(0),
|
||||||
1, "Hue conversion is wrong")
|
1, "Hue conversion is wrong")
|
||||||
self.assert_image_similar(im.split()[1], comparable.split()[1],
|
self.assert_image_similar(im.getchannel(1), comparable.getchannel(1),
|
||||||
1, "Saturation conversion is wrong")
|
1, "Saturation conversion is wrong")
|
||||||
self.assert_image_similar(im.split()[2], comparable.split()[2],
|
self.assert_image_similar(im.getchannel(2), comparable.getchannel(2),
|
||||||
1, "Value conversion is wrong")
|
1, "Value conversion is wrong")
|
||||||
|
|
||||||
# print(im.getpixel((192, 64)))
|
# print(im.getpixel((192, 64)))
|
||||||
|
@ -120,11 +120,11 @@ class TestFormatHSV(PillowTestCase):
|
||||||
# print(im.getpixel((192, 64)))
|
# print(im.getpixel((192, 64)))
|
||||||
# print(comparable.getpixel((192, 64)))
|
# print(comparable.getpixel((192, 64)))
|
||||||
|
|
||||||
self.assert_image_similar(im.split()[0], comparable.split()[0],
|
self.assert_image_similar(im.getchannel(0), comparable.getchannel(0),
|
||||||
3, "R conversion is wrong")
|
3, "R conversion is wrong")
|
||||||
self.assert_image_similar(im.split()[1], comparable.split()[1],
|
self.assert_image_similar(im.getchannel(1), comparable.getchannel(1),
|
||||||
3, "G conversion is wrong")
|
3, "G conversion is wrong")
|
||||||
self.assert_image_similar(im.split()[2], comparable.split()[2],
|
self.assert_image_similar(im.getchannel(2), comparable.getchannel(2),
|
||||||
3, "B conversion is wrong")
|
3, "B conversion is wrong")
|
||||||
|
|
||||||
def test_convert(self):
|
def test_convert(self):
|
||||||
|
@ -137,11 +137,11 @@ class TestFormatHSV(PillowTestCase):
|
||||||
# print(im.split()[0].histogram())
|
# print(im.split()[0].histogram())
|
||||||
# print(comparable.split()[0].histogram())
|
# print(comparable.split()[0].histogram())
|
||||||
|
|
||||||
self.assert_image_similar(im.split()[0], comparable.split()[0],
|
self.assert_image_similar(im.getchannel(0), comparable.getchannel(0),
|
||||||
1, "Hue conversion is wrong")
|
1, "Hue conversion is wrong")
|
||||||
self.assert_image_similar(im.split()[1], comparable.split()[1],
|
self.assert_image_similar(im.getchannel(1), comparable.getchannel(1),
|
||||||
1, "Saturation conversion is wrong")
|
1, "Saturation conversion is wrong")
|
||||||
self.assert_image_similar(im.split()[2], comparable.split()[2],
|
self.assert_image_similar(im.getchannel(2), comparable.getchannel(2),
|
||||||
1, "Value conversion is wrong")
|
1, "Value conversion is wrong")
|
||||||
|
|
||||||
def test_hsv_to_rgb(self):
|
def test_hsv_to_rgb(self):
|
||||||
|
@ -155,11 +155,14 @@ class TestFormatHSV(PillowTestCase):
|
||||||
# print([ord(x) for x in target.split()[1].tobytes()[:80]])
|
# print([ord(x) for x in target.split()[1].tobytes()[:80]])
|
||||||
# print([ord(x) for x in converted.split()[1].tobytes()[:80]])
|
# print([ord(x) for x in converted.split()[1].tobytes()[:80]])
|
||||||
|
|
||||||
self.assert_image_similar(converted.split()[0], comparable.split()[0],
|
self.assert_image_similar(converted.getchannel(0),
|
||||||
|
comparable.getchannel(0),
|
||||||
3, "R conversion is wrong")
|
3, "R conversion is wrong")
|
||||||
self.assert_image_similar(converted.split()[1], comparable.split()[1],
|
self.assert_image_similar(converted.getchannel(1),
|
||||||
|
comparable.getchannel(1),
|
||||||
3, "G conversion is wrong")
|
3, "G conversion is wrong")
|
||||||
self.assert_image_similar(converted.split()[2], comparable.split()[2],
|
self.assert_image_similar(converted.getchannel(2),
|
||||||
|
comparable.getchannel(2),
|
||||||
3, "B conversion is wrong")
|
3, "B conversion is wrong")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,25 @@ import sys
|
||||||
|
|
||||||
class TestImage(PillowTestCase):
|
class TestImage(PillowTestCase):
|
||||||
|
|
||||||
|
def test_image_modes_success(self):
|
||||||
|
for mode in [
|
||||||
|
'1', 'P', 'PA',
|
||||||
|
'L', 'LA', 'La',
|
||||||
|
'F', 'I', 'I;16', 'I;16L', 'I;16B', 'I;16N',
|
||||||
|
'RGB', 'RGBX', 'RGBA', 'RGBa',
|
||||||
|
'CMYK', 'YCbCr', 'LAB', 'HSV',
|
||||||
|
]:
|
||||||
|
Image.new(mode, (1, 1))
|
||||||
|
|
||||||
|
def test_image_modes_fail(self):
|
||||||
|
for mode in [
|
||||||
|
'', 'bad', 'very very long',
|
||||||
|
'BGR;15', 'BGR;16', 'BGR;24', 'BGR;32'
|
||||||
|
]:
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
Image.new(mode, (1, 1));
|
||||||
|
self.assertEqual(str(e.exception), 'unrecognized image mode')
|
||||||
|
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
|
|
||||||
im = Image.new("L", (100, 100))
|
im = Image.new("L", (100, 100))
|
||||||
|
@ -145,14 +164,28 @@ class TestImage(PillowTestCase):
|
||||||
self.assertEqual(im.size[1], orig_size[1] + 2*ymargin)
|
self.assertEqual(im.size[1], orig_size[1] + 2*ymargin)
|
||||||
|
|
||||||
def test_getbands(self):
|
def test_getbands(self):
|
||||||
# Arrange
|
# Assert
|
||||||
|
self.assertEqual(hopper('RGB').getbands(), ('R', 'G', 'B'))
|
||||||
|
self.assertEqual(hopper('YCbCr').getbands(), ('Y', 'Cb', 'Cr'))
|
||||||
|
|
||||||
|
def test_getchannel_wrong_params(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
||||||
# Act
|
self.assertRaises(ValueError, im.getchannel, -1)
|
||||||
bands = im.getbands()
|
self.assertRaises(ValueError, im.getchannel, 3)
|
||||||
|
self.assertRaises(ValueError, im.getchannel, 'Z')
|
||||||
|
self.assertRaises(ValueError, im.getchannel, '1')
|
||||||
|
|
||||||
# Assert
|
def test_getchannel(self):
|
||||||
self.assertEqual(bands, ('R', 'G', 'B'))
|
im = hopper('YCbCr')
|
||||||
|
Y, Cb, Cr = im.split()
|
||||||
|
|
||||||
|
self.assert_image_equal(Y, im.getchannel(0))
|
||||||
|
self.assert_image_equal(Y, im.getchannel('Y'))
|
||||||
|
self.assert_image_equal(Cb, im.getchannel(1))
|
||||||
|
self.assert_image_equal(Cb, im.getchannel('Cb'))
|
||||||
|
self.assert_image_equal(Cr, im.getchannel(2))
|
||||||
|
self.assert_image_equal(Cr, im.getchannel('Cr'))
|
||||||
|
|
||||||
def test_getbbox(self):
|
def test_getbbox(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -133,7 +133,7 @@ class TestImageConvert(PillowTestCase):
|
||||||
alpha = hopper('L')
|
alpha = hopper('L')
|
||||||
im.putalpha(alpha)
|
im.putalpha(alpha)
|
||||||
|
|
||||||
comparable = im.convert('P').convert('LA').split()[1]
|
comparable = im.convert('P').convert('LA').getchannel('A')
|
||||||
|
|
||||||
self.assert_image_similar(alpha, comparable, 5)
|
self.assert_image_similar(alpha, comparable, 5)
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ class TestImageConvert(PillowTestCase):
|
||||||
if converted_im.mode == 'RGB':
|
if converted_im.mode == 'RGB':
|
||||||
self.assert_image_similar(converted_im, target, 3)
|
self.assert_image_similar(converted_im, target, 3)
|
||||||
else:
|
else:
|
||||||
self.assert_image_similar(converted_im, target.split()[0], 1)
|
self.assert_image_similar(converted_im, target.getchannel(0), 1)
|
||||||
|
|
||||||
matrix_convert('RGB')
|
matrix_convert('RGB')
|
||||||
matrix_convert('L')
|
matrix_convert('L')
|
||||||
|
|
|
@ -94,6 +94,28 @@ class TestImageFilter(PillowTestCase):
|
||||||
self.assertEqual(rankfilter.size, 1)
|
self.assertEqual(rankfilter.size, 1)
|
||||||
self.assertEqual(rankfilter.rank, 2)
|
self.assertEqual(rankfilter.rank, 2)
|
||||||
|
|
||||||
|
def test_consistency_3x3(self):
|
||||||
|
im = Image.open("Tests/images/hopper.bmp")
|
||||||
|
emboss = im.filter(ImageFilter.Kernel((3, 3),
|
||||||
|
(-1, -1, 0,
|
||||||
|
-1, 0, 1,
|
||||||
|
0, 1, 1), .3))
|
||||||
|
|
||||||
|
self.assert_image_equal(
|
||||||
|
emboss, Image.open("Tests/images/hopper_emboss.bmp"))
|
||||||
|
|
||||||
|
def test_consistency_5x5(self):
|
||||||
|
im = Image.open("Tests/images/hopper.bmp")
|
||||||
|
emboss = im.filter(ImageFilter.Kernel((5, 5),
|
||||||
|
(-1, -1, -1, -1, 0,
|
||||||
|
-1, -1, -1, 0, 1,
|
||||||
|
-1, -1, 0, 1, 1,
|
||||||
|
-1, 0, 1, 1, 1,
|
||||||
|
0, 1, 1, 1, 1), 0.3))
|
||||||
|
|
||||||
|
self.assert_image_equal(
|
||||||
|
emboss, Image.open("Tests/images/hopper_emboss_more.bmp"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
from __future__ import print_function
|
from __future__ import division, print_function
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
@ -300,24 +303,46 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
|
||||||
|
|
||||||
|
|
||||||
class CoreResamplePassesTest(PillowTestCase):
|
class CoreResamplePassesTest(PillowTestCase):
|
||||||
|
@contextmanager
|
||||||
|
def count(self, diff):
|
||||||
|
count = Image.core.getcount()
|
||||||
|
yield
|
||||||
|
self.assertEqual(Image.core.getcount() - count, diff)
|
||||||
|
|
||||||
def test_horizontal(self):
|
def test_horizontal(self):
|
||||||
im = hopper('L')
|
im = hopper('L')
|
||||||
count = Image.core.getcount()
|
with self.count(1):
|
||||||
im.resize((im.size[0] + 10, im.size[1]), Image.BILINEAR)
|
im.resize((im.size[0] - 10, im.size[1]), Image.BILINEAR)
|
||||||
self.assertEqual(Image.core.getcount(), count + 1)
|
|
||||||
|
|
||||||
def test_vertical(self):
|
def test_vertical(self):
|
||||||
im = hopper('L')
|
im = hopper('L')
|
||||||
count = Image.core.getcount()
|
with self.count(1):
|
||||||
im.resize((im.size[0], im.size[1] + 10), Image.BILINEAR)
|
im.resize((im.size[0], im.size[1] - 10), Image.BILINEAR)
|
||||||
self.assertEqual(Image.core.getcount(), count + 1)
|
|
||||||
|
|
||||||
def test_both(self):
|
def test_both(self):
|
||||||
im = hopper('L')
|
im = hopper('L')
|
||||||
count = Image.core.getcount()
|
with self.count(2):
|
||||||
im.resize((im.size[0] + 10, im.size[1] + 10), Image.BILINEAR)
|
im.resize((im.size[0] - 10, im.size[1] - 10), Image.BILINEAR)
|
||||||
self.assertEqual(Image.core.getcount(), count + 2)
|
|
||||||
|
|
||||||
|
def test_box_horizontal(self):
|
||||||
|
im = hopper('L')
|
||||||
|
box = (20, 0, im.size[0] - 20, im.size[1])
|
||||||
|
with self.count(1):
|
||||||
|
# the same size, but different box
|
||||||
|
with_box = im.resize(im.size, Image.BILINEAR, box)
|
||||||
|
with self.count(2):
|
||||||
|
cropped = im.crop(box).resize(im.size, Image.BILINEAR)
|
||||||
|
self.assert_image_similar(with_box, cropped, 0.1)
|
||||||
|
|
||||||
|
def test_box_vertical(self):
|
||||||
|
im = hopper('L')
|
||||||
|
box = (0, 20, im.size[0], im.size[1] - 20)
|
||||||
|
with self.count(1):
|
||||||
|
# the same size, but different box
|
||||||
|
with_box = im.resize(im.size, Image.BILINEAR, box)
|
||||||
|
with self.count(2):
|
||||||
|
cropped = im.crop(box).resize(im.size, Image.BILINEAR)
|
||||||
|
self.assert_image_similar(with_box, cropped, 0.1)
|
||||||
|
|
||||||
class CoreResampleCoefficientsTest(PillowTestCase):
|
class CoreResampleCoefficientsTest(PillowTestCase):
|
||||||
def test_reduce(self):
|
def test_reduce(self):
|
||||||
|
@ -347,5 +372,92 @@ class CoreResampleCoefficientsTest(PillowTestCase):
|
||||||
self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) # fourth channel
|
self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) # fourth channel
|
||||||
|
|
||||||
|
|
||||||
|
class CoreResampleBoxTest(PillowTestCase):
|
||||||
|
def test_wrong_arguments(self):
|
||||||
|
im = hopper()
|
||||||
|
for resample in (Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING,
|
||||||
|
Image.BICUBIC, Image.LANCZOS):
|
||||||
|
im.resize((32, 32), resample, (0, 0, im.width, im.height))
|
||||||
|
im.resize((32, 32), resample, (20, 20, im.width, im.height))
|
||||||
|
im.resize((32, 32), resample, (20, 20, 20, 100))
|
||||||
|
im.resize((32, 32), resample, (20, 20, 100, 20))
|
||||||
|
|
||||||
|
with self.assertRaisesRegexp(TypeError, "must be sequence of length 4"):
|
||||||
|
im.resize((32, 32), resample, (im.width, im.height))
|
||||||
|
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't be negative"):
|
||||||
|
im.resize((32, 32), resample, (-20, 20, 100, 100))
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't be negative"):
|
||||||
|
im.resize((32, 32), resample, (20, -20, 100, 100))
|
||||||
|
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't be empty"):
|
||||||
|
im.resize((32, 32), resample, (20.1, 20, 20, 100))
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't be empty"):
|
||||||
|
im.resize((32, 32), resample, (20, 20.1, 100, 20))
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't be empty"):
|
||||||
|
im.resize((32, 32), resample, (20.1, 20.1, 20, 20))
|
||||||
|
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't exceed"):
|
||||||
|
im.resize((32, 32), resample, (0, 0, im.width + 1, im.height))
|
||||||
|
with self.assertRaisesRegexp(ValueError, "can't exceed"):
|
||||||
|
im.resize((32, 32), resample, (0, 0, im.width, im.height + 1))
|
||||||
|
|
||||||
|
def resize_tiled(self, im, dst_size, xtiles, ytiles):
|
||||||
|
def split_range(size, tiles):
|
||||||
|
scale = size / tiles
|
||||||
|
for i in range(tiles):
|
||||||
|
yield (int(round(scale * i)), int(round(scale * (i + 1))))
|
||||||
|
|
||||||
|
tiled = Image.new(im.mode, dst_size)
|
||||||
|
scale = (im.size[0] / tiled.size[0], im.size[1] / tiled.size[1])
|
||||||
|
|
||||||
|
for y0, y1 in split_range(dst_size[1], ytiles):
|
||||||
|
for x0, x1 in split_range(dst_size[0], xtiles):
|
||||||
|
box = (x0 * scale[0], y0 * scale[1],
|
||||||
|
x1 * scale[0], y1 * scale[1])
|
||||||
|
tile = im.resize((x1 - x0, y1 - y0), Image.BICUBIC, box)
|
||||||
|
tiled.paste(tile, (x0, y0))
|
||||||
|
return tiled
|
||||||
|
|
||||||
|
def test_tiles(self):
|
||||||
|
im = Image.open("Tests/images/flower.jpg")
|
||||||
|
assert im.size == (480, 360)
|
||||||
|
dst_size = (251, 188)
|
||||||
|
reference = im.resize(dst_size, Image.BICUBIC)
|
||||||
|
|
||||||
|
for tiles in [(1, 1), (3, 3), (9, 7), (100, 100)]:
|
||||||
|
tiled = self.resize_tiled(im, dst_size, *tiles)
|
||||||
|
self.assert_image_similar(reference, tiled, 0.01)
|
||||||
|
|
||||||
|
def test_subsample(self):
|
||||||
|
# This test shows advantages of the subpixel resizing
|
||||||
|
# after supersampling (e.g. during JPEG decoding).
|
||||||
|
im = Image.open("Tests/images/flower.jpg")
|
||||||
|
assert im.size == (480, 360)
|
||||||
|
dst_size = (48, 36)
|
||||||
|
# Reference is cropped image resized to destination
|
||||||
|
reference = im.crop((0, 0, 473, 353)).resize(dst_size, Image.BICUBIC)
|
||||||
|
# Image.BOX emulates supersampling (480 / 8 = 60, 360 / 8 = 45)
|
||||||
|
supersampled = im.resize((60, 45), Image.BOX)
|
||||||
|
|
||||||
|
with_box = supersampled.resize(dst_size, Image.BICUBIC,
|
||||||
|
(0, 0, 59.125, 44.125))
|
||||||
|
without_box = supersampled.resize(dst_size, Image.BICUBIC)
|
||||||
|
|
||||||
|
# error with box should be much smaller than without
|
||||||
|
self.assert_image_similar(reference, with_box, 6)
|
||||||
|
with self.assertRaisesRegexp(AssertionError, "difference 29\."):
|
||||||
|
self.assert_image_similar(reference, without_box, 5)
|
||||||
|
|
||||||
|
def test_formats(self):
|
||||||
|
for resample in [Image.NEAREST, Image.BILINEAR]:
|
||||||
|
for mode in ['RGB', 'L', 'RGBA', 'LA', 'I', '']:
|
||||||
|
im = hopper(mode)
|
||||||
|
box = (20, 20, im.size[0] - 20, im.size[1] - 20)
|
||||||
|
with_box = im.resize((32, 32), resample, box)
|
||||||
|
cropped = im.crop(box).resize((32, 32), resample)
|
||||||
|
self.assert_image_similar(cropped, with_box, 0.4)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -360,8 +360,7 @@ class TestImageCms(PillowTestCase):
|
||||||
return Image.merge(mode, chans)
|
return Image.merge(mode, chans)
|
||||||
|
|
||||||
source_image = create_test_image()
|
source_image = create_test_image()
|
||||||
preserved_channel_ndx = source_image.getbands().index(preserved_channel)
|
source_image_aux = source_image.getchannel(preserved_channel)
|
||||||
source_image_aux = source_image.split()[preserved_channel_ndx]
|
|
||||||
|
|
||||||
# create some transform, it doesn't matter which one
|
# create some transform, it doesn't matter which one
|
||||||
source_profile = ImageCms.createProfile("sRGB")
|
source_profile = ImageCms.createProfile("sRGB")
|
||||||
|
@ -374,7 +373,7 @@ class TestImageCms(PillowTestCase):
|
||||||
result_image = source_image
|
result_image = source_image
|
||||||
else:
|
else:
|
||||||
result_image = ImageCms.applyTransform(source_image, t, inPlace=False)
|
result_image = ImageCms.applyTransform(source_image, t, inPlace=False)
|
||||||
result_image_aux = result_image.split()[preserved_channel_ndx]
|
result_image_aux = result_image.getchannel(preserved_channel)
|
||||||
|
|
||||||
self.assert_image_equal(source_image_aux, result_image_aux)
|
self.assert_image_equal(source_image_aux, result_image_aux)
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class TestImageEnhance(PillowTestCase):
|
||||||
|
|
||||||
def _check_alpha(self, im, original, op, amount):
|
def _check_alpha(self, im, original, op, amount):
|
||||||
self.assertEqual(im.getbands(), original.getbands())
|
self.assertEqual(im.getbands(), original.getbands())
|
||||||
self.assert_image_equal(im.split()[-1], original.split()[-1],
|
self.assert_image_equal(im.getchannel('A'), original.getchannel('A'),
|
||||||
"Diff on %s: %s" % (op, amount))
|
"Diff on %s: %s" % (op, amount))
|
||||||
|
|
||||||
def test_alpha(self):
|
def test_alpha(self):
|
||||||
|
|
|
@ -40,13 +40,15 @@ class SimplePatcher(object):
|
||||||
else:
|
else:
|
||||||
delattr(self._parent_obj, self._attr_name)
|
delattr(self._parent_obj, self._attr_name)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not Available")
|
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not Available")
|
||||||
class TestImageFont(PillowTestCase):
|
class TestImageFont(PillowTestCase):
|
||||||
LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC
|
LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC
|
||||||
|
|
||||||
# Freetype has different metrics depending on the version.
|
# Freetype has different metrics depending on the version.
|
||||||
# (and, other things, but first things first)
|
# (and, other things, but first things first)
|
||||||
METRICS = { ('2', '3'): {'multiline': 30,
|
METRICS = {
|
||||||
|
('2', '3'): {'multiline': 30,
|
||||||
'textsize': 12,
|
'textsize': 12,
|
||||||
'getters': (13, 16)},
|
'getters': (13, 16)},
|
||||||
('2', '7'): {'multiline': 6.2,
|
('2', '7'): {'multiline': 6.2,
|
||||||
|
@ -213,6 +215,14 @@ class TestImageFont(PillowTestCase):
|
||||||
font=ttf,
|
font=ttf,
|
||||||
align="unknown"))
|
align="unknown"))
|
||||||
|
|
||||||
|
def test_draw_align(self):
|
||||||
|
im = Image.new('RGB', (300, 100), 'white')
|
||||||
|
draw = ImageDraw.Draw(im)
|
||||||
|
ttf = self.get_font()
|
||||||
|
line = "some text"
|
||||||
|
draw.text((100, 40), line, (0, 0, 0), font=ttf, align='left')
|
||||||
|
del draw
|
||||||
|
|
||||||
def test_multiline_size(self):
|
def test_multiline_size(self):
|
||||||
ttf = self.get_font()
|
ttf = self.get_font()
|
||||||
im = Image.new(mode='RGB', size=(300, 100))
|
im = Image.new(mode='RGB', size=(300, 100))
|
||||||
|
@ -494,5 +504,6 @@ class TestImageFont(PillowTestCase):
|
||||||
class TestImageFont_RaqmLayout(TestImageFont):
|
class TestImageFont_RaqmLayout(TestImageFont):
|
||||||
LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM
|
LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -1,157 +1,481 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
from helper import unittest, PillowTestCase, py3
|
from helper import unittest, PillowTestCase, py3
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
X = 255
|
||||||
|
|
||||||
|
|
||||||
class TestLibPack(PillowTestCase):
|
class TestLibPack(PillowTestCase):
|
||||||
|
def assert_pack(self, mode, rawmode, data, *pixels):
|
||||||
|
"""
|
||||||
|
data - either raw bytes with data or just number of bytes in rawmode.
|
||||||
|
"""
|
||||||
|
im = Image.new(mode, (len(pixels), 1))
|
||||||
|
for x, pixel in enumerate(pixels):
|
||||||
|
im.putpixel((x, 0), pixel)
|
||||||
|
|
||||||
def pack(self):
|
if isinstance(data, (int)):
|
||||||
pass # not yet
|
data_len = data * len(pixels)
|
||||||
|
data = bytes(bytearray(range(1, data_len + 1)))
|
||||||
|
|
||||||
def test_pack(self):
|
self.assertEqual(data, im.tobytes("raw", rawmode))
|
||||||
|
|
||||||
def pack(mode, rawmode, in_data=(1, 2, 3, 4)):
|
def test_1(self):
|
||||||
if len(mode) == 1:
|
self.assert_pack("1", "1", b'\x01', 0,0,0,0,0,0,0,X)
|
||||||
im = Image.new(mode, (1, 1), in_data[0])
|
self.assert_pack("1", "1;I", b'\x01', X,X,X,X,X,X,X,0)
|
||||||
|
self.assert_pack("1", "1;R", b'\x01', X,0,0,0,0,0,0,0)
|
||||||
|
self.assert_pack("1", "1;IR", b'\x01', 0,X,X,X,X,X,X,X)
|
||||||
|
|
||||||
|
self.assert_pack("1", "1", b'\xaa', X,0,X,0,X,0,X,0)
|
||||||
|
self.assert_pack("1", "1;I", b'\xaa', 0,X,0,X,0,X,0,X)
|
||||||
|
self.assert_pack("1", "1;R", b'\xaa', 0,X,0,X,0,X,0,X)
|
||||||
|
self.assert_pack("1", "1;IR", b'\xaa', X,0,X,0,X,0,X,0)
|
||||||
|
|
||||||
|
self.assert_pack("1", "L", b'\xff\x00\x00\xff\x00\x00', X,0,0,X,0,0)
|
||||||
|
|
||||||
|
def test_L(self):
|
||||||
|
self.assert_pack("L", "L", 1, 1,2,3,4)
|
||||||
|
|
||||||
|
def test_LA(self):
|
||||||
|
self.assert_pack("LA", "LA", 2, (1,2), (3,4), (5,6))
|
||||||
|
self.assert_pack("LA", "LA;L", 2, (1,4), (2,5), (3,6))
|
||||||
|
|
||||||
|
def test_P(self):
|
||||||
|
self.assert_pack("P", "P;1", b'\xe4', 1, 1, 1, 0, 0, 255, 0, 0)
|
||||||
|
self.assert_pack("P", "P;2", b'\xe4', 3, 2, 1, 0)
|
||||||
|
self.assert_pack("P", "P;4", b'\x02\xef', 0, 2, 14, 15)
|
||||||
|
self.assert_pack("P", "P", 1, 1, 2, 3, 4)
|
||||||
|
|
||||||
|
def test_PA(self):
|
||||||
|
self.assert_pack("PA", "PA", 2, (1,2), (3,4), (5,6))
|
||||||
|
self.assert_pack("PA", "PA;L", 2, (1,4), (2,5), (3,6))
|
||||||
|
|
||||||
|
def test_RGB(self):
|
||||||
|
self.assert_pack("RGB", "RGB", 3, (1,2,3), (4,5,6), (7,8,9))
|
||||||
|
self.assert_pack("RGB", "RGBX",
|
||||||
|
b'\x01\x02\x03\xff\x05\x06\x07\xff', (1,2,3), (5,6,7))
|
||||||
|
self.assert_pack("RGB", "XRGB",
|
||||||
|
b'\x00\x02\x03\x04\x00\x06\x07\x08', (2,3,4), (6,7,8))
|
||||||
|
self.assert_pack("RGB", "BGR", 3, (3,2,1), (6,5,4), (9,8,7))
|
||||||
|
self.assert_pack("RGB", "BGRX",
|
||||||
|
b'\x01\x02\x03\x00\x05\x06\x07\x00', (3,2,1), (7,6,5))
|
||||||
|
self.assert_pack("RGB", "XBGR",
|
||||||
|
b'\x00\x02\x03\x04\x00\x06\x07\x08', (4,3,2), (8,7,6))
|
||||||
|
self.assert_pack("RGB", "RGB;L", 3, (1,4,7), (2,5,8), (3,6,9))
|
||||||
|
self.assert_pack("RGB", "R", 1, (1,9,9), (2,9,9), (3,9,9))
|
||||||
|
self.assert_pack("RGB", "G", 1, (9,1,9), (9,2,9), (9,3,9))
|
||||||
|
self.assert_pack("RGB", "B", 1, (9,9,1), (9,9,2), (9,9,3))
|
||||||
|
|
||||||
|
def test_RGBA(self):
|
||||||
|
self.assert_pack("RGBA", "RGBA", 4,
|
||||||
|
(1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_pack("RGBA", "RGBA;L", 4,
|
||||||
|
(1,4,7,10), (2,5,8,11), (3,6,9,12))
|
||||||
|
self.assert_pack("RGBA", "RGB", 3, (1,2,3,14), (4,5,6,15), (7,8,9,16))
|
||||||
|
self.assert_pack("RGBA", "BGR", 3, (3,2,1,14), (6,5,4,15), (9,8,7,16))
|
||||||
|
self.assert_pack("RGBA", "BGRA", 4,
|
||||||
|
(3,2,1,4), (7,6,5,8), (11,10,9,12))
|
||||||
|
self.assert_pack("RGBA", "ABGR", 4,
|
||||||
|
(4,3,2,1), (8,7,6,5), (12,11,10,9))
|
||||||
|
self.assert_pack("RGBA", "BGRa", 4,
|
||||||
|
(191,127,63,4), (223,191,159,8), (233,212,191,12))
|
||||||
|
self.assert_pack("RGBA", "R", 1, (1,0,8,9), (2,0,8,9), (3,0,8,0))
|
||||||
|
self.assert_pack("RGBA", "G", 1, (6,1,8,9), (6,2,8,9), (6,3,8,9))
|
||||||
|
self.assert_pack("RGBA", "B", 1, (6,7,1,9), (6,7,2,0), (6,7,3,9))
|
||||||
|
self.assert_pack("RGBA", "A", 1, (6,7,0,1), (6,7,0,2), (0,7,0,3))
|
||||||
|
|
||||||
|
def test_RGBa(self):
|
||||||
|
self.assert_pack("RGBa", "RGBa", 4,
|
||||||
|
(1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_pack("RGBa", "BGRa", 4,
|
||||||
|
(3,2,1,4), (7,6,5,8), (11,10,9,12))
|
||||||
|
self.assert_pack("RGBa", "aBGR", 4,
|
||||||
|
(4,3,2,1), (8,7,6,5), (12,11,10,9))
|
||||||
|
|
||||||
|
def test_RGBX(self):
|
||||||
|
self.assert_pack("RGBX", "RGBX", 4, (1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_pack("RGBX", "RGBX;L", 4, (1,4,7,10), (2,5,8,11), (3,6,9,12))
|
||||||
|
self.assert_pack("RGBX", "RGB", 3, (1,2,3,X), (4,5,6,X), (7,8,9,X))
|
||||||
|
self.assert_pack("RGBX", "BGR", 3, (3,2,1,X), (6,5,4,X), (9,8,7,X))
|
||||||
|
self.assert_pack("RGBX", "BGRX",
|
||||||
|
b'\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00',
|
||||||
|
(3,2,1,X), (7,6,5,X), (11,10,9,X))
|
||||||
|
self.assert_pack("RGBX", "XBGR",
|
||||||
|
b'\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c',
|
||||||
|
(4,3,2,X), (8,7,6,X), (12,11,10,X))
|
||||||
|
self.assert_pack("RGBX", "R", 1, (1,0,8,9), (2,0,8,9), (3,0,8,0))
|
||||||
|
self.assert_pack("RGBX", "G", 1, (6,1,8,9), (6,2,8,9), (6,3,8,9))
|
||||||
|
self.assert_pack("RGBX", "B", 1, (6,7,1,9), (6,7,2,0), (6,7,3,9))
|
||||||
|
self.assert_pack("RGBX", "X", 1, (6,7,0,1), (6,7,0,2), (0,7,0,3))
|
||||||
|
|
||||||
|
def test_CMYK(self):
|
||||||
|
self.assert_pack("CMYK", "CMYK", 4, (1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_pack("CMYK", "CMYK;I", 4,
|
||||||
|
(254,253,252,251), (250,249,248,247), (246,245,244,243))
|
||||||
|
self.assert_pack("CMYK", "CMYK;L", 4,
|
||||||
|
(1,4,7,10), (2,5,8,11), (3,6,9,12))
|
||||||
|
self.assert_pack("CMYK", "K", 1, (6,7,0,1), (6,7,0,2), (0,7,0,3))
|
||||||
|
|
||||||
|
def test_YCbCr(self):
|
||||||
|
self.assert_pack("YCbCr", "YCbCr", 3, (1,2,3), (4,5,6), (7,8,9))
|
||||||
|
self.assert_pack("YCbCr", "YCbCr;L", 3, (1,4,7), (2,5,8), (3,6,9))
|
||||||
|
self.assert_pack("YCbCr", "YCbCrX",
|
||||||
|
b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
|
||||||
|
(1,2,3), (5,6,7), (9,10,11))
|
||||||
|
self.assert_pack("YCbCr", "YCbCrK",
|
||||||
|
b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
|
||||||
|
(1,2,3), (5,6,7), (9,10,11))
|
||||||
|
self.assert_pack("YCbCr", "Y", 1, (1,0,8,9), (2,0,8,9), (3,0,8,0))
|
||||||
|
self.assert_pack("YCbCr", "Cb", 1, (6,1,8,9), (6,2,8,9), (6,3,8,9))
|
||||||
|
self.assert_pack("YCbCr", "Cr", 1, (6,7,1,9), (6,7,2,0), (6,7,3,9))
|
||||||
|
|
||||||
|
def test_LAB(self):
|
||||||
|
self.assert_pack("LAB", "LAB", 3,
|
||||||
|
(1,130,131), (4,133,134), (7,136,137))
|
||||||
|
self.assert_pack("LAB", "L", 1, (1,9,9), (2,9,9), (3,9,9))
|
||||||
|
self.assert_pack("LAB", "A", 1, (9,1,9), (9,2,9), (9,3,9))
|
||||||
|
self.assert_pack("LAB", "B", 1, (9,9,1), (9,9,2), (9,9,3))
|
||||||
|
|
||||||
|
def test_HSV(self):
|
||||||
|
self.assert_pack("HSV", "HSV", 3, (1,2,3), (4,5,6), (7,8,9))
|
||||||
|
self.assert_pack("HSV", "H", 1, (1,9,9), (2,9,9), (3,9,9))
|
||||||
|
self.assert_pack("HSV", "S", 1, (9,1,9), (9,2,9), (9,3,9))
|
||||||
|
self.assert_pack("HSV", "V", 1, (9,9,1), (9,9,2), (9,9,3))
|
||||||
|
|
||||||
|
def test_I(self):
|
||||||
|
self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304)
|
||||||
|
self.assert_pack("I", "I;32S",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
0x01000083, -2097151999)
|
||||||
|
|
||||||
|
if sys.byteorder == 'little':
|
||||||
|
self.assert_pack("I", "I", 4, 0x04030201, 0x08070605)
|
||||||
|
self.assert_pack("I", "I;32NS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
0x01000083, -2097151999)
|
||||||
else:
|
else:
|
||||||
im = Image.new(mode, (1, 1), in_data[:len(mode)])
|
self.assert_pack("I", "I", 4, 0x01020304, 0x05060708)
|
||||||
|
self.assert_pack("I", "I;32NS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
-2097151999, 0x01000083)
|
||||||
|
|
||||||
if py3:
|
def test_F_float(self):
|
||||||
return list(im.tobytes("raw", rawmode))
|
self.assert_pack("F", "F;32F", 4,
|
||||||
|
1.539989614439558e-36, 4.063216068939723e-34)
|
||||||
|
|
||||||
|
if sys.byteorder == 'little':
|
||||||
|
self.assert_pack("F", "F", 4,
|
||||||
|
1.539989614439558e-36, 4.063216068939723e-34)
|
||||||
|
self.assert_pack("F", "F;32NF", 4,
|
||||||
|
1.539989614439558e-36, 4.063216068939723e-34)
|
||||||
else:
|
else:
|
||||||
return [ord(c) for c in im.tobytes("raw", rawmode)]
|
self.assert_pack("F", "F", 4,
|
||||||
|
2.387939260590663e-38, 6.301941157072183e-36)
|
||||||
|
self.assert_pack("F", "F;32NF", 4,
|
||||||
|
2.387939260590663e-38, 6.301941157072183e-36)
|
||||||
|
|
||||||
order = 1 if Image._ENDIAN == '<' else -1
|
|
||||||
|
|
||||||
self.assertEqual(pack("1", "1"), [128])
|
class TestLibUnpack(PillowTestCase):
|
||||||
self.assertEqual(pack("1", "1;I"), [0])
|
def assert_unpack(self, mode, rawmode, data, *pixels):
|
||||||
self.assertEqual(pack("1", "1;R"), [1])
|
"""
|
||||||
self.assertEqual(pack("1", "1;IR"), [0])
|
data - either raw bytes with data or just number of bytes in rawmode.
|
||||||
|
"""
|
||||||
|
if isinstance(data, (int)):
|
||||||
|
data_len = data * len(pixels)
|
||||||
|
data = bytes(bytearray(range(1, data_len + 1)))
|
||||||
|
|
||||||
self.assertEqual(pack("L", "L"), [1])
|
im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1)
|
||||||
|
|
||||||
self.assertEqual(pack("I", "I"), [1, 0, 0, 0][::order])
|
for x, pixel in enumerate(pixels):
|
||||||
|
self.assertEqual(pixel, im.getpixel((x, 0)))
|
||||||
|
|
||||||
self.assertEqual(pack("F", "F"), [0, 0, 128, 63][::order])
|
def test_1(self):
|
||||||
|
self.assert_unpack("1", "1", b'\x01', 0, 0, 0, 0, 0, 0, 0, X)
|
||||||
|
self.assert_unpack("1", "1;I", b'\x01', X, X, X, X, X, X, X, 0)
|
||||||
|
self.assert_unpack("1", "1;R", b'\x01', X, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
self.assert_unpack("1", "1;IR", b'\x01', 0, X, X, X, X, X, X, X)
|
||||||
|
|
||||||
self.assertEqual(pack("LA", "LA"), [1, 2])
|
self.assert_unpack("1", "1", b'\xaa', X, 0, X, 0, X, 0, X, 0)
|
||||||
|
self.assert_unpack("1", "1;I", b'\xaa', 0, X, 0, X, 0, X, 0, X)
|
||||||
|
self.assert_unpack("1", "1;R", b'\xaa', 0, X, 0, X, 0, X, 0, X)
|
||||||
|
self.assert_unpack("1", "1;IR", b'\xaa', X, 0, X, 0, X, 0, X, 0)
|
||||||
|
|
||||||
self.assertEqual(pack("RGB", "RGB"), [1, 2, 3])
|
self.assert_unpack("1", "1;8", b'\x00\x01\x02\xff', 0, X, X, X)
|
||||||
self.assertEqual(pack("RGB", "RGB;L"), [1, 2, 3])
|
|
||||||
self.assertEqual(pack("RGB", "BGR"), [3, 2, 1])
|
|
||||||
self.assertEqual(pack("RGB", "RGBX"), [1, 2, 3, 255]) # 255?
|
|
||||||
self.assertEqual(pack("RGB", "BGRX"), [3, 2, 1, 0])
|
|
||||||
self.assertEqual(pack("RGB", "XRGB"), [0, 1, 2, 3])
|
|
||||||
self.assertEqual(pack("RGB", "XBGR"), [0, 3, 2, 1])
|
|
||||||
|
|
||||||
self.assertEqual(pack("RGBX", "RGBX"), [1, 2, 3, 4]) # 4->255?
|
def test_L(self):
|
||||||
|
self.assert_unpack("L", "L;2", b'\xe4', 255, 170, 85, 0)
|
||||||
|
self.assert_unpack("L", "L;2I", b'\xe4', 0, 85, 170, 255)
|
||||||
|
self.assert_unpack("L", "L;2R", b'\xe4', 0, 170, 85, 255)
|
||||||
|
self.assert_unpack("L", "L;2IR", b'\xe4', 255, 85, 170, 0)
|
||||||
|
|
||||||
self.assertEqual(pack("RGBA", "RGBA"), [1, 2, 3, 4])
|
self.assert_unpack("L", "L;4", b'\x02\xef', 0, 34, 238, 255)
|
||||||
self.assertEqual(pack("RGBA", "BGRa"), [0, 0, 0, 4])
|
self.assert_unpack("L", "L;4I", b'\x02\xef', 255, 221, 17, 0)
|
||||||
self.assertEqual(pack("RGBA", "BGRa", in_data=(20, 30, 40, 50)), [8, 6, 4, 50])
|
self.assert_unpack("L", "L;4R", b'\x02\xef', 68, 0, 255, 119)
|
||||||
|
self.assert_unpack("L", "L;4IR", b'\x02\xef', 187, 255, 0, 136)
|
||||||
|
|
||||||
self.assertEqual(pack("RGBa", "RGBa"), [1, 2, 3, 4])
|
self.assert_unpack("L", "L", 1, 1, 2, 3, 4)
|
||||||
self.assertEqual(pack("RGBa", "BGRa"), [3, 2, 1, 4])
|
self.assert_unpack("L", "L;I", 1, 254, 253, 252, 251)
|
||||||
self.assertEqual(pack("RGBa", "aBGR"), [4, 3, 2, 1])
|
self.assert_unpack("L", "L;R", 1, 128, 64, 192, 32)
|
||||||
|
self.assert_unpack("L", "L;16", 2, 2, 4, 6, 8)
|
||||||
|
self.assert_unpack("L", "L;16B", 2, 1, 3, 5, 7)
|
||||||
|
|
||||||
self.assertEqual(pack("CMYK", "CMYK"), [1, 2, 3, 4])
|
def test_LA(self):
|
||||||
self.assertEqual(pack("YCbCr", "YCbCr"), [1, 2, 3])
|
self.assert_unpack("LA", "LA", 2, (1, 2), (3, 4), (5, 6))
|
||||||
|
self.assert_unpack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6))
|
||||||
|
|
||||||
def test_unpack(self):
|
def test_P(self):
|
||||||
|
self.assert_unpack("P", "P;1", b'\xe4', 1, 1, 1, 0, 0, 1, 0, 0)
|
||||||
|
self.assert_unpack("P", "P;2", b'\xe4', 3, 2, 1, 0)
|
||||||
|
# self.assert_unpack("P", "P;2L", b'\xe4', 1, 1, 1, 0) # erroneous?
|
||||||
|
self.assert_unpack("P", "P;4", b'\x02\xef', 0, 2, 14, 15)
|
||||||
|
# self.assert_unpack("P", "P;4L", b'\x02\xef', 2, 10, 10, 0) # erroneous?
|
||||||
|
self.assert_unpack("P", "P", 1, 1, 2, 3, 4)
|
||||||
|
self.assert_unpack("P", "P;R", 1, 128, 64, 192, 32)
|
||||||
|
|
||||||
def unpack(mode, rawmode, bytes_):
|
def test_PA(self):
|
||||||
im = None
|
self.assert_unpack("PA", "PA", 2, (1, 2), (3, 4), (5, 6))
|
||||||
|
self.assert_unpack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6))
|
||||||
|
|
||||||
if py3:
|
def test_RGB(self):
|
||||||
data = bytes(range(1, bytes_+1))
|
self.assert_unpack("RGB", "RGB", 3, (1,2,3), (4,5,6), (7,8,9))
|
||||||
|
self.assert_unpack("RGB", "RGB;L", 3, (1,4,7), (2,5,8), (3,6,9))
|
||||||
|
self.assert_unpack("RGB", "RGB;R", 3, (128,64,192), (32,160,96))
|
||||||
|
self.assert_unpack("RGB", "RGB;16B", 6, (1,3,5), (7,9,11))
|
||||||
|
self.assert_unpack("RGB", "BGR", 3, (3,2,1), (6,5,4), (9,8,7))
|
||||||
|
self.assert_unpack("RGB", "RGB;15", 2, (8,131,0), (24,0,8))
|
||||||
|
self.assert_unpack("RGB", "BGR;15", 2, (0,131,8), (8,0,24))
|
||||||
|
self.assert_unpack("RGB", "RGB;16", 2, (8,64,0), (24,129,0))
|
||||||
|
self.assert_unpack("RGB", "BGR;16", 2, (0,64,8), (0,129,24))
|
||||||
|
self.assert_unpack("RGB", "RGB;4B", 2, (17,0,34), (51,0,68))
|
||||||
|
self.assert_unpack("RGB", "RGBX", 4, (1,2,3), (5,6,7), (9,10,11))
|
||||||
|
self.assert_unpack("RGB", "RGBX;L", 4, (1,4,7), (2,5,8), (3,6,9))
|
||||||
|
self.assert_unpack("RGB", "BGRX", 4, (3,2,1), (7,6,5), (11,10,9))
|
||||||
|
self.assert_unpack("RGB", "XRGB", 4, (2,3,4), (6,7,8), (10,11,12))
|
||||||
|
self.assert_unpack("RGB", "XBGR", 4, (4,3,2), (8,7,6), (12,11,10))
|
||||||
|
self.assert_unpack("RGB", "YCC;P",
|
||||||
|
b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data
|
||||||
|
(127,102,0), (192,227,0), (213,255,170), (98,255,133))
|
||||||
|
self.assert_unpack("RGB", "R", 1, (1,0,0), (2,0,0), (3,0,0))
|
||||||
|
self.assert_unpack("RGB", "G", 1, (0,1,0), (0,2,0), (0,3,0))
|
||||||
|
self.assert_unpack("RGB", "B", 1, (0,0,1), (0,0,2), (0,0,3))
|
||||||
|
|
||||||
|
def test_RGBA(self):
|
||||||
|
self.assert_unpack("RGBA", "LA", 2, (1,1,1,2), (3,3,3,4), (5,5,5,6))
|
||||||
|
self.assert_unpack("RGBA", "LA;16B", 4,
|
||||||
|
(1,1,1,3), (5,5,5,7), (9,9,9,11))
|
||||||
|
self.assert_unpack("RGBA", "RGBA", 4,
|
||||||
|
(1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_unpack("RGBA", "RGBa", 4,
|
||||||
|
(63,127,191,4), (159,191,223,8), (191,212,233,12))
|
||||||
|
self.assert_unpack("RGBA", "BGRa", 4,
|
||||||
|
(191,127,63,4), (223,191,159,8), (233,212,191,12))
|
||||||
|
self.assert_unpack("RGBA", "RGBA;I", 4,
|
||||||
|
(254,253,252,4), (250,249,248,8), (246,245,244,12))
|
||||||
|
self.assert_unpack("RGBA", "RGBA;L", 4,
|
||||||
|
(1,4,7,10), (2,5,8,11), (3,6,9,12))
|
||||||
|
self.assert_unpack("RGBA", "RGBA;15", 2, (8,131,0,0), (24,0,8,0))
|
||||||
|
self.assert_unpack("RGBA", "BGRA;15", 2, (0,131,8,0), (8,0,24,0))
|
||||||
|
self.assert_unpack("RGBA", "RGBA;4B", 2, (17,0,34,0), (51,0,68,0))
|
||||||
|
self.assert_unpack("RGBA", "RGBA;16B", 8, (1,3,5,7), (9,11,13,15))
|
||||||
|
self.assert_unpack("RGBA", "BGRA", 4,
|
||||||
|
(3,2,1,4), (7,6,5,8), (11,10,9,12))
|
||||||
|
self.assert_unpack("RGBA", "ARGB", 4,
|
||||||
|
(2,3,4,1), (6,7,8,5), (10,11,12,9))
|
||||||
|
self.assert_unpack("RGBA", "ABGR", 4,
|
||||||
|
(4,3,2,1), (8,7,6,5), (12,11,10,9))
|
||||||
|
self.assert_unpack("RGBA", "YCCA;P",
|
||||||
|
b']bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11', # random data
|
||||||
|
(0,161,0,4), (255,255,255,237), (27,158,0,206), (0,118,0,17))
|
||||||
|
self.assert_unpack("RGBA", "R", 1, (1,0,0,0), (2,0,0,0), (3,0,0,0))
|
||||||
|
self.assert_unpack("RGBA", "G", 1, (0,1,0,0), (0,2,0,0), (0,3,0,0))
|
||||||
|
self.assert_unpack("RGBA", "B", 1, (0,0,1,0), (0,0,2,0), (0,0,3,0))
|
||||||
|
self.assert_unpack("RGBA", "A", 1, (0,0,0,1), (0,0,0,2), (0,0,0,3))
|
||||||
|
|
||||||
|
def test_RGBa(self):
|
||||||
|
self.assert_unpack("RGBa", "RGBa", 4,
|
||||||
|
(1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_unpack("RGBa", "BGRa", 4,
|
||||||
|
(3,2,1,4), (7,6,5,8), (11,10,9,12))
|
||||||
|
self.assert_unpack("RGBa", "aRGB", 4,
|
||||||
|
(2,3,4,1), (6,7,8,5), (10,11,12,9))
|
||||||
|
self.assert_unpack("RGBa", "aBGR", 4,
|
||||||
|
(4,3,2,1), (8,7,6,5), (12,11,10,9))
|
||||||
|
|
||||||
|
def test_RGBX(self):
|
||||||
|
self.assert_unpack("RGBX", "RGB", 3, (1,2,3,X), (4,5,6,X), (7,8,9,X))
|
||||||
|
self.assert_unpack("RGBX", "RGB;L", 3, (1,4,7,X), (2,5,8,X), (3,6,9,X))
|
||||||
|
self.assert_unpack("RGBX", "RGB;16B", 6, (1,3,5,X), (7,9,11,X))
|
||||||
|
self.assert_unpack("RGBX", "BGR", 3, (3,2,1,X), (6,5,4,X), (9,8,7,X))
|
||||||
|
self.assert_unpack("RGBX", "RGB;15", 2, (8,131,0,X), (24,0,8,X))
|
||||||
|
self.assert_unpack("RGBX", "BGR;15", 2, (0,131,8,X), (8,0,24,X))
|
||||||
|
self.assert_unpack("RGBX", "RGB;4B", 2, (17,0,34,X), (51,0,68,X))
|
||||||
|
self.assert_unpack("RGBX", "RGBX", 4,
|
||||||
|
(1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_unpack("RGBX", "RGBX;L", 4,
|
||||||
|
(1,4,7,10), (2,5,8,11), (3,6,9,12))
|
||||||
|
self.assert_unpack("RGBX", "BGRX", 4, (3,2,1,X), (7,6,5,X), (11,10,9,X))
|
||||||
|
self.assert_unpack("RGBX", "XRGB", 4, (2,3,4,X), (6,7,8,X), (10,11,12,X))
|
||||||
|
self.assert_unpack("RGBX", "XBGR", 4, (4,3,2,X), (8,7,6,X), (12,11,10,X))
|
||||||
|
self.assert_unpack("RGBX", "YCC;P",
|
||||||
|
b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data
|
||||||
|
(127,102,0,X), (192,227,0,X), (213,255,170,X), (98,255,133,X))
|
||||||
|
self.assert_unpack("RGBX", "R", 1, (1,0,0,0), (2,0,0,0), (3,0,0,0))
|
||||||
|
self.assert_unpack("RGBX", "G", 1, (0,1,0,0), (0,2,0,0), (0,3,0,0))
|
||||||
|
self.assert_unpack("RGBX", "B", 1, (0,0,1,0), (0,0,2,0), (0,0,3,0))
|
||||||
|
self.assert_unpack("RGBX", "X", 1, (0,0,0,1), (0,0,0,2), (0,0,0,3))
|
||||||
|
|
||||||
|
def test_CMYK(self):
|
||||||
|
self.assert_unpack("CMYK", "CMYK", 4, (1,2,3,4), (5,6,7,8), (9,10,11,12))
|
||||||
|
self.assert_unpack("CMYK", "CMYK;I", 4,
|
||||||
|
(254,253,252,251), (250,249,248,247), (246,245,244,243))
|
||||||
|
self.assert_unpack("CMYK", "CMYK;L", 4,
|
||||||
|
(1,4,7,10), (2,5,8,11), (3,6,9,12))
|
||||||
|
self.assert_unpack("CMYK", "C", 1, (1,0,0,0), (2,0,0,0), (3,0,0,0))
|
||||||
|
self.assert_unpack("CMYK", "M", 1, (0,1,0,0), (0,2,0,0), (0,3,0,0))
|
||||||
|
self.assert_unpack("CMYK", "Y", 1, (0,0,1,0), (0,0,2,0), (0,0,3,0))
|
||||||
|
self.assert_unpack("CMYK", "K", 1, (0,0,0,1), (0,0,0,2), (0,0,0,3))
|
||||||
|
self.assert_unpack("CMYK", "C;I", 1,
|
||||||
|
(254,0,0,0), (253,0,0,0), (252,0,0,0))
|
||||||
|
self.assert_unpack("CMYK", "M;I", 1,
|
||||||
|
(0,254,0,0), (0,253,0,0), (0,252,0,0))
|
||||||
|
self.assert_unpack("CMYK", "Y;I", 1,
|
||||||
|
(0,0,254,0), (0,0,253,0), (0,0,252,0))
|
||||||
|
self.assert_unpack("CMYK", "K;I", 1,
|
||||||
|
(0,0,0,254), (0,0,0,253), (0,0,0,252))
|
||||||
|
|
||||||
|
def test_YCbCr(self):
|
||||||
|
self.assert_unpack("YCbCr", "YCbCr", 3, (1,2,3), (4,5,6), (7,8,9))
|
||||||
|
self.assert_unpack("YCbCr", "YCbCr;L", 3, (1,4,7), (2,5,8), (3,6,9))
|
||||||
|
self.assert_unpack("YCbCr", "YCbCrX", 4, (1,2,3), (5,6,7), (9,10,11))
|
||||||
|
self.assert_unpack("YCbCr", "YCbCrK", 4, (1,2,3), (5,6,7), (9,10,11))
|
||||||
|
|
||||||
|
def test_LAB(self):
|
||||||
|
self.assert_unpack("LAB", "LAB", 3,
|
||||||
|
(1,130,131), (4,133,134), (7,136,137))
|
||||||
|
self.assert_unpack("LAB", "L", 1, (1,0,0), (2,0,0), (3,0,0))
|
||||||
|
self.assert_unpack("LAB", "A", 1, (0,1,0), (0,2,0), (0,3,0))
|
||||||
|
self.assert_unpack("LAB", "B", 1, (0,0,1), (0,0,2), (0,0,3))
|
||||||
|
|
||||||
|
def test_HSV(self):
|
||||||
|
self.assert_unpack("HSV", "HSV", 3, (1,2,3), (4,5,6), (7,8,9))
|
||||||
|
self.assert_unpack("HSV", "H", 1, (1,0,0), (2,0,0), (3,0,0))
|
||||||
|
self.assert_unpack("HSV", "S", 1, (0,1,0), (0,2,0), (0,3,0))
|
||||||
|
self.assert_unpack("HSV", "V", 1, (0,0,1), (0,0,2), (0,0,3))
|
||||||
|
|
||||||
|
def test_I(self):
|
||||||
|
self.assert_unpack("I", "I;8", 1, 0x01, 0x02, 0x03, 0x04)
|
||||||
|
self.assert_unpack("I", "I;8S", b'\x01\x83', 1, -125)
|
||||||
|
self.assert_unpack("I", "I;16", 2, 0x0201, 0x0403)
|
||||||
|
self.assert_unpack("I", "I;16S", b'\x83\x01\x01\x83', 0x0183, -31999)
|
||||||
|
self.assert_unpack("I", "I;16B", 2, 0x0102, 0x0304)
|
||||||
|
self.assert_unpack("I", "I;16BS", b'\x83\x01\x01\x83', -31999, 0x0183)
|
||||||
|
self.assert_unpack("I", "I;32", 4, 0x04030201, 0x08070605)
|
||||||
|
self.assert_unpack("I", "I;32S",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
0x01000083, -2097151999)
|
||||||
|
self.assert_unpack("I", "I;32B", 4, 0x01020304, 0x05060708)
|
||||||
|
self.assert_unpack("I", "I;32BS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
-2097151999, 0x01000083)
|
||||||
|
|
||||||
|
if sys.byteorder == 'little':
|
||||||
|
self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605)
|
||||||
|
self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403)
|
||||||
|
self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', 0x0183, -31999)
|
||||||
|
self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605)
|
||||||
|
self.assert_unpack("I", "I;32NS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
0x01000083, -2097151999)
|
||||||
else:
|
else:
|
||||||
data = ''.join(chr(i) for i in range(1, bytes_+1))
|
self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708)
|
||||||
|
self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304)
|
||||||
|
self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', -31999, 0x0183)
|
||||||
|
self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708)
|
||||||
|
self.assert_unpack("I", "I;32NS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
-2097151999, 0x01000083)
|
||||||
|
|
||||||
im = Image.frombytes(mode, (1, 1), data, "raw", rawmode, 0, 1)
|
def test_F_int(self):
|
||||||
|
self.assert_unpack("F", "F;8", 1, 0x01, 0x02, 0x03, 0x04)
|
||||||
|
self.assert_unpack("F", "F;8S", b'\x01\x83', 1, -125)
|
||||||
|
self.assert_unpack("F", "F;16", 2, 0x0201, 0x0403)
|
||||||
|
self.assert_unpack("F", "F;16S", b'\x83\x01\x01\x83', 0x0183, -31999)
|
||||||
|
self.assert_unpack("F", "F;16B", 2, 0x0102, 0x0304)
|
||||||
|
self.assert_unpack("F", "F;16BS", b'\x83\x01\x01\x83', -31999, 0x0183)
|
||||||
|
self.assert_unpack("F", "F;32", 4, 67305984, 134678016)
|
||||||
|
self.assert_unpack("F", "F;32S",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
16777348, -2097152000)
|
||||||
|
self.assert_unpack("F", "F;32B", 4, 0x01020304, 0x05060708)
|
||||||
|
self.assert_unpack("F", "F;32BS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
-2097152000, 16777348)
|
||||||
|
|
||||||
return im.getpixel((0, 0))
|
if sys.byteorder == 'little':
|
||||||
|
self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403)
|
||||||
def unpack_1(mode, rawmode, value):
|
self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', 0x0183, -31999)
|
||||||
assert mode == "1"
|
self.assert_unpack("F", "F;32N", 4, 67305984, 134678016)
|
||||||
im = None
|
self.assert_unpack("F", "F;32NS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
if py3:
|
16777348, -2097152000)
|
||||||
im = Image.frombytes(
|
|
||||||
mode, (8, 1), bytes([value]), "raw", rawmode, 0, 1)
|
|
||||||
else:
|
else:
|
||||||
im = Image.frombytes(
|
self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304)
|
||||||
mode, (8, 1), chr(value), "raw", rawmode, 0, 1)
|
self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', -31999, 0x0183)
|
||||||
|
self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708)
|
||||||
|
self.assert_unpack("F", "F;32NS",
|
||||||
|
b'\x83\x00\x00\x01\x01\x00\x00\x83',
|
||||||
|
-2097152000, 16777348)
|
||||||
|
|
||||||
return tuple(im.getdata())
|
def test_F_float(self):
|
||||||
|
self.assert_unpack("F", "F;32F", 4,
|
||||||
|
1.539989614439558e-36, 4.063216068939723e-34)
|
||||||
|
self.assert_unpack("F", "F;32BF", 4,
|
||||||
|
2.387939260590663e-38, 6.301941157072183e-36)
|
||||||
|
self.assert_unpack("F", "F;64F",
|
||||||
|
b'333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0', # by struct.pack
|
||||||
|
0.15000000596046448, -1234.5)
|
||||||
|
self.assert_unpack("F", "F;64BF",
|
||||||
|
b'?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00', # by struct.pack
|
||||||
|
0.15000000596046448, -1234.5)
|
||||||
|
|
||||||
X = 255
|
if sys.byteorder == 'little':
|
||||||
|
self.assert_unpack("F", "F", 4,
|
||||||
|
1.539989614439558e-36, 4.063216068939723e-34)
|
||||||
|
self.assert_unpack("F", "F;32NF", 4,
|
||||||
|
1.539989614439558e-36, 4.063216068939723e-34)
|
||||||
|
self.assert_unpack("F", "F;64NF",
|
||||||
|
b'333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0',
|
||||||
|
0.15000000596046448, -1234.5)
|
||||||
|
else:
|
||||||
|
self.assert_unpack("F", "F", 4,
|
||||||
|
2.387939260590663e-38, 6.301941157072183e-36)
|
||||||
|
self.assert_unpack("F", "F;32NF", 4,
|
||||||
|
2.387939260590663e-38, 6.301941157072183e-36)
|
||||||
|
self.assert_unpack("F", "F;64NF",
|
||||||
|
b'?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00',
|
||||||
|
0.15000000596046448, -1234.5)
|
||||||
|
|
||||||
self.assertEqual(unpack_1("1", "1", 1), (0, 0, 0, 0, 0, 0, 0, X))
|
def test_I16(self):
|
||||||
self.assertEqual(unpack_1("1", "1;I", 1), (X, X, X, X, X, X, X, 0))
|
self.assert_unpack("I;16", "I;16", 2, 0x0201, 0x0403, 0x0605)
|
||||||
self.assertEqual(unpack_1("1", "1;R", 1), (X, 0, 0, 0, 0, 0, 0, 0))
|
self.assert_unpack("I;16B", "I;16B", 2, 0x0102, 0x0304, 0x0506)
|
||||||
self.assertEqual(unpack_1("1", "1;IR", 1), (0, X, X, X, X, X, X, X))
|
self.assert_unpack("I;16L", "I;16L", 2, 0x0201, 0x0403, 0x0605)
|
||||||
|
self.assert_unpack("I;16", "I;12", 2, 0x0010, 0x0203, 0x0040, 0x0506)
|
||||||
|
if sys.byteorder == 'little':
|
||||||
|
self.assert_unpack("I;16", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||||
|
self.assert_unpack("I;16B", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||||
|
self.assert_unpack("I;16L", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||||
|
else:
|
||||||
|
self.assert_unpack("I;16", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||||
|
self.assert_unpack("I;16B", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||||
|
self.assert_unpack("I;16L", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||||
|
|
||||||
self.assertEqual(unpack_1("1", "1", 170), (X, 0, X, 0, X, 0, X, 0))
|
def test_value_error(self):
|
||||||
self.assertEqual(unpack_1("1", "1;I", 170), (0, X, 0, X, 0, X, 0, X))
|
self.assertRaises(ValueError, self.assert_unpack, "L", "L", 0, 0)
|
||||||
self.assertEqual(unpack_1("1", "1;R", 170), (0, X, 0, X, 0, X, 0, X))
|
self.assertRaises(ValueError, self.assert_unpack, "RGB", "RGB", 2, 0)
|
||||||
self.assertEqual(unpack_1("1", "1;IR", 170), (X, 0, X, 0, X, 0, X, 0))
|
self.assertRaises(ValueError, self.assert_unpack, "CMYK", "CMYK", 2, 0)
|
||||||
|
|
||||||
self.assertEqual(unpack("L", "L;2", 1), 0)
|
|
||||||
self.assertEqual(unpack("L", "L;4", 1), 0)
|
|
||||||
self.assertEqual(unpack("L", "L", 1), 1)
|
|
||||||
self.assertEqual(unpack("L", "L;I", 1), 254)
|
|
||||||
self.assertEqual(unpack("L", "L;R", 1), 128)
|
|
||||||
self.assertEqual(unpack("L", "L;16", 2), 2) # little endian
|
|
||||||
self.assertEqual(unpack("L", "L;16B", 2), 1) # big endian
|
|
||||||
|
|
||||||
self.assertEqual(unpack("LA", "LA", 2), (1, 2))
|
|
||||||
self.assertEqual(unpack("LA", "LA;L", 2), (1, 2))
|
|
||||||
|
|
||||||
self.assertEqual(unpack("RGB", "RGB", 3), (1, 2, 3))
|
|
||||||
self.assertEqual(unpack("RGB", "RGB;L", 3), (1, 2, 3))
|
|
||||||
self.assertEqual(unpack("RGB", "RGB;R", 3), (128, 64, 192))
|
|
||||||
self.assertEqual(unpack("RGB", "RGB;16B", 6), (1, 3, 5)) # ?
|
|
||||||
self.assertEqual(unpack("RGB", "BGR", 3), (3, 2, 1))
|
|
||||||
self.assertEqual(unpack("RGB", "RGB;15", 2), (8, 131, 0))
|
|
||||||
self.assertEqual(unpack("RGB", "BGR;15", 2), (0, 131, 8))
|
|
||||||
self.assertEqual(unpack("RGB", "RGB;16", 2), (8, 64, 0))
|
|
||||||
self.assertEqual(unpack("RGB", "BGR;16", 2), (0, 64, 8))
|
|
||||||
self.assertEqual(unpack("RGB", "RGB;4B", 2), (17, 0, 34))
|
|
||||||
|
|
||||||
self.assertEqual(unpack("RGB", "RGBX", 4), (1, 2, 3))
|
|
||||||
self.assertEqual(unpack("RGB", "BGRX", 4), (3, 2, 1))
|
|
||||||
self.assertEqual(unpack("RGB", "XRGB", 4), (2, 3, 4))
|
|
||||||
self.assertEqual(unpack("RGB", "XBGR", 4), (4, 3, 2))
|
|
||||||
|
|
||||||
self.assertEqual(unpack("RGBA", "RGBA", 4), (1, 2, 3, 4))
|
|
||||||
self.assertEqual(unpack("RGBA", "RGBa", 4), (63, 127, 191, 4))
|
|
||||||
self.assertEqual(unpack("RGBA", "BGRA", 4), (3, 2, 1, 4))
|
|
||||||
self.assertEqual(unpack("RGBA", "BGRa", 4), (191, 127, 63, 4))
|
|
||||||
self.assertEqual(unpack("RGBA", "ARGB", 4), (2, 3, 4, 1))
|
|
||||||
self.assertEqual(unpack("RGBA", "ABGR", 4), (4, 3, 2, 1))
|
|
||||||
self.assertEqual(unpack("RGBA", "RGBA;15", 2), (8, 131, 0, 0))
|
|
||||||
self.assertEqual(unpack("RGBA", "BGRA;15", 2), (0, 131, 8, 0))
|
|
||||||
self.assertEqual(unpack("RGBA", "RGBA;4B", 2), (17, 0, 34, 0))
|
|
||||||
|
|
||||||
self.assertEqual(unpack("RGBa", "RGBa", 4), (1, 2, 3, 4))
|
|
||||||
self.assertEqual(unpack("RGBa", "BGRa", 4), (3, 2, 1, 4))
|
|
||||||
self.assertEqual(unpack("RGBa", "aRGB", 4), (2, 3, 4, 1))
|
|
||||||
self.assertEqual(unpack("RGBa", "aBGR", 4), (4, 3, 2, 1))
|
|
||||||
|
|
||||||
self.assertEqual(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255?
|
|
||||||
self.assertEqual(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255))
|
|
||||||
self.assertEqual(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255))
|
|
||||||
self.assertEqual(unpack("RGBX", "XBGR", 4), (4, 3, 2, 255))
|
|
||||||
self.assertEqual(unpack("RGBX", "RGB;15", 2), (8, 131, 0, 255))
|
|
||||||
self.assertEqual(unpack("RGBX", "BGR;15", 2), (0, 131, 8, 255))
|
|
||||||
self.assertEqual(unpack("RGBX", "RGB;4B", 2), (17, 0, 34, 255))
|
|
||||||
|
|
||||||
self.assertEqual(unpack("CMYK", "CMYK", 4), (1, 2, 3, 4))
|
|
||||||
self.assertEqual(unpack("CMYK", "CMYK;I", 4), (254, 253, 252, 251))
|
|
||||||
|
|
||||||
self.assertRaises(ValueError, lambda: unpack("L", "L", 0))
|
|
||||||
self.assertRaises(ValueError, lambda: unpack("RGB", "RGB", 2))
|
|
||||||
self.assertRaises(ValueError, lambda: unpack("CMYK", "CMYK", 2))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -39,7 +39,7 @@ class TestNumpy(PillowTestCase):
|
||||||
def to_image(dtype, bands=1, boolean=0):
|
def to_image(dtype, bands=1, boolean=0):
|
||||||
if bands == 1:
|
if bands == 1:
|
||||||
if boolean:
|
if boolean:
|
||||||
data = [0, 1] * 50
|
data = [0, 255] * 50
|
||||||
else:
|
else:
|
||||||
data = list(range(100))
|
data = list(range(100))
|
||||||
a = numpy.array(data, dtype=dtype)
|
a = numpy.array(data, dtype=dtype)
|
||||||
|
@ -52,14 +52,14 @@ class TestNumpy(PillowTestCase):
|
||||||
a = numpy.array([[x]*bands for x in data], dtype=dtype)
|
a = numpy.array([[x]*bands for x in data], dtype=dtype)
|
||||||
a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands
|
a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands
|
||||||
i = Image.fromarray(a)
|
i = Image.fromarray(a)
|
||||||
if list(i.split()[0].getdata()) != list(range(100)):
|
if list(i.getchannel(0).getdata()) != list(range(100)):
|
||||||
print("data mismatch for", dtype)
|
print("data mismatch for", dtype)
|
||||||
# print(dtype, list(i.getdata()))
|
# print(dtype, list(i.getdata()))
|
||||||
return i
|
return i
|
||||||
|
|
||||||
# Check supported 1-bit integer formats
|
# Check supported 1-bit integer formats
|
||||||
self.assertRaises(TypeError, lambda: to_image(numpy.bool))
|
self.assert_image(to_image(numpy.bool, 1, 1), '1', TEST_IMAGE_SIZE)
|
||||||
self.assertRaises(TypeError, lambda: to_image(numpy.bool8))
|
self.assert_image(to_image(numpy.bool8, 1, 1), '1', TEST_IMAGE_SIZE)
|
||||||
|
|
||||||
# Check supported 8-bit integer formats
|
# Check supported 8-bit integer formats
|
||||||
self.assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
|
self.assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
|
||||||
|
@ -213,5 +213,13 @@ class TestNumpy(PillowTestCase):
|
||||||
self.assertEqual(im.size, (0, 0))
|
self.assertEqual(im.size, (0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_bool(self):
|
||||||
|
# https://github.com/python-pillow/Pillow/issues/2044
|
||||||
|
a = numpy.zeros((10,2), dtype=numpy.bool)
|
||||||
|
a[0][0] = True
|
||||||
|
|
||||||
|
im2 = Image.fromarray(a)
|
||||||
|
self.assertEqual(im2.getdata()[0], 255)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
115
_imaging.c
115
_imaging.c
|
@ -599,7 +599,7 @@ _fill(PyObject* self, PyObject* args)
|
||||||
if (!PyArg_ParseTuple(args, "s|(ii)O", &mode, &xsize, &ysize, &color))
|
if (!PyArg_ParseTuple(args, "s|(ii)O", &mode, &xsize, &ysize, &color))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
im = ImagingNew(mode, xsize, ysize);
|
im = ImagingNewDirty(mode, xsize, ysize);
|
||||||
if (!im)
|
if (!im)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -791,23 +791,6 @@ _copy(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(ImagingCopy(self->image));
|
return PyImagingNew(ImagingCopy(self->image));
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
_copy2(ImagingObject* self, PyObject* args)
|
|
||||||
{
|
|
||||||
ImagingObject* imagep1;
|
|
||||||
ImagingObject* imagep2;
|
|
||||||
if (!PyArg_ParseTuple(args, "O!O!",
|
|
||||||
&Imaging_Type, &imagep1,
|
|
||||||
&Imaging_Type, &imagep2))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!ImagingCopy2(imagep1->image, imagep2->image))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_crop(ImagingObject* self, PyObject* args)
|
_crop(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
|
@ -874,7 +857,7 @@ _gaussian_blur(ImagingObject* self, PyObject* args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
imIn = self->image;
|
imIn = self->image;
|
||||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1520,26 +1503,45 @@ _resize(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
int xsize, ysize;
|
int xsize, ysize;
|
||||||
int filter = IMAGING_TRANSFORM_NEAREST;
|
int filter = IMAGING_TRANSFORM_NEAREST;
|
||||||
if (!PyArg_ParseTuple(args, "(ii)|i", &xsize, &ysize, &filter))
|
float box[4] = {0, 0, 0, 0};
|
||||||
return NULL;
|
|
||||||
|
|
||||||
imIn = self->image;
|
imIn = self->image;
|
||||||
|
box[2] = imIn->xsize;
|
||||||
|
box[3] = imIn->ysize;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "(ii)|i(ffff)", &xsize, &ysize, &filter,
|
||||||
|
&box[0], &box[1], &box[2], &box[3]))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (xsize < 1 || ysize < 1) {
|
if (xsize < 1 || ysize < 1) {
|
||||||
return ImagingError_ValueError("height and width must be > 0");
|
return ImagingError_ValueError("height and width must be > 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imIn->xsize == xsize && imIn->ysize == ysize) {
|
if (box[0] < 0 || box[1] < 0) {
|
||||||
|
return ImagingError_ValueError("box offset can't be negative");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (box[2] > imIn->xsize || box[3] > imIn->ysize) {
|
||||||
|
return ImagingError_ValueError("box can't exceed original image size");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (box[2] - box[0] < 0 || box[3] - box[1] < 0) {
|
||||||
|
return ImagingError_ValueError("box can't be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (box[0] == 0 && box[1] == 0 && box[2] == xsize && box[3] == ysize) {
|
||||||
imOut = ImagingCopy(imIn);
|
imOut = ImagingCopy(imIn);
|
||||||
}
|
}
|
||||||
else if (filter == IMAGING_TRANSFORM_NEAREST) {
|
else if (filter == IMAGING_TRANSFORM_NEAREST) {
|
||||||
double a[6];
|
double a[6];
|
||||||
|
|
||||||
memset(a, 0, sizeof a);
|
memset(a, 0, sizeof a);
|
||||||
a[0] = (double) imIn->xsize / xsize;
|
a[0] = (double) (box[2] - box[0]) / xsize;
|
||||||
a[4] = (double) imIn->ysize / ysize;
|
a[4] = (double) (box[3] - box[1]) / ysize;
|
||||||
|
a[2] = box[0];
|
||||||
|
a[5] = box[1];
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
|
||||||
|
|
||||||
imOut = ImagingTransform(
|
imOut = ImagingTransform(
|
||||||
imOut, imIn, IMAGING_TRANSFORM_AFFINE,
|
imOut, imIn, IMAGING_TRANSFORM_AFFINE,
|
||||||
|
@ -1547,7 +1549,7 @@ _resize(ImagingObject* self, PyObject* args)
|
||||||
a, filter, 1);
|
a, filter, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
imOut = ImagingResample(imIn, xsize, ysize, filter);
|
imOut = ImagingResample(imIn, xsize, ysize, filter, box);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PyImagingNew(imOut);
|
return PyImagingNew(imOut);
|
||||||
|
@ -1665,12 +1667,12 @@ _transpose(ImagingObject* self, PyObject* args)
|
||||||
case 0: /* flip left right */
|
case 0: /* flip left right */
|
||||||
case 1: /* flip top bottom */
|
case 1: /* flip top bottom */
|
||||||
case 3: /* rotate 180 */
|
case 3: /* rotate 180 */
|
||||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||||
break;
|
break;
|
||||||
case 2: /* rotate 90 */
|
case 2: /* rotate 90 */
|
||||||
case 4: /* rotate 270 */
|
case 4: /* rotate 270 */
|
||||||
case 5: /* transpose */
|
case 5: /* transpose */
|
||||||
imOut = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize);
|
imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_SetString(PyExc_ValueError, "No such transpose operation");
|
PyErr_SetString(PyExc_ValueError, "No such transpose operation");
|
||||||
|
@ -1715,7 +1717,7 @@ _unsharp_mask(ImagingObject* self, PyObject* args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
imIn = self->image;
|
imIn = self->image;
|
||||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1738,7 +1740,7 @@ _box_blur(ImagingObject* self, PyObject* args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
imIn = self->image;
|
imIn = self->image;
|
||||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1905,6 +1907,55 @@ _putband(ImagingObject* self, PyObject* args)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_merge(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
char* mode;
|
||||||
|
ImagingObject *band0 = NULL;
|
||||||
|
ImagingObject *band1 = NULL;
|
||||||
|
ImagingObject *band2 = NULL;
|
||||||
|
ImagingObject *band3 = NULL;
|
||||||
|
Imaging bands[4] = {NULL, NULL, NULL, NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "sO!|O!O!O!", &mode,
|
||||||
|
&Imaging_Type, &band0, &Imaging_Type, &band1,
|
||||||
|
&Imaging_Type, &band2, &Imaging_Type, &band3))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (band0) bands[0] = band0->image;
|
||||||
|
if (band1) bands[1] = band1->image;
|
||||||
|
if (band2) bands[2] = band2->image;
|
||||||
|
if (band3) bands[3] = band3->image;
|
||||||
|
|
||||||
|
return PyImagingNew(ImagingMerge(mode, bands));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_split(ImagingObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
int fails = 0;
|
||||||
|
Py_ssize_t i;
|
||||||
|
PyObject* list;
|
||||||
|
PyObject* imaging_object;
|
||||||
|
Imaging bands[4] = {NULL, NULL, NULL, NULL};
|
||||||
|
|
||||||
|
if ( ! ImagingSplit(self->image, bands))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
list = PyTuple_New(self->image->bands);
|
||||||
|
for (i = 0; i < self->image->bands; i++) {
|
||||||
|
imaging_object = PyImagingNew(bands[i]);
|
||||||
|
if ( ! imaging_object)
|
||||||
|
fails += 1;
|
||||||
|
PyTuple_SET_ITEM(list, i, imaging_object);
|
||||||
|
}
|
||||||
|
if (fails) {
|
||||||
|
Py_DECREF(list);
|
||||||
|
list = NULL;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifdef WITH_IMAGECHOPS
|
#ifdef WITH_IMAGECHOPS
|
||||||
|
@ -2940,7 +2991,6 @@ static struct PyMethodDef methods[] = {
|
||||||
{"convert_matrix", (PyCFunction)_convert_matrix, 1},
|
{"convert_matrix", (PyCFunction)_convert_matrix, 1},
|
||||||
{"convert_transparent", (PyCFunction)_convert_transparent, 1},
|
{"convert_transparent", (PyCFunction)_convert_transparent, 1},
|
||||||
{"copy", (PyCFunction)_copy, 1},
|
{"copy", (PyCFunction)_copy, 1},
|
||||||
{"copy2", (PyCFunction)_copy2, 1},
|
|
||||||
{"crop", (PyCFunction)_crop, 1},
|
{"crop", (PyCFunction)_crop, 1},
|
||||||
{"expand", (PyCFunction)_expand_image, 1},
|
{"expand", (PyCFunction)_expand_image, 1},
|
||||||
{"filter", (PyCFunction)_filter, 1},
|
{"filter", (PyCFunction)_filter, 1},
|
||||||
|
@ -2972,6 +3022,7 @@ static struct PyMethodDef methods[] = {
|
||||||
|
|
||||||
{"getband", (PyCFunction)_getband, 1},
|
{"getband", (PyCFunction)_getband, 1},
|
||||||
{"putband", (PyCFunction)_putband, 1},
|
{"putband", (PyCFunction)_putband, 1},
|
||||||
|
{"split", (PyCFunction)_split, 1},
|
||||||
{"fillband", (PyCFunction)_fillband, 1},
|
{"fillband", (PyCFunction)_fillband, 1},
|
||||||
|
|
||||||
{"setmode", (PyCFunction)im_setmode, 1},
|
{"setmode", (PyCFunction)im_setmode, 1},
|
||||||
|
@ -3316,12 +3367,12 @@ static PyMethodDef functions[] = {
|
||||||
{"blend", (PyCFunction)_blend, 1},
|
{"blend", (PyCFunction)_blend, 1},
|
||||||
{"fill", (PyCFunction)_fill, 1},
|
{"fill", (PyCFunction)_fill, 1},
|
||||||
{"new", (PyCFunction)_new, 1},
|
{"new", (PyCFunction)_new, 1},
|
||||||
|
{"merge", (PyCFunction)_merge, 1},
|
||||||
|
|
||||||
{"getcount", (PyCFunction)_getcount, 1},
|
{"getcount", (PyCFunction)_getcount, 1},
|
||||||
|
|
||||||
/* Functions */
|
/* Functions */
|
||||||
{"convert", (PyCFunction)_convert2, 1},
|
{"convert", (PyCFunction)_convert2, 1},
|
||||||
{"copy", (PyCFunction)_copy2, 1},
|
|
||||||
|
|
||||||
/* Codecs */
|
/* Codecs */
|
||||||
{"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, 1},
|
{"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, 1},
|
||||||
|
|
2
_webp.c
2
_webp.c
|
@ -247,7 +247,7 @@ PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){
|
||||||
* The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well.
|
* The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well.
|
||||||
* Files that are valid with 0.3 are reported as being invalid.
|
* Files that are valid with 0.3 are reported as being invalid.
|
||||||
*/
|
*/
|
||||||
int WebPDecoderBuggyAlpha() {
|
int WebPDecoderBuggyAlpha(void) {
|
||||||
return WebPGetDecoderVersion()==0x0103;
|
return WebPGetDecoderVersion()==0x0103;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# install libimagequant
|
# install libimagequant
|
||||||
|
|
||||||
archive=libimagequant-2.10.1
|
archive=libimagequant-2.10.2
|
||||||
|
|
||||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz
|
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# install openjpeg
|
# install openjpeg
|
||||||
|
|
||||||
archive=openjpeg-2.1.2
|
archive=openjpeg-2.2.0
|
||||||
|
|
||||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz
|
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz
|
||||||
|
|
||||||
|
|
5
depends/termux.sh
Executable file
5
depends/termux.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
pkg -y install python python-dev ndk-sysroot clang make \
|
||||||
|
libjpeg-turbo-dev
|
||||||
|
|
2
docs/_templates/sidebarhelp.html
vendored
2
docs/_templates/sidebarhelp.html
vendored
|
@ -1,4 +1,4 @@
|
||||||
<h3>Need help?</h3>
|
<h3>Need help?</h3>
|
||||||
<p>
|
<p>
|
||||||
You can get help via IRC at <a href="irc://irc.freenode.net#pil">irc://irc.freenode.net#pil</a> or Stack Overflow <a href="https://stackoverflow.com/questions/tagged/pillow">here</a> and <a href="https://stackoverflow.com/questions/tagged/pil">here</a>. Please <a href="https://github.com/python-pillow/Pillow/issues/new">report issues on GitHub</a>.
|
You can get help via IRC at <a href="irc://irc.freenode.net#pil">irc://irc.freenode.net#pil</a> or Stack Overflow <a href="https://stackoverflow.com/questions/tagged/pillow">here</a> and <a href="https://stackoverflow.com/questions/tagged/python-imaging-library">here</a>. Please <a href="https://github.com/python-pillow/Pillow/issues/new">report issues on GitHub</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -146,6 +146,7 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
||||||
.. automethod:: PIL.Image.Image.seek
|
.. automethod:: PIL.Image.Image.seek
|
||||||
.. automethod:: PIL.Image.Image.show
|
.. automethod:: PIL.Image.Image.show
|
||||||
.. automethod:: PIL.Image.Image.split
|
.. automethod:: PIL.Image.Image.split
|
||||||
|
.. automethod:: PIL.Image.Image.getchannel
|
||||||
.. automethod:: PIL.Image.Image.tell
|
.. automethod:: PIL.Image.Image.tell
|
||||||
.. automethod:: PIL.Image.Image.thumbnail
|
.. automethod:: PIL.Image.Image.thumbnail
|
||||||
.. automethod:: PIL.Image.Image.tobitmap
|
.. automethod:: PIL.Image.Image.tobitmap
|
||||||
|
|
9
docs/releasenotes/4.3.0.rst
Normal file
9
docs/releasenotes/4.3.0.rst
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
4.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
Get One Channel From Image
|
||||||
|
==========================
|
||||||
|
|
||||||
|
New method :py:meth:`PIL.Image.Image.getchannel` added.
|
||||||
|
It returns single channel by index or name. For example,
|
||||||
|
``image.getchannel("A")`` will return alpha channel as seperate image.
|
|
@ -6,6 +6,7 @@ Release Notes
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
4.3.0
|
||||||
4.2.1
|
4.2.1
|
||||||
4.2.0
|
4.2.0
|
||||||
4.1.1
|
4.1.1
|
||||||
|
@ -21,5 +22,3 @@ Release Notes
|
||||||
3.0.0
|
3.0.0
|
||||||
2.8.0
|
2.8.0
|
||||||
2.7.0
|
2.7.0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
|
||||||
imDst->ysize != imSrc->ysize)
|
imDst->ysize != imSrc->ysize)
|
||||||
return ImagingError_Mismatch();
|
return ImagingError_Mismatch();
|
||||||
|
|
||||||
imOut = ImagingNew(imDst->mode, imDst->xsize, imDst->ysize);
|
imOut = ImagingNewDirty(imDst->mode, imDst->xsize, imDst->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,13 @@
|
||||||
#define CLIP(x) ((x) <= 0 ? 0 : (x) < 256 ? (x) : 255)
|
#define CLIP(x) ((x) <= 0 ? 0 : (x) < 256 ? (x) : 255)
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingGetBand(Imaging imIn, int band)
|
ImagingGetBand(Imaging imIn, int band)
|
||||||
{
|
{
|
||||||
|
@ -43,7 +50,7 @@ ImagingGetBand(Imaging imIn, int band)
|
||||||
if (imIn->bands == 2 && band == 1)
|
if (imIn->bands == 2 && band == 1)
|
||||||
band = 3;
|
band = 3;
|
||||||
|
|
||||||
imOut = ImagingNew("L", imIn->xsize, imIn->ysize);
|
imOut = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -51,7 +58,12 @@ ImagingGetBand(Imaging imIn, int band)
|
||||||
for (y = 0; y < imIn->ysize; y++) {
|
for (y = 0; y < imIn->ysize; y++) {
|
||||||
UINT8* in = (UINT8*) imIn->image[y] + band;
|
UINT8* in = (UINT8*) imIn->image[y] + band;
|
||||||
UINT8* out = imOut->image8[y];
|
UINT8* out = imOut->image8[y];
|
||||||
for (x = 0; x < imIn->xsize; x++) {
|
x = 0;
|
||||||
|
for (; x < imIn->xsize - 3; x += 4) {
|
||||||
|
*((UINT32*) (out + x)) = MAKE_UINT32(in[0], in[4], in[8], in[12]);
|
||||||
|
in += 16;
|
||||||
|
}
|
||||||
|
for (; x < imIn->xsize; x++) {
|
||||||
out[x] = *in;
|
out[x] = *in;
|
||||||
in += 4;
|
in += 4;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +72,101 @@ ImagingGetBand(Imaging imIn, int band)
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingSplit(Imaging imIn, Imaging bands[4])
|
||||||
|
{
|
||||||
|
int i, j, x, y;
|
||||||
|
|
||||||
|
/* Check arguments */
|
||||||
|
if (!imIn || imIn->type != IMAGING_TYPE_UINT8) {
|
||||||
|
(Imaging) ImagingError_ModeError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shortcuts */
|
||||||
|
if (imIn->bands == 1) {
|
||||||
|
bands[0] = ImagingCopy(imIn);
|
||||||
|
return imIn->bands;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < imIn->bands; i++) {
|
||||||
|
bands[i] = ImagingNew("L", imIn->xsize, imIn->ysize);
|
||||||
|
if ( ! bands[i]) {
|
||||||
|
for (j = 0; j < i; ++j) {
|
||||||
|
ImagingDelete(bands[j]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract bands from image */
|
||||||
|
if (imIn->bands == 2) {
|
||||||
|
for (y = 0; y < imIn->ysize; y++) {
|
||||||
|
UINT8* in = (UINT8*) imIn->image[y];
|
||||||
|
UINT8* out0 = bands[0]->image8[y];
|
||||||
|
UINT8* out1 = bands[1]->image8[y];
|
||||||
|
x = 0;
|
||||||
|
for (; x < imIn->xsize - 3; x += 4) {
|
||||||
|
*((UINT32*) (out0 + x)) = MAKE_UINT32(in[0], in[4], in[8], in[12]);
|
||||||
|
*((UINT32*) (out1 + x)) = MAKE_UINT32(in[0+3], in[4+3], in[8+3], in[12+3]);
|
||||||
|
in += 16;
|
||||||
|
}
|
||||||
|
for (; x < imIn->xsize; x++) {
|
||||||
|
out0[x] = in[0];
|
||||||
|
out1[x] = in[3];
|
||||||
|
in += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (imIn->bands == 3) {
|
||||||
|
for (y = 0; y < imIn->ysize; y++) {
|
||||||
|
UINT8* in = (UINT8*) imIn->image[y];
|
||||||
|
UINT8* out0 = bands[0]->image8[y];
|
||||||
|
UINT8* out1 = bands[1]->image8[y];
|
||||||
|
UINT8* out2 = bands[2]->image8[y];
|
||||||
|
x = 0;
|
||||||
|
for (; x < imIn->xsize - 3; x += 4) {
|
||||||
|
*((UINT32*) (out0 + x)) = MAKE_UINT32(in[0], in[4], in[8], in[12]);
|
||||||
|
*((UINT32*) (out1 + x)) = MAKE_UINT32(in[0+1], in[4+1], in[8+1], in[12+1]);
|
||||||
|
*((UINT32*) (out2 + x)) = MAKE_UINT32(in[0+2], in[4+2], in[8+2], in[12+2]);
|
||||||
|
in += 16;
|
||||||
|
}
|
||||||
|
for (; x < imIn->xsize; x++) {
|
||||||
|
out0[x] = in[0];
|
||||||
|
out1[x] = in[1];
|
||||||
|
out2[x] = in[2];
|
||||||
|
in += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (y = 0; y < imIn->ysize; y++) {
|
||||||
|
UINT8* in = (UINT8*) imIn->image[y];
|
||||||
|
UINT8* out0 = bands[0]->image8[y];
|
||||||
|
UINT8* out1 = bands[1]->image8[y];
|
||||||
|
UINT8* out2 = bands[2]->image8[y];
|
||||||
|
UINT8* out3 = bands[3]->image8[y];
|
||||||
|
x = 0;
|
||||||
|
for (; x < imIn->xsize - 3; x += 4) {
|
||||||
|
*((UINT32*) (out0 + x)) = MAKE_UINT32(in[0], in[4], in[8], in[12]);
|
||||||
|
*((UINT32*) (out1 + x)) = MAKE_UINT32(in[0+1], in[4+1], in[8+1], in[12+1]);
|
||||||
|
*((UINT32*) (out2 + x)) = MAKE_UINT32(in[0+2], in[4+2], in[8+2], in[12+2]);
|
||||||
|
*((UINT32*) (out3 + x)) = MAKE_UINT32(in[0+3], in[4+3], in[8+3], in[12+3]);
|
||||||
|
in += 16;
|
||||||
|
}
|
||||||
|
for (; x < imIn->xsize; x++) {
|
||||||
|
out0[x] = in[0];
|
||||||
|
out1[x] = in[1];
|
||||||
|
out2[x] = in[2];
|
||||||
|
out3[x] = in[3];
|
||||||
|
in += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imIn->bands;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingPutBand(Imaging imOut, Imaging imIn, int band)
|
ImagingPutBand(Imaging imOut, Imaging imIn, int band)
|
||||||
{
|
{
|
||||||
|
@ -127,3 +234,77 @@ ImagingFillBand(Imaging imOut, int band, int color)
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingMerge(const char* mode, Imaging bands[4])
|
||||||
|
{
|
||||||
|
int i, x, y;
|
||||||
|
int bandsCount = 0;
|
||||||
|
Imaging imOut;
|
||||||
|
Imaging firstBand;
|
||||||
|
|
||||||
|
firstBand = bands[0];
|
||||||
|
if ( ! firstBand) {
|
||||||
|
return (Imaging) ImagingError_ValueError("wrong number of bands");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
if ( ! bands[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (bands[i]->bands != 1) {
|
||||||
|
return (Imaging) ImagingError_ModeError();
|
||||||
|
}
|
||||||
|
if (bands[i]->xsize != firstBand->xsize
|
||||||
|
|| bands[i]->ysize != firstBand->ysize) {
|
||||||
|
return (Imaging) ImagingError_Mismatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bandsCount = i;
|
||||||
|
|
||||||
|
imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize);
|
||||||
|
if ( ! imOut)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (imOut->bands != bandsCount) {
|
||||||
|
ImagingDelete(imOut);
|
||||||
|
return (Imaging) ImagingError_ValueError("wrong number of bands");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imOut->bands == 1)
|
||||||
|
return ImagingCopy2(imOut, firstBand);
|
||||||
|
|
||||||
|
if (imOut->bands == 2) {
|
||||||
|
for (y = 0; y < imOut->ysize; y++) {
|
||||||
|
UINT8* in0 = bands[0]->image8[y];
|
||||||
|
UINT8* in1 = bands[1]->image8[y];
|
||||||
|
UINT32* out = (UINT32*) imOut->image32[y];
|
||||||
|
for (x = 0; x < imOut->xsize; x++) {
|
||||||
|
out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (imOut->bands == 3) {
|
||||||
|
for (y = 0; y < imOut->ysize; y++) {
|
||||||
|
UINT8* in0 = bands[0]->image8[y];
|
||||||
|
UINT8* in1 = bands[1]->image8[y];
|
||||||
|
UINT8* in2 = bands[2]->image8[y];
|
||||||
|
UINT32* out = (UINT32*) imOut->image32[y];
|
||||||
|
for (x = 0; x < imOut->xsize; x++) {
|
||||||
|
out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (imOut->bands == 4) {
|
||||||
|
for (y = 0; y < imOut->ysize; y++) {
|
||||||
|
UINT8* in0 = bands[0]->image8[y];
|
||||||
|
UINT8* in1 = bands[1]->image8[y];
|
||||||
|
UINT8* in2 = bands[2]->image8[y];
|
||||||
|
UINT8* in3 = bands[3]->image8[y];
|
||||||
|
UINT32* out = (UINT32*) imOut->image32[y];
|
||||||
|
for (x = 0; x < imOut->xsize; x++) {
|
||||||
|
out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imOut;
|
||||||
|
}
|
||||||
|
|
|
@ -815,6 +815,7 @@ static int decode_bcn(Imaging im, ImagingCodecState state, const UINT8* src, int
|
||||||
case NN: \
|
case NN: \
|
||||||
while (bytes >= SZ) { \
|
while (bytes >= SZ) { \
|
||||||
TY col[16]; \
|
TY col[16]; \
|
||||||
|
memset(col, 0, 16 * sizeof(col[0])); \
|
||||||
decode_bc##NN##_block(col, ptr); \
|
decode_bc##NN##_block(col, ptr); \
|
||||||
put_block(im, state, (const char *)col, sizeof(col[0]), C); \
|
put_block(im, state, (const char *)col, sizeof(col[0]), C); \
|
||||||
ptr += SZ; \
|
ptr += SZ; \
|
||||||
|
|
|
@ -40,7 +40,7 @@ ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha)
|
||||||
else if (alpha == 1.0)
|
else if (alpha == 1.0)
|
||||||
return ImagingCopy(imIn2);
|
return ImagingCopy(imIn2);
|
||||||
|
|
||||||
imOut = ImagingNew(imIn1->mode, imIn1->xsize, imIn1->ysize);
|
imOut = ImagingNewDirty(imIn1->mode, imIn1->xsize, imIn1->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,7 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n)
|
||||||
strcmp(imIn->mode, "La") == 0))
|
strcmp(imIn->mode, "La") == 0))
|
||||||
return ImagingError_ModeError();
|
return ImagingError_ModeError();
|
||||||
|
|
||||||
imTransposed = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize);
|
imTransposed = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
|
||||||
if (!imTransposed)
|
if (!imTransposed)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -1035,7 +1035,7 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode)
|
||||||
else
|
else
|
||||||
return (Imaging) ImagingError_ValueError("conversion not supported");
|
return (Imaging) ImagingError_ValueError("conversion not supported");
|
||||||
|
|
||||||
imOut = ImagingNew2(mode, imOut, imIn);
|
imOut = ImagingNew2Dirty(mode, imOut, imIn);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1073,7 +1073,7 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
|
||||||
if (!palette)
|
if (!palette)
|
||||||
return (Imaging) ImagingError_ValueError("no palette");
|
return (Imaging) ImagingError_ValueError("no palette");
|
||||||
|
|
||||||
imOut = ImagingNew2("P", imOut, imIn);
|
imOut = ImagingNew2Dirty("P", imOut, imIn);
|
||||||
if (!imOut) {
|
if (!imOut) {
|
||||||
if (palette != inpalette)
|
if (palette != inpalette)
|
||||||
ImagingPaletteDelete(palette);
|
ImagingPaletteDelete(palette);
|
||||||
|
@ -1211,7 +1211,7 @@ tobilevel(Imaging imOut, Imaging imIn, int dither)
|
||||||
if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0)
|
if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0)
|
||||||
return (Imaging) ImagingError_ValueError("conversion not supported");
|
return (Imaging) ImagingError_ValueError("conversion not supported");
|
||||||
|
|
||||||
imOut = ImagingNew2("1", imOut, imIn);
|
imOut = ImagingNew2Dirty("1", imOut, imIn);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1344,7 +1344,7 @@ convert(Imaging imOut, Imaging imIn, const char *mode,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
imOut = ImagingNew2(mode, imOut, imIn);
|
imOut = ImagingNew2Dirty(mode, imOut, imIn);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1407,7 +1407,7 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
|
||||||
g = b = r;
|
g = b = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
imOut = ImagingNew2(mode, imOut, imIn);
|
imOut = ImagingNew2Dirty(mode, imOut, imIn);
|
||||||
if (!imOut){
|
if (!imOut){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ _copy(Imaging imOut, Imaging imIn)
|
||||||
if (!imIn)
|
if (!imIn)
|
||||||
return (Imaging) ImagingError_ValueError(NULL);
|
return (Imaging) ImagingError_ValueError(NULL);
|
||||||
|
|
||||||
imOut = ImagingNew2(imIn->mode, imOut, imIn);
|
imOut = ImagingNew2Dirty(imIn->mode, imOut, imIn);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1)
|
||||||
if (ysize < 0)
|
if (ysize < 0)
|
||||||
ysize = 0;
|
ysize = 0;
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ ImagingFillLinearGradient(const char *mode)
|
||||||
return (Imaging) ImagingError_ModeError();
|
return (Imaging) ImagingError_ModeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
im = ImagingNew(mode, 256, 256);
|
im = ImagingNewDirty(mode, 256, 256);
|
||||||
if (!im) {
|
if (!im) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ ImagingFillRadialGradient(const char *mode)
|
||||||
return (Imaging) ImagingError_ModeError();
|
return (Imaging) ImagingError_ModeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
im = ImagingNew(mode, 256, 256);
|
im = ImagingNewDirty(mode, 256, 256);
|
||||||
if (!im) {
|
if (!im) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
|
||||||
{
|
{
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
ImagingSectionCookie cookie;
|
||||||
|
|
||||||
if (xmargin < 0 && ymargin < 0)
|
if (xmargin < 0 && ymargin < 0)
|
||||||
return (Imaging) ImagingError_ValueError("bad kernel size");
|
return (Imaging) ImagingError_ValueError("bad kernel size");
|
||||||
|
@ -60,11 +61,13 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
|
||||||
EXPAND_LINE(type, image, imIn->ysize-1, ymargin+imIn->ysize+y);\
|
EXPAND_LINE(type, image, imIn->ysize-1, ymargin+imIn->ysize+y);\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImagingSectionEnter(&cookie);
|
||||||
if (imIn->image8) {
|
if (imIn->image8) {
|
||||||
EXPAND(UINT8, image8);
|
EXPAND(UINT8, image8);
|
||||||
} else {
|
} else {
|
||||||
EXPAND(INT32, image32);
|
EXPAND(INT32, image32);
|
||||||
}
|
}
|
||||||
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
ImagingCopyInfo(imOut, imIn);
|
ImagingCopyInfo(imOut, imIn);
|
||||||
|
|
||||||
|
@ -78,6 +81,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
int x, y;
|
int x, y;
|
||||||
FLOAT32 sum;
|
FLOAT32 sum;
|
||||||
|
ImagingSectionCookie cookie;
|
||||||
|
|
||||||
if (!im || strcmp(im->mode, "L") != 0)
|
if (!im || strcmp(im->mode, "L") != 0)
|
||||||
return (Imaging) ImagingError_ModeError();
|
return (Imaging) ImagingError_ModeError();
|
||||||
|
@ -92,6 +96,9 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
// Add one time for rounding
|
||||||
|
offset += 0.5;
|
||||||
|
|
||||||
/* brute force kernel implementations */
|
/* brute force kernel implementations */
|
||||||
#define KERNEL3x3(image, kernel, d) ( \
|
#define KERNEL3x3(image, kernel, d) ( \
|
||||||
(int) image[y+1][x-d] * kernel[0] + \
|
(int) image[y+1][x-d] * kernel[0] + \
|
||||||
|
@ -131,6 +138,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
||||||
(int) image[y-2][x+d] * kernel[23] + \
|
(int) image[y-2][x+d] * kernel[23] + \
|
||||||
(int) image[y-2][x+d+d] * kernel[24])
|
(int) image[y-2][x+d+d] * kernel[24])
|
||||||
|
|
||||||
|
ImagingSectionEnter(&cookie);
|
||||||
if (xsize == 3) {
|
if (xsize == 3) {
|
||||||
/* 3x3 kernel. */
|
/* 3x3 kernel. */
|
||||||
for (x = 0; x < im->xsize; x++)
|
for (x = 0; x < im->xsize; x++)
|
||||||
|
@ -174,6 +182,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
||||||
for (x = 0; x < im->xsize; x++)
|
for (x = 0; x < im->xsize; x++)
|
||||||
imOut->image8[y][x] = im->image8[y][x];
|
imOut->image8[y][x] = im->image8[y][x];
|
||||||
}
|
}
|
||||||
|
ImagingSectionLeave(&cookie);
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,11 +159,11 @@ struct ImagingPaletteInstance {
|
||||||
extern int ImagingNewCount;
|
extern int ImagingNewCount;
|
||||||
|
|
||||||
extern Imaging ImagingNew(const char* mode, int xsize, int ysize);
|
extern Imaging ImagingNew(const char* mode, int xsize, int ysize);
|
||||||
extern Imaging ImagingNew2(const char* mode, Imaging imOut, Imaging imIn);
|
extern Imaging ImagingNewDirty(const char* mode, int xsize, int ysize);
|
||||||
|
extern Imaging ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn);
|
||||||
extern void ImagingDelete(Imaging im);
|
extern void ImagingDelete(Imaging im);
|
||||||
|
|
||||||
extern Imaging ImagingNewBlock(const char* mode, int xsize, int ysize);
|
extern Imaging ImagingNewBlock(const char* mode, int xsize, int ysize);
|
||||||
extern Imaging ImagingNewArray(const char* mode, int xsize, int ysize);
|
|
||||||
extern Imaging ImagingNewMap(const char* filename, int readonly,
|
extern Imaging ImagingNewMap(const char* filename, int readonly,
|
||||||
const char* mode, int xsize, int ysize);
|
const char* mode, int xsize, int ysize);
|
||||||
|
|
||||||
|
@ -172,7 +172,6 @@ extern Imaging ImagingNewPrologue(const char *mode,
|
||||||
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 Imaging ImagingNewEpilogue(Imaging im);
|
|
||||||
|
|
||||||
extern void ImagingCopyInfo(Imaging destination, Imaging source);
|
extern void ImagingCopyInfo(Imaging destination, Imaging source);
|
||||||
|
|
||||||
|
@ -267,6 +266,8 @@ 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 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,
|
||||||
|
@ -290,7 +291,7 @@ 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);
|
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 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,
|
||||||
|
|
|
@ -32,7 +32,7 @@ ImagingConvertMatrix(Imaging im, const char *mode, float m[])
|
||||||
|
|
||||||
if (strcmp(mode, "L") == 0 && im->bands == 3) {
|
if (strcmp(mode, "L") == 0 && im->bands == 3) {
|
||||||
|
|
||||||
imOut = ImagingNew("L", im->xsize, im->ysize);
|
imOut = ImagingNewDirty("L", im->xsize, im->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ ImagingConvertMatrix(Imaging im, const char *mode, float m[])
|
||||||
|
|
||||||
} else if (strlen(mode) == 3 && im->bands == 3) {
|
} else if (strlen(mode) == 3 && im->bands == 3) {
|
||||||
|
|
||||||
imOut = ImagingNew(mode, im->xsize, im->ysize);
|
imOut = ImagingNewDirty(mode, im->xsize, im->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ ImagingNegative(Imaging im)
|
||||||
if (!im)
|
if (!im)
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ ImagingOffset(Imaging im, int xoffset, int yoffset)
|
||||||
if (!im)
|
if (!im)
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -559,8 +559,8 @@ static struct {
|
||||||
/* true colour w. padding */
|
/* true colour w. padding */
|
||||||
{"RGBX", "RGBX", 32, copy4},
|
{"RGBX", "RGBX", 32, copy4},
|
||||||
{"RGBX", "RGBX;L", 32, packRGBXL},
|
{"RGBX", "RGBX;L", 32, packRGBXL},
|
||||||
{"RGBX", "RGB", 32, ImagingPackRGB},
|
{"RGBX", "RGB", 24, ImagingPackRGB},
|
||||||
{"RGBX", "BGR", 32, ImagingPackBGR},
|
{"RGBX", "BGR", 24, ImagingPackBGR},
|
||||||
{"RGBX", "BGRX", 32, ImagingPackBGRX},
|
{"RGBX", "BGRX", 32, ImagingPackBGRX},
|
||||||
{"RGBX", "XBGR", 32, ImagingPackXBGR},
|
{"RGBX", "XBGR", 32, ImagingPackXBGR},
|
||||||
{"RGBX", "R", 8, band0},
|
{"RGBX", "R", 8, band0},
|
||||||
|
|
|
@ -5,6 +5,13 @@
|
||||||
|
|
||||||
#define ROUND_UP(f) ((int) ((f) >= 0.0 ? (f) + 0.5F : (f) - 0.5F))
|
#define ROUND_UP(f) ((int) ((f) >= 0.0 ? (f) + 0.5F : (f) - 0.5F))
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
struct filter {
|
struct filter {
|
||||||
double (*filter)(double x);
|
double (*filter)(double x);
|
||||||
double support;
|
double support;
|
||||||
|
@ -127,16 +134,16 @@ static inline UINT8 clip8(int in)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
precompute_coeffs(int inSize, int outSize, struct filter *filterp,
|
precompute_coeffs(int inSize, float in0, float in1, int outSize,
|
||||||
int **xboundsp, double **kkp) {
|
struct filter *filterp, int **boundsp, double **kkp) {
|
||||||
double support, scale, filterscale;
|
double support, scale, filterscale;
|
||||||
double center, ww, ss;
|
double center, ww, ss;
|
||||||
int xx, x, kmax, xmin, xmax;
|
int xx, x, ksize, xmin, xmax;
|
||||||
int *xbounds;
|
int *bounds;
|
||||||
double *kk, *k;
|
double *kk, *k;
|
||||||
|
|
||||||
/* prepare for horizontal stretch */
|
/* prepare for horizontal stretch */
|
||||||
filterscale = scale = (double) inSize / outSize;
|
filterscale = scale = (double) (in1 - in0) / outSize;
|
||||||
if (filterscale < 1.0) {
|
if (filterscale < 1.0) {
|
||||||
filterscale = 1.0;
|
filterscale = 1.0;
|
||||||
}
|
}
|
||||||
|
@ -145,27 +152,32 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp,
|
||||||
support = filterp->support * filterscale;
|
support = filterp->support * filterscale;
|
||||||
|
|
||||||
/* maximum number of coeffs */
|
/* maximum number of coeffs */
|
||||||
kmax = (int) ceil(support) * 2 + 1;
|
ksize = (int) ceil(support) * 2 + 1;
|
||||||
|
|
||||||
// check for overflow
|
// check for overflow
|
||||||
if (outSize > INT_MAX / (kmax * sizeof(double)))
|
if (outSize > INT_MAX / (ksize * sizeof(double))) {
|
||||||
|
ImagingError_MemoryError();
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* coefficient buffer */
|
/* coefficient buffer */
|
||||||
/* malloc check ok, overflow checked above */
|
/* malloc check ok, overflow checked above */
|
||||||
kk = malloc(outSize * kmax * sizeof(double));
|
kk = malloc(outSize * ksize * sizeof(double));
|
||||||
if ( ! kk)
|
if ( ! kk) {
|
||||||
|
ImagingError_MemoryError();
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* malloc check ok, kmax*sizeof(double) > 2*sizeof(int) */
|
/* malloc check ok, ksize*sizeof(double) > 2*sizeof(int) */
|
||||||
xbounds = malloc(outSize * 2 * sizeof(int));
|
bounds = malloc(outSize * 2 * sizeof(int));
|
||||||
if ( ! xbounds) {
|
if ( ! bounds) {
|
||||||
free(kk);
|
free(kk);
|
||||||
|
ImagingError_MemoryError();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (xx = 0; xx < outSize; xx++) {
|
for (xx = 0; xx < outSize; xx++) {
|
||||||
center = (xx + 0.5) * scale;
|
center = in0 + (xx + 0.5) * scale;
|
||||||
ww = 0.0;
|
ww = 0.0;
|
||||||
ss = 1.0 / filterscale;
|
ss = 1.0 / filterscale;
|
||||||
// Round the value
|
// Round the value
|
||||||
|
@ -177,7 +189,7 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp,
|
||||||
if (xmax > inSize)
|
if (xmax > inSize)
|
||||||
xmax = inSize;
|
xmax = inSize;
|
||||||
xmax -= xmin;
|
xmax -= xmin;
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
for (x = 0; x < xmax; x++) {
|
for (x = 0; x < xmax; x++) {
|
||||||
double w = filterp->filter((x + xmin - center + 0.5) * ss);
|
double w = filterp->filter((x + xmin - center + 0.5) * ss);
|
||||||
k[x] = w;
|
k[x] = w;
|
||||||
|
@ -188,185 +200,138 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp,
|
||||||
k[x] /= ww;
|
k[x] /= ww;
|
||||||
}
|
}
|
||||||
// Remaining values should stay empty if they are used despite of xmax.
|
// Remaining values should stay empty if they are used despite of xmax.
|
||||||
for (; x < kmax; x++) {
|
for (; x < ksize; x++) {
|
||||||
k[x] = 0;
|
k[x] = 0;
|
||||||
}
|
}
|
||||||
xbounds[xx * 2 + 0] = xmin;
|
bounds[xx * 2 + 0] = xmin;
|
||||||
xbounds[xx * 2 + 1] = xmax;
|
bounds[xx * 2 + 1] = xmax;
|
||||||
}
|
}
|
||||||
*xboundsp = xbounds;
|
*boundsp = bounds;
|
||||||
*kkp = kk;
|
*kkp = kk;
|
||||||
return kmax;
|
return ksize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
void
|
||||||
normalize_coeffs_8bpc(int outSize, int kmax, double *prekk, INT32 **kkp)
|
normalize_coeffs_8bpc(int outSize, int ksize, double *prekk)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
INT32 *kk;
|
INT32 *kk;
|
||||||
|
|
||||||
/* malloc check ok, overflow checked in precompute_coeffs */
|
// use the same buffer for normalized coefficients
|
||||||
kk = malloc(outSize * kmax * sizeof(INT32));
|
kk = (INT32 *) prekk;
|
||||||
if ( ! kk) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (x = 0; x < outSize * kmax; x++) {
|
for (x = 0; x < outSize * ksize; x++) {
|
||||||
if (prekk[x] < 0) {
|
if (prekk[x] < 0) {
|
||||||
kk[x] = (int) (-0.5 + prekk[x] * (1 << PRECISION_BITS));
|
kk[x] = (int) (-0.5 + prekk[x] * (1 << PRECISION_BITS));
|
||||||
} else {
|
} else {
|
||||||
kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS));
|
kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*kkp = kk;
|
|
||||||
return kmax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
void
|
||||||
ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset,
|
||||||
|
int ksize, int *bounds, double *prekk)
|
||||||
{
|
{
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
Imaging imOut;
|
|
||||||
int ss0, ss1, ss2, ss3;
|
int ss0, ss1, ss2, ss3;
|
||||||
int xx, yy, x, kmax, xmin, xmax;
|
int xx, yy, x, xmin, xmax;
|
||||||
int *xbounds;
|
|
||||||
INT32 *k, *kk;
|
INT32 *k, *kk;
|
||||||
double *prekk;
|
|
||||||
|
|
||||||
kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &prekk);
|
// use the same buffer for normalized coefficients
|
||||||
if ( ! kmax) {
|
kk = (INT32 *) prekk;
|
||||||
return (Imaging) ImagingError_MemoryError();
|
normalize_coeffs_8bpc(imOut->xsize, ksize, prekk);
|
||||||
}
|
|
||||||
|
|
||||||
kmax = normalize_coeffs_8bpc(xsize, kmax, prekk, &kk);
|
|
||||||
free(prekk);
|
|
||||||
if ( ! kmax) {
|
|
||||||
free(xbounds);
|
|
||||||
return (Imaging) ImagingError_MemoryError();
|
|
||||||
}
|
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, xsize, imIn->ysize);
|
|
||||||
if ( ! imOut) {
|
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
if (imIn->image8) {
|
if (imIn->image8) {
|
||||||
for (yy = 0; yy < imOut->ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
for (xx = 0; xx < xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
xmin = xbounds[xx * 2 + 0];
|
xmin = bounds[xx * 2 + 0];
|
||||||
xmax = xbounds[xx * 2 + 1];
|
xmax = bounds[xx * 2 + 1];
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
ss0 = 1 << (PRECISION_BITS -1);
|
ss0 = 1 << (PRECISION_BITS -1);
|
||||||
for (x = 0; x < xmax; x++)
|
for (x = 0; x < xmax; x++)
|
||||||
ss0 += ((UINT8) imIn->image8[yy][x + xmin]) * k[x];
|
ss0 += ((UINT8) imIn->image8[yy + offset][x + xmin]) * k[x];
|
||||||
imOut->image8[yy][xx] = clip8(ss0);
|
imOut->image8[yy][xx] = clip8(ss0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (imIn->type == IMAGING_TYPE_UINT8) {
|
} else if (imIn->type == IMAGING_TYPE_UINT8) {
|
||||||
if (imIn->bands == 2) {
|
if (imIn->bands == 2) {
|
||||||
for (yy = 0; yy < imOut->ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
for (xx = 0; xx < xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
xmin = xbounds[xx * 2 + 0];
|
xmin = bounds[xx * 2 + 0];
|
||||||
xmax = xbounds[xx * 2 + 1];
|
xmax = bounds[xx * 2 + 1];
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
ss0 = ss3 = 1 << (PRECISION_BITS -1);
|
ss0 = ss3 = 1 << (PRECISION_BITS -1);
|
||||||
for (x = 0; x < xmax; x++) {
|
for (x = 0; x < xmax; x++) {
|
||||||
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
|
ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
|
||||||
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
|
ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x];
|
||||||
}
|
}
|
||||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
clip8(ss0), 0, 0, clip8(ss3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (imIn->bands == 3) {
|
} else if (imIn->bands == 3) {
|
||||||
for (yy = 0; yy < imOut->ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
for (xx = 0; xx < xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
xmin = xbounds[xx * 2 + 0];
|
xmin = bounds[xx * 2 + 0];
|
||||||
xmax = xbounds[xx * 2 + 1];
|
xmax = bounds[xx * 2 + 1];
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
|
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
|
||||||
for (x = 0; x < xmax; x++) {
|
for (x = 0; x < xmax; x++) {
|
||||||
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
|
ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
|
||||||
ss1 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 1]) * k[x];
|
ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x];
|
||||||
ss2 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 2]) * k[x];
|
ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x];
|
||||||
}
|
}
|
||||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
clip8(ss0), clip8(ss1), clip8(ss2), 0);
|
||||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (yy = 0; yy < imOut->ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
for (xx = 0; xx < xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
xmin = xbounds[xx * 2 + 0];
|
xmin = bounds[xx * 2 + 0];
|
||||||
xmax = xbounds[xx * 2 + 1];
|
xmax = bounds[xx * 2 + 1];
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
|
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
|
||||||
for (x = 0; x < xmax; x++) {
|
for (x = 0; x < xmax; x++) {
|
||||||
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
|
ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
|
||||||
ss1 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 1]) * k[x];
|
ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x];
|
||||||
ss2 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 2]) * k[x];
|
ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x];
|
||||||
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
|
ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x];
|
||||||
}
|
}
|
||||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
|
||||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
|
||||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return imOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
void
|
||||||
ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset,
|
||||||
|
int ksize, int *bounds, double *prekk)
|
||||||
{
|
{
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
Imaging imOut;
|
|
||||||
int ss0, ss1, ss2, ss3;
|
int ss0, ss1, ss2, ss3;
|
||||||
int xx, yy, y, kmax, ymin, ymax;
|
int xx, yy, y, ymin, ymax;
|
||||||
int *xbounds;
|
|
||||||
INT32 *k, *kk;
|
INT32 *k, *kk;
|
||||||
double *prekk;
|
|
||||||
|
|
||||||
kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &prekk);
|
// use the same buffer for normalized coefficients
|
||||||
if ( ! kmax) {
|
kk = (INT32 *) prekk;
|
||||||
return (Imaging) ImagingError_MemoryError();
|
normalize_coeffs_8bpc(imOut->ysize, ksize, prekk);
|
||||||
}
|
|
||||||
|
|
||||||
kmax = normalize_coeffs_8bpc(ysize, kmax, prekk, &kk);
|
|
||||||
free(prekk);
|
|
||||||
if ( ! kmax) {
|
|
||||||
free(xbounds);
|
|
||||||
return (Imaging) ImagingError_MemoryError();
|
|
||||||
}
|
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
|
||||||
if ( ! imOut) {
|
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
if (imIn->image8) {
|
if (imIn->image8) {
|
||||||
for (yy = 0; yy < ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
k = &kk[yy * kmax];
|
k = &kk[yy * ksize];
|
||||||
ymin = xbounds[yy * 2 + 0];
|
ymin = bounds[yy * 2 + 0];
|
||||||
ymax = xbounds[yy * 2 + 1];
|
ymax = bounds[yy * 2 + 1];
|
||||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
ss0 = 1 << (PRECISION_BITS -1);
|
ss0 = 1 << (PRECISION_BITS -1);
|
||||||
for (y = 0; y < ymax; y++)
|
for (y = 0; y < ymax; y++)
|
||||||
|
@ -376,25 +341,25 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||||
}
|
}
|
||||||
} else if (imIn->type == IMAGING_TYPE_UINT8) {
|
} else if (imIn->type == IMAGING_TYPE_UINT8) {
|
||||||
if (imIn->bands == 2) {
|
if (imIn->bands == 2) {
|
||||||
for (yy = 0; yy < ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
k = &kk[yy * kmax];
|
k = &kk[yy * ksize];
|
||||||
ymin = xbounds[yy * 2 + 0];
|
ymin = bounds[yy * 2 + 0];
|
||||||
ymax = xbounds[yy * 2 + 1];
|
ymax = bounds[yy * 2 + 1];
|
||||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
ss0 = ss3 = 1 << (PRECISION_BITS -1);
|
ss0 = ss3 = 1 << (PRECISION_BITS -1);
|
||||||
for (y = 0; y < ymax; y++) {
|
for (y = 0; y < ymax; y++) {
|
||||||
ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
|
ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
|
||||||
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
||||||
}
|
}
|
||||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
clip8(ss0), 0, 0, clip8(ss3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (imIn->bands == 3) {
|
} else if (imIn->bands == 3) {
|
||||||
for (yy = 0; yy < ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
k = &kk[yy * kmax];
|
k = &kk[yy * ksize];
|
||||||
ymin = xbounds[yy * 2 + 0];
|
ymin = bounds[yy * 2 + 0];
|
||||||
ymax = xbounds[yy * 2 + 1];
|
ymax = bounds[yy * 2 + 1];
|
||||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
|
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
|
||||||
for (y = 0; y < ymax; y++) {
|
for (y = 0; y < ymax; y++) {
|
||||||
|
@ -402,16 +367,15 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||||
ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
|
ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
|
||||||
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
||||||
}
|
}
|
||||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
clip8(ss0), clip8(ss1), clip8(ss2), 0);
|
||||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (yy = 0; yy < ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
k = &kk[yy * kmax];
|
k = &kk[yy * ksize];
|
||||||
ymin = xbounds[yy * 2 + 0];
|
ymin = bounds[yy * 2 + 0];
|
||||||
ymax = xbounds[yy * 2 + 1];
|
ymax = bounds[yy * 2 + 1];
|
||||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
|
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
|
||||||
for (y = 0; y < ymax; y++) {
|
for (y = 0; y < ymax; y++) {
|
||||||
|
@ -420,55 +384,36 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||||
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
||||||
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
||||||
}
|
}
|
||||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
|
||||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
|
||||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return imOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
void
|
||||||
ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
|
ImagingResampleHorizontal_32bpc(Imaging imOut, Imaging imIn, int offset,
|
||||||
|
int ksize, int *bounds, double *kk)
|
||||||
{
|
{
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
Imaging imOut;
|
|
||||||
double ss;
|
double ss;
|
||||||
int xx, yy, x, kmax, xmin, xmax;
|
int xx, yy, x, xmin, xmax;
|
||||||
int *xbounds;
|
double *k;
|
||||||
double *k, *kk;
|
|
||||||
|
|
||||||
kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &kk);
|
|
||||||
if ( ! kmax) {
|
|
||||||
return (Imaging) ImagingError_MemoryError();
|
|
||||||
}
|
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, xsize, imIn->ysize);
|
|
||||||
if ( ! imOut) {
|
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
switch(imIn->type) {
|
switch(imIn->type) {
|
||||||
case IMAGING_TYPE_INT32:
|
case IMAGING_TYPE_INT32:
|
||||||
for (yy = 0; yy < imOut->ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
for (xx = 0; xx < xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
xmin = xbounds[xx * 2 + 0];
|
xmin = bounds[xx * 2 + 0];
|
||||||
xmax = xbounds[xx * 2 + 1];
|
xmax = bounds[xx * 2 + 1];
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
ss = 0.0;
|
ss = 0.0;
|
||||||
for (x = 0; x < xmax; x++)
|
for (x = 0; x < xmax; x++)
|
||||||
ss += IMAGING_PIXEL_I(imIn, x + xmin, yy) * k[x];
|
ss += IMAGING_PIXEL_I(imIn, x + xmin, yy + offset) * k[x];
|
||||||
IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
|
IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,55 +421,38 @@ ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
|
||||||
|
|
||||||
case IMAGING_TYPE_FLOAT32:
|
case IMAGING_TYPE_FLOAT32:
|
||||||
for (yy = 0; yy < imOut->ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
for (xx = 0; xx < xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
xmin = xbounds[xx * 2 + 0];
|
xmin = bounds[xx * 2 + 0];
|
||||||
xmax = xbounds[xx * 2 + 1];
|
xmax = bounds[xx * 2 + 1];
|
||||||
k = &kk[xx * kmax];
|
k = &kk[xx * ksize];
|
||||||
ss = 0.0;
|
ss = 0.0;
|
||||||
for (x = 0; x < xmax; x++)
|
for (x = 0; x < xmax; x++)
|
||||||
ss += IMAGING_PIXEL_F(imIn, x + xmin, yy) * k[x];
|
ss += IMAGING_PIXEL_F(imIn, x + xmin, yy + offset) * k[x];
|
||||||
IMAGING_PIXEL_F(imOut, xx, yy) = ss;
|
IMAGING_PIXEL_F(imOut, xx, yy) = ss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return imOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
void
|
||||||
ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
|
ImagingResampleVertical_32bpc(Imaging imOut, Imaging imIn, int offset,
|
||||||
|
int ksize, int *bounds, double *kk)
|
||||||
{
|
{
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
Imaging imOut;
|
|
||||||
double ss;
|
double ss;
|
||||||
int xx, yy, y, kmax, ymin, ymax;
|
int xx, yy, y, ymin, ymax;
|
||||||
int *xbounds;
|
double *k;
|
||||||
double *k, *kk;
|
|
||||||
|
|
||||||
kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &kk);
|
|
||||||
if ( ! kmax) {
|
|
||||||
return (Imaging) ImagingError_MemoryError();
|
|
||||||
}
|
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
|
||||||
if ( ! imOut) {
|
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
switch(imIn->type) {
|
switch(imIn->type) {
|
||||||
case IMAGING_TYPE_INT32:
|
case IMAGING_TYPE_INT32:
|
||||||
for (yy = 0; yy < ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
ymin = xbounds[yy * 2 + 0];
|
ymin = bounds[yy * 2 + 0];
|
||||||
ymax = xbounds[yy * 2 + 1];
|
ymax = bounds[yy * 2 + 1];
|
||||||
k = &kk[yy * kmax];
|
k = &kk[yy * ksize];
|
||||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
ss = 0.0;
|
ss = 0.0;
|
||||||
for (y = 0; y < ymax; y++)
|
for (y = 0; y < ymax; y++)
|
||||||
|
@ -535,10 +463,10 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IMAGING_TYPE_FLOAT32:
|
case IMAGING_TYPE_FLOAT32:
|
||||||
for (yy = 0; yy < ysize; yy++) {
|
for (yy = 0; yy < imOut->ysize; yy++) {
|
||||||
ymin = xbounds[yy * 2 + 0];
|
ymin = bounds[yy * 2 + 0];
|
||||||
ymax = xbounds[yy * 2 + 1];
|
ymax = bounds[yy * 2 + 1];
|
||||||
k = &kk[yy * kmax];
|
k = &kk[yy * ksize];
|
||||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||||
ss = 0.0;
|
ss = 0.0;
|
||||||
for (y = 0; y < ymax; y++)
|
for (y = 0; y < ymax; y++)
|
||||||
|
@ -548,22 +476,27 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
free(kk);
|
|
||||||
free(xbounds);
|
|
||||||
return imOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*ResampleFunction)(Imaging imOut, Imaging imIn, int offset,
|
||||||
|
int ksize, int *bounds, double *kk);
|
||||||
|
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
|
ImagingResampleInner(Imaging imIn, int xsize, int ysize,
|
||||||
|
struct filter *filterp, float box[4],
|
||||||
|
ResampleFunction ResampleHorizontal,
|
||||||
|
ResampleFunction ResampleVertical);
|
||||||
|
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4])
|
||||||
{
|
{
|
||||||
Imaging imTemp = NULL;
|
|
||||||
Imaging imOut = NULL;
|
|
||||||
struct filter *filterp;
|
struct filter *filterp;
|
||||||
Imaging (*ResampleHorizontal)(Imaging imIn, int xsize, struct filter *filterp);
|
ResampleFunction ResampleHorizontal;
|
||||||
Imaging (*ResampleVertical)(Imaging imIn, int xsize, struct filter *filterp);
|
ResampleFunction ResampleVertical;
|
||||||
|
|
||||||
if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
|
if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
|
||||||
return (Imaging) ImagingError_ModeError();
|
return (Imaging) ImagingError_ModeError();
|
||||||
|
@ -612,24 +545,93 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* two-pass resize, first pass */
|
return ImagingResampleInner(imIn, xsize, ysize, filterp, box,
|
||||||
if (imIn->xsize != xsize) {
|
ResampleHorizontal, ResampleVertical);
|
||||||
imTemp = ResampleHorizontal(imIn, xsize, filterp);
|
}
|
||||||
if ( ! imTemp)
|
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingResampleInner(Imaging imIn, int xsize, int ysize,
|
||||||
|
struct filter *filterp, float box[4],
|
||||||
|
ResampleFunction ResampleHorizontal,
|
||||||
|
ResampleFunction ResampleVertical)
|
||||||
|
{
|
||||||
|
Imaging imTemp = NULL;
|
||||||
|
Imaging imOut = NULL;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int yroi_min, yroi_max;
|
||||||
|
int ksize_horiz, ksize_vert;
|
||||||
|
int *bounds_horiz, *bounds_vert;
|
||||||
|
double *kk_horiz, *kk_vert;
|
||||||
|
|
||||||
|
ksize_horiz = precompute_coeffs(imIn->xsize, box[0], box[2], xsize,
|
||||||
|
filterp, &bounds_horiz, &kk_horiz);
|
||||||
|
if ( ! ksize_horiz) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksize_vert = precompute_coeffs(imIn->ysize, box[1], box[3], ysize,
|
||||||
|
filterp, &bounds_vert, &kk_vert);
|
||||||
|
if ( ! ksize_vert) {
|
||||||
|
free(bounds_horiz);
|
||||||
|
free(kk_horiz);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First used row in the source image
|
||||||
|
yroi_min = bounds_vert[0];
|
||||||
|
// Last used row in the source image
|
||||||
|
yroi_max = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1];
|
||||||
|
|
||||||
|
|
||||||
|
/* two-pass resize, first pass */
|
||||||
|
if (box[0] || box[2] != xsize) {
|
||||||
|
// Shift bounds for vertical pass
|
||||||
|
for (i = 0; i < ysize; i++) {
|
||||||
|
bounds_vert[i * 2] -= yroi_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
imTemp = ImagingNewDirty(imIn->mode, xsize, yroi_max - yroi_min);
|
||||||
|
if (imTemp) {
|
||||||
|
ResampleHorizontal(imTemp, imIn, yroi_min,
|
||||||
|
ksize_horiz, bounds_horiz, kk_horiz);
|
||||||
|
}
|
||||||
|
free(bounds_horiz);
|
||||||
|
free(kk_horiz);
|
||||||
|
if ( ! imTemp) {
|
||||||
|
free(bounds_vert);
|
||||||
|
free(kk_vert);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
imOut = imIn = imTemp;
|
imOut = imIn = imTemp;
|
||||||
|
} else {
|
||||||
|
// Free in any case
|
||||||
|
free(bounds_horiz);
|
||||||
|
free(kk_horiz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* second pass */
|
/* second pass */
|
||||||
if (imIn->ysize != ysize) {
|
if (box[1] || box[3] != ysize) {
|
||||||
|
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
|
||||||
|
if (imOut) {
|
||||||
/* imIn can be the original image or horizontally resampled one */
|
/* imIn can be the original image or horizontally resampled one */
|
||||||
imOut = ResampleVertical(imIn, ysize, filterp);
|
ResampleVertical(imOut, imIn, 0,
|
||||||
|
ksize_vert, bounds_vert, kk_vert);
|
||||||
|
}
|
||||||
/* it's safe to call ImagingDelete with empty value
|
/* it's safe to call ImagingDelete with empty value
|
||||||
if there was no previous step. */
|
if previous step was not performed. */
|
||||||
ImagingDelete(imTemp);
|
ImagingDelete(imTemp);
|
||||||
if ( ! imOut)
|
free(bounds_vert);
|
||||||
|
free(kk_vert);
|
||||||
|
if ( ! imOut) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Free in any case
|
||||||
|
free(bounds_vert);
|
||||||
|
free(kk_vert);
|
||||||
|
}
|
||||||
|
|
||||||
/* none of the previous steps are performed, copying */
|
/* none of the previous steps are performed, copying */
|
||||||
if ( ! imOut) {
|
if ( ! imOut) {
|
||||||
|
|
|
@ -46,21 +46,20 @@ int ImagingNewCount = 0;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize,
|
ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
Imaging im;
|
Imaging im;
|
||||||
ImagingSectionCookie cookie;
|
|
||||||
|
|
||||||
im = (Imaging) calloc(1, size);
|
|
||||||
if (!im)
|
|
||||||
return (Imaging) ImagingError_MemoryError();
|
|
||||||
|
|
||||||
/* linesize overflow check, roughly the current largest space req'd */
|
/* linesize overflow check, roughly the current largest space req'd */
|
||||||
if (xsize > (INT_MAX / 4) - 1) {
|
if (xsize > (INT_MAX / 4) - 1) {
|
||||||
return (Imaging) ImagingError_MemoryError();
|
return (Imaging) ImagingError_MemoryError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
im = (Imaging) calloc(1, size);
|
||||||
|
if (!im) {
|
||||||
|
return (Imaging) ImagingError_MemoryError();
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup image descriptor */
|
/* Setup image descriptor */
|
||||||
im->xsize = xsize;
|
im->xsize = xsize;
|
||||||
im->ysize = ysize;
|
im->ysize = ysize;
|
||||||
|
@ -206,47 +205,21 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize,
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
free(im);
|
free(im);
|
||||||
return (Imaging) ImagingError_ValueError("unrecognized mode");
|
return (Imaging) ImagingError_ValueError("unrecognized image mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup image descriptor */
|
/* Setup image descriptor */
|
||||||
strcpy(im->mode, mode);
|
strcpy(im->mode, mode);
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
|
||||||
|
|
||||||
/* Pointer array (allocate at least one line, to avoid MemoryError
|
/* Pointer array (allocate at least one line, to avoid MemoryError
|
||||||
exceptions on platforms where calloc(0, x) returns NULL) */
|
exceptions on platforms where calloc(0, x) returns NULL) */
|
||||||
im->image = (char **) calloc((ysize > 0) ? ysize : 1, sizeof(void *));
|
im->image = (char **) calloc((ysize > 0) ? ysize : 1, sizeof(void *));
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
if ( ! im->image) {
|
||||||
|
|
||||||
if (!im->image) {
|
|
||||||
free(im);
|
free(im);
|
||||||
return (Imaging) ImagingError_MemoryError();
|
return (Imaging) ImagingError_MemoryError();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingNewCount++;
|
|
||||||
|
|
||||||
return im;
|
|
||||||
}
|
|
||||||
|
|
||||||
Imaging
|
|
||||||
ImagingNewPrologue(const char *mode, int xsize, int ysize)
|
|
||||||
{
|
|
||||||
return ImagingNewPrologueSubtype(
|
|
||||||
mode, xsize, ysize, sizeof(struct ImagingMemoryInstance)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Imaging
|
|
||||||
ImagingNewEpilogue(Imaging im)
|
|
||||||
{
|
|
||||||
/* If the raster data allocator didn't setup a destructor,
|
|
||||||
assume that it couldn't allocate the required amount of
|
|
||||||
memory. */
|
|
||||||
if (!im->destroy)
|
|
||||||
return (Imaging) ImagingError_MemoryError();
|
|
||||||
|
|
||||||
/* Initialize alias pointers to pixel data. */
|
/* Initialize alias pointers to pixel data. */
|
||||||
switch (im->pixelsize) {
|
switch (im->pixelsize) {
|
||||||
case 1: case 2: case 3:
|
case 1: case 2: case 3:
|
||||||
|
@ -257,9 +230,18 @@ ImagingNewEpilogue(Imaging im)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImagingNewCount++;
|
||||||
|
|
||||||
return im;
|
return im;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingNewPrologue(const char *mode, int xsize, int ysize)
|
||||||
|
{
|
||||||
|
return ImagingNewPrologueSubtype(
|
||||||
|
mode, xsize, ysize, sizeof(struct ImagingMemoryInstance));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ImagingDelete(Imaging im)
|
ImagingDelete(Imaging im)
|
||||||
{
|
{
|
||||||
|
@ -295,24 +277,23 @@ ImagingDestroyArray(Imaging im)
|
||||||
}
|
}
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingNewArray(const char *mode, int xsize, int ysize)
|
ImagingAllocateArray(Imaging im, int dirty)
|
||||||
{
|
{
|
||||||
Imaging im;
|
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
|
|
||||||
int y;
|
int y;
|
||||||
char* p;
|
char* p;
|
||||||
|
|
||||||
im = ImagingNewPrologue(mode, xsize, ysize);
|
|
||||||
if (!im)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
/* Allocate image as an array of lines */
|
/* Allocate image as an array of lines */
|
||||||
for (y = 0; y < im->ysize; y++) {
|
for (y = 0; y < im->ysize; y++) {
|
||||||
/* malloc check linesize checked in prologue */
|
/* malloc check linesize checked in prologue */
|
||||||
|
if (dirty) {
|
||||||
|
p = (char *) malloc(im->linesize);
|
||||||
|
} else {
|
||||||
p = (char *) calloc(1, im->linesize);
|
p = (char *) calloc(1, im->linesize);
|
||||||
|
}
|
||||||
if (!p) {
|
if (!p) {
|
||||||
ImagingDestroyArray(im);
|
ImagingDestroyArray(im);
|
||||||
break;
|
break;
|
||||||
|
@ -322,10 +303,13 @@ ImagingNewArray(const char *mode, int xsize, int ysize)
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
if (y == im->ysize)
|
if (y != im->ysize) {
|
||||||
|
return (Imaging) ImagingError_MemoryError();
|
||||||
|
}
|
||||||
|
|
||||||
im->destroy = ImagingDestroyArray;
|
im->destroy = ImagingDestroyArray;
|
||||||
|
|
||||||
return ImagingNewEpilogue(im);
|
return im;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -341,15 +325,10 @@ ImagingDestroyBlock(Imaging im)
|
||||||
}
|
}
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingNewBlock(const char *mode, int xsize, int ysize)
|
ImagingAllocateBlock(Imaging im, int dirty)
|
||||||
{
|
{
|
||||||
Imaging im;
|
|
||||||
Py_ssize_t y, i;
|
Py_ssize_t y, i;
|
||||||
|
|
||||||
im = ImagingNewPrologue(mode, xsize, ysize);
|
|
||||||
if (!im)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* We shouldn't overflow, since the threshold defined
|
/* We shouldn't overflow, since the threshold defined
|
||||||
below says that we're only going to allocate max 4M
|
below says that we're only going to allocate max 4M
|
||||||
here before going to the array allocator. Check anyway.
|
here before going to the array allocator. Check anyway.
|
||||||
|
@ -357,7 +336,7 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
||||||
if (im->linesize &&
|
if (im->linesize &&
|
||||||
im->ysize > INT_MAX / im->linesize) {
|
im->ysize > INT_MAX / im->linesize) {
|
||||||
/* punt if we're going to overflow */
|
/* punt if we're going to overflow */
|
||||||
return NULL;
|
return (Imaging) ImagingError_MemoryError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (im->ysize * im->linesize <= 0) {
|
if (im->ysize * im->linesize <= 0) {
|
||||||
|
@ -365,12 +344,20 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
||||||
prevents MemoryError on zero-sized images on such
|
prevents MemoryError on zero-sized images on such
|
||||||
platforms */
|
platforms */
|
||||||
im->block = (char *) malloc(1);
|
im->block = (char *) malloc(1);
|
||||||
|
} else {
|
||||||
|
if (dirty) {
|
||||||
|
/* malloc check ok, overflow check above */
|
||||||
|
im->block = (char *) malloc(im->ysize * im->linesize);
|
||||||
} else {
|
} else {
|
||||||
/* malloc check ok, overflow check above */
|
/* malloc check ok, overflow check above */
|
||||||
im->block = (char *) calloc(im->ysize, im->linesize);
|
im->block = (char *) calloc(im->ysize, im->linesize);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! im->block) {
|
||||||
|
return (Imaging) ImagingError_MemoryError();
|
||||||
|
}
|
||||||
|
|
||||||
if (im->block) {
|
|
||||||
for (y = i = 0; y < im->ysize; y++) {
|
for (y = i = 0; y < im->ysize; y++) {
|
||||||
im->image[y] = im->block + i;
|
im->image[y] = im->block + i;
|
||||||
i += im->linesize;
|
i += im->linesize;
|
||||||
|
@ -378,9 +365,7 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
||||||
|
|
||||||
im->destroy = ImagingDestroyBlock;
|
im->destroy = ImagingDestroyBlock;
|
||||||
|
|
||||||
}
|
return im;
|
||||||
|
|
||||||
return ImagingNewEpilogue(im);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------
|
/* --------------------------------------------------------------------
|
||||||
|
@ -393,39 +378,65 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingNew(const char* mode, int xsize, int ysize)
|
ImagingNewInternal(const char* mode, int xsize, int ysize, int dirty)
|
||||||
{
|
{
|
||||||
int bytes;
|
|
||||||
Imaging im;
|
Imaging im;
|
||||||
|
|
||||||
if (strcmp(mode, "") == 0)
|
|
||||||
return (Imaging) ImagingError_ValueError("empty mode");
|
|
||||||
|
|
||||||
if (strlen(mode) == 1) {
|
|
||||||
if (mode[0] == 'F' || mode[0] == 'I')
|
|
||||||
bytes = 4;
|
|
||||||
else
|
|
||||||
bytes = 1;
|
|
||||||
} else
|
|
||||||
bytes = strlen(mode); /* close enough */
|
|
||||||
|
|
||||||
if (xsize < 0 || ysize < 0) {
|
if (xsize < 0 || ysize < 0) {
|
||||||
return (Imaging) ImagingError_ValueError("bad image size");
|
return (Imaging) ImagingError_ValueError("bad image size");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int64_t) xsize * (int64_t) ysize <= THRESHOLD / bytes) {
|
im = ImagingNewPrologue(mode, xsize, ysize);
|
||||||
im = ImagingNewBlock(mode, xsize, ysize);
|
if ( ! im)
|
||||||
if (im)
|
return NULL;
|
||||||
|
|
||||||
|
if (im->ysize && im->linesize <= THRESHOLD / im->ysize) {
|
||||||
|
if (ImagingAllocateBlock(im, dirty)) {
|
||||||
return im;
|
return im;
|
||||||
|
}
|
||||||
/* assume memory error; try allocating in array mode instead */
|
/* assume memory error; try allocating in array mode instead */
|
||||||
ImagingError_Clear();
|
ImagingError_Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImagingNewArray(mode, xsize, ysize);
|
if (ImagingAllocateArray(im, dirty)) {
|
||||||
|
return im;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagingDelete(im);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingNew2(const char* mode, Imaging imOut, Imaging imIn)
|
ImagingNew(const char* mode, int xsize, int ysize)
|
||||||
|
{
|
||||||
|
return ImagingNewInternal(mode, xsize, ysize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingNewDirty(const char* mode, int xsize, int ysize)
|
||||||
|
{
|
||||||
|
return ImagingNewInternal(mode, xsize, ysize, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingNewBlock(const char* mode, int xsize, int ysize)
|
||||||
|
{
|
||||||
|
Imaging im;
|
||||||
|
|
||||||
|
im = ImagingNewPrologue(mode, xsize, ysize);
|
||||||
|
if ( ! im)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ImagingAllocateBlock(im, 0)) {
|
||||||
|
return im;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagingDelete(im);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Imaging
|
||||||
|
ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn)
|
||||||
{
|
{
|
||||||
/* allocate or validate output image */
|
/* allocate or validate output image */
|
||||||
|
|
||||||
|
@ -438,7 +449,7 @@ ImagingNew2(const char* mode, Imaging imOut, Imaging imIn)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* create new image */
|
/* create new image */
|
||||||
imOut = ImagingNew(mode, imIn->xsize, imIn->ysize);
|
imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize);
|
||||||
if (!imOut)
|
if (!imOut)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,19 @@ unpack1IR(UINT8* out, const UINT8* in, int pixels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unpack18(UINT8* out, const UINT8* in, int pixels)
|
||||||
|
{
|
||||||
|
/* Unpack a '|b1' image, which is a numpy boolean.
|
||||||
|
1 == true, 0==false, in bytes */
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < pixels; i++) {
|
||||||
|
out[i] = in[i] > 0 ? 255 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Unpack to "L" image */
|
/* Unpack to "L" image */
|
||||||
|
|
||||||
|
@ -1163,11 +1176,14 @@ static struct {
|
||||||
endian byte order (default is little endian); "L" line
|
endian byte order (default is little endian); "L" line
|
||||||
interleave, "S" signed, "F" floating point */
|
interleave, "S" signed, "F" floating point */
|
||||||
|
|
||||||
|
/* exception: rawmodes "I" and "F" are always native endian byte order */
|
||||||
|
|
||||||
/* bilevel */
|
/* bilevel */
|
||||||
{"1", "1", 1, unpack1},
|
{"1", "1", 1, unpack1},
|
||||||
{"1", "1;I", 1, unpack1I},
|
{"1", "1;I", 1, unpack1I},
|
||||||
{"1", "1;R", 1, unpack1R},
|
{"1", "1;R", 1, unpack1R},
|
||||||
{"1", "1;IR", 1, unpack1IR},
|
{"1", "1;IR", 1, unpack1IR},
|
||||||
|
{"1", "1;8", 1, unpack18},
|
||||||
|
|
||||||
/* greyscale */
|
/* greyscale */
|
||||||
{"L", "L;2", 2, unpackL2},
|
{"L", "L;2", 2, unpackL2},
|
||||||
|
|
9
map.c
9
map.c
|
@ -229,9 +229,6 @@ mapping_readimage(ImagingMapperObject* mapper, PyObject* args)
|
||||||
|
|
||||||
im->destroy = ImagingDestroyMap;
|
im->destroy = ImagingDestroyMap;
|
||||||
|
|
||||||
if (!ImagingNewEpilogue(im))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mapper->offset += size;
|
mapper->offset += size;
|
||||||
|
|
||||||
return PyImagingNew(im);
|
return PyImagingNew(im);
|
||||||
|
@ -368,8 +365,7 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
im = ImagingNewPrologueSubtype(
|
im = ImagingNewPrologueSubtype(
|
||||||
mode, xsize, ysize, sizeof(ImagingBufferInstance)
|
mode, xsize, ysize, sizeof(ImagingBufferInstance));
|
||||||
);
|
|
||||||
if (!im)
|
if (!im)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -387,9 +383,6 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
|
||||||
((ImagingBufferInstance*) im)->target = target;
|
((ImagingBufferInstance*) im)->target = target;
|
||||||
((ImagingBufferInstance*) im)->view = view;
|
((ImagingBufferInstance*) im)->view = view;
|
||||||
|
|
||||||
if (!ImagingNewEpilogue(im))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return PyImagingNew(im);
|
return PyImagingNew(im);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
setup.py
8
setup.py
|
@ -365,6 +365,14 @@ class pil_build_ext(build_ext):
|
||||||
# work ;-)
|
# work ;-)
|
||||||
self.add_multiarch_paths()
|
self.add_multiarch_paths()
|
||||||
|
|
||||||
|
# termux support for android.
|
||||||
|
# system libraries (zlib) are installed in /system/lib
|
||||||
|
# headers are at $PREFIX/include
|
||||||
|
# user libs are at $PREFIX/lib
|
||||||
|
if os.environ.get('ANDROID_ROOT', None):
|
||||||
|
_add_directory(library_dirs,
|
||||||
|
os.path.join(os.environ['ANDROID_ROOT'],'lib'))
|
||||||
|
|
||||||
elif sys.platform.startswith("gnu"):
|
elif sys.platform.startswith("gnu"):
|
||||||
self.add_multiarch_paths()
|
self.add_multiarch_paths()
|
||||||
|
|
||||||
|
|
|
@ -55,15 +55,15 @@ libs = {
|
||||||
'version': '8.5.19',
|
'version': '8.5.19',
|
||||||
},
|
},
|
||||||
'tcl-8.6': {
|
'tcl-8.6': {
|
||||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.6/tcl866-src.zip',
|
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.7/tcl867-src.zip',
|
||||||
'filename': PILLOW_DEPENDS_DIR + 'tcl866-src.zip',
|
'filename': PILLOW_DEPENDS_DIR + 'tcl867-src.zip',
|
||||||
'dir': '',
|
'dir': '',
|
||||||
},
|
},
|
||||||
'tk-8.6': {
|
'tk-8.6': {
|
||||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.6/tk866-src.zip',
|
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.7/tk867-src.zip',
|
||||||
'filename': PILLOW_DEPENDS_DIR + 'tk866-src.zip',
|
'filename': PILLOW_DEPENDS_DIR + 'tk867-src.zip',
|
||||||
'dir': '',
|
'dir': '',
|
||||||
'version': '8.6.6',
|
'version': '8.6.7',
|
||||||
},
|
},
|
||||||
'webp': {
|
'webp': {
|
||||||
'url': 'http://downloads.webmproject.org/releases/webp/libwebp-0.6.0.tar.gz',
|
'url': 'http://downloads.webmproject.org/releases/webp/libwebp-0.6.0.tar.gz',
|
||||||
|
@ -71,9 +71,9 @@ libs = {
|
||||||
'dir': 'libwebp-0.6.0',
|
'dir': 'libwebp-0.6.0',
|
||||||
},
|
},
|
||||||
'openjpeg': {
|
'openjpeg': {
|
||||||
'url': SF_MIRROR+'/project/openjpeg/openjpeg/2.1.2/openjpeg-2.1.2.tar.gz',
|
'url': SF_MIRROR+'/project/openjpeg/openjpeg/2.2.0/openjpeg-2.2.0.tar.gz',
|
||||||
'filename': PILLOW_DEPENDS_DIR + 'openjpeg-2.1.2.tar.gz',
|
'filename': PILLOW_DEPENDS_DIR + 'openjpeg-2.2.0.tar.gz',
|
||||||
'dir': 'openjpeg-2.1.2',
|
'dir': 'openjpeg-2.2.0',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user