mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 01:46:18 +03:00
Merge branch 'master' into fast-merge
# Conflicts: # _imaging.c # libImaging/Bands.c # libImaging/Imaging.h
This commit is contained in:
commit
9cf8f93c64
|
@ -26,6 +26,8 @@ matrix:
|
|||
- env: DOCKER="debian-stretch-x86"
|
||||
- env: DOCKER="centos-6-amd64"
|
||||
- env: DOCKER="amazon-amd64"
|
||||
- env: DOCKER="fedora-24-amd64"
|
||||
- env: DOCKER="fedora-26-amd64"
|
||||
|
||||
dist: trusty
|
||||
|
||||
|
|
60
CHANGES.rst
60
CHANGES.rst
|
@ -4,6 +4,66 @@ Changelog (Pillow)
|
|||
4.3.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- 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.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 uninitalized 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
|
||||
[wiredfool]
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
format = "FLI"
|
||||
format_description = "Autodesk FLI/FLC Animation"
|
||||
_close_exclusive_fp_after_loading = False
|
||||
|
||||
|
||||
def _open(self):
|
||||
|
||||
# HEAD
|
||||
|
@ -49,6 +49,9 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
s[20:22] == b"\x00\x00"): # reserved
|
||||
raise SyntaxError("not an FLI/FLC file")
|
||||
|
||||
# frames
|
||||
self.__framecount = i16(s[6:8])
|
||||
|
||||
# image characteristics
|
||||
self.mode = "P"
|
||||
self.size = i16(s[8:10]), i16(s[10:12])
|
||||
|
@ -56,7 +59,7 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
# animation speed
|
||||
duration = i32(s[16:20])
|
||||
if magic == 0xAF11:
|
||||
duration = (duration * 1000) / 70
|
||||
duration = (duration * 1000) // 70
|
||||
self.info["duration"] = duration
|
||||
|
||||
# look for palette
|
||||
|
@ -86,8 +89,6 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
self.__frame = -1
|
||||
self.__fp = self.fp
|
||||
self.__rewind = self.fp.tell()
|
||||
self._n_frames = None
|
||||
self._is_animated = None
|
||||
self.seek(0)
|
||||
|
||||
def _palette(self, palette, shift):
|
||||
|
@ -110,43 +111,22 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
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
|
||||
return self.__framecount
|
||||
|
||||
@property
|
||||
def is_animated(self):
|
||||
if self._is_animated is None:
|
||||
current = self.tell()
|
||||
|
||||
try:
|
||||
self.seek(1)
|
||||
self._is_animated = True
|
||||
except EOFError:
|
||||
self._is_animated = False
|
||||
|
||||
self.seek(current)
|
||||
return self._is_animated
|
||||
return self.__framecount > 1
|
||||
|
||||
def seek(self, frame):
|
||||
if frame == self.__frame:
|
||||
return
|
||||
if frame < self.__frame:
|
||||
self._seek(0)
|
||||
if frame >= self.__framecount:
|
||||
raise EOFError("no more images in FLI file")
|
||||
|
||||
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")
|
||||
self._seek(f)
|
||||
|
||||
def _seek(self, frame):
|
||||
if frame == 0:
|
||||
|
@ -176,6 +156,7 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
def tell(self):
|
||||
return self.__frame
|
||||
|
||||
|
||||
#
|
||||
# registry
|
||||
|
||||
|
|
34
PIL/Image.py
34
PIL/Image.py
|
@ -56,8 +56,9 @@ try:
|
|||
from . import _imaging as core
|
||||
if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None):
|
||||
raise ImportError("The _imaging extension was built for another "
|
||||
"version of Pillow or PIL: Core Version: %s"
|
||||
"Pillow Version: %s" %
|
||||
"version of Pillow or PIL:\n"
|
||||
"Core version: %s\n"
|
||||
"Pillow version: %s" %
|
||||
(getattr(core, 'PILLOW_VERSION', None),
|
||||
PILLOW_VERSION))
|
||||
|
||||
|
@ -1947,6 +1948,9 @@ class Image(object):
|
|||
containing a copy of one of the original bands (red, green,
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -1954,11 +1958,31 @@ class Image(object):
|
|||
if self.im.bands == 1:
|
||||
ims = [self.copy()]
|
||||
else:
|
||||
ims = []
|
||||
for i in range(self.im.bands):
|
||||
ims.append(self._new(self.im.getband(i)))
|
||||
ims = map(self._new, self.im.split())
|
||||
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):
|
||||
"""
|
||||
Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
|
||||
|
|
|
@ -67,7 +67,7 @@ class Contrast(_Enhance):
|
|||
self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
|
||||
|
||||
if 'A' in image.getbands():
|
||||
self.degenerate.putalpha(image.split()[-1])
|
||||
self.degenerate.putalpha(image.getchannel('A'))
|
||||
|
||||
|
||||
class Brightness(_Enhance):
|
||||
|
@ -82,7 +82,7 @@ class Brightness(_Enhance):
|
|||
self.degenerate = Image.new(image.mode, image.size, 0)
|
||||
|
||||
if 'A' in image.getbands():
|
||||
self.degenerate.putalpha(image.split()[-1])
|
||||
self.degenerate.putalpha(image.getchannel('A'))
|
||||
|
||||
|
||||
class Sharpness(_Enhance):
|
||||
|
@ -97,4 +97,4 @@ class Sharpness(_Enhance):
|
|||
self.degenerate = image.filter(ImageFilter.SMOOTH)
|
||||
|
||||
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):
|
||||
raise ImportError("The _imagingft C module is not installed")
|
||||
|
||||
|
||||
try:
|
||||
from . import _imagingft as core
|
||||
except ImportError:
|
||||
|
@ -113,7 +114,6 @@ class ImageFont(object):
|
|||
return self.font.getmask(text, mode)
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Wrapper for FreeType fonts. Application code should use the
|
||||
# <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):
|
||||
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)
|
||||
im = fill("L", size, 0)
|
||||
self.font.render(text, im.id, mode == "1", direction, features)
|
||||
|
@ -250,7 +250,7 @@ def truetype(font=None, size=10, index=0, encoding="",
|
|||
and "armn" (Apple Roman). See the FreeType documentation
|
||||
for more information.
|
||||
:param layout_engine: Which layout engine to use, if available:
|
||||
`ImageFont.LAYOUT_BASIC` or `ImageFont.LAYOUT_RAQM`.
|
||||
`ImageFont.LAYOUT_BASIC` or `ImageFont.LAYOUT_RAQM`.
|
||||
:return: A font object.
|
||||
:exception IOError: If the file could not be read.
|
||||
"""
|
||||
|
|
|
@ -131,9 +131,10 @@ def APP(self, marker):
|
|||
# 1 dpcm = 2.54 dpi
|
||||
dpi *= 2.54
|
||||
self.info["dpi"] = dpi, dpi
|
||||
except (KeyError, SyntaxError):
|
||||
except (KeyError, SyntaxError, ZeroDivisionError):
|
||||
# SyntaxError for invalid/unreadable exif
|
||||
# KeyError for dpi not included
|
||||
# ZeroDivisionError for invalid dpi rational value
|
||||
self.info["dpi"] = 72, 72
|
||||
|
||||
|
||||
|
|
|
@ -104,6 +104,11 @@ def _save(im, fp, filename):
|
|||
z = len(im.mode)
|
||||
if dim == 1 or dim == 2:
|
||||
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
|
||||
pinmin = 0
|
||||
# Maximum Byte value (255 = 8bits per pixel)
|
||||
|
@ -131,11 +136,6 @@ def _save(im, fp, filename):
|
|||
|
||||
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():
|
||||
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
|
||||
# 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):
|
||||
|
||||
def test_sanity(self):
|
||||
im = Image.open(test_file)
|
||||
im = Image.open(static_test_file)
|
||||
im.load()
|
||||
self.assertEqual(im.mode, "P")
|
||||
self.assertEqual(im.size, (128, 128))
|
||||
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):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
@ -23,12 +44,16 @@ class TestFileFli(PillowTestCase):
|
|||
lambda: FliImagePlugin.FliImageFile(invalid_file))
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open(test_file)
|
||||
im = Image.open(static_test_file)
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
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):
|
||||
im = Image.open(test_file)
|
||||
im = Image.open(animated_test_file)
|
||||
|
||||
n_frames = im.n_frames
|
||||
while True:
|
||||
|
@ -39,6 +64,33 @@ class TestFileFli(PillowTestCase):
|
|||
except EOFError:
|
||||
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__':
|
||||
unittest.main()
|
||||
|
|
|
@ -15,6 +15,16 @@ class TestFileIm(PillowTestCase):
|
|||
self.assertEqual(im.size, (128, 128))
|
||||
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):
|
||||
im = Image.open(TEST_IM)
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
|
|
|
@ -535,6 +535,16 @@ class TestFileJpeg(PillowTestCase):
|
|||
# Act / Assert
|
||||
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):
|
||||
# Arrange
|
||||
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
|
||||
|
|
|
@ -200,7 +200,7 @@ class TestFilePng(PillowTestCase):
|
|||
self.assert_image(im, "RGBA", (162, 150))
|
||||
|
||||
# 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):
|
||||
test_file = "Tests/images/rgb_trns.png"
|
||||
|
@ -212,7 +212,7 @@ class TestFilePng(PillowTestCase):
|
|||
self.assert_image(im, "RGBA", (64, 64))
|
||||
|
||||
# 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):
|
||||
in_file = "Tests/images/pil123p.png"
|
||||
|
@ -234,7 +234,7 @@ class TestFilePng(PillowTestCase):
|
|||
self.assert_image(im, "RGBA", (162, 150))
|
||||
|
||||
# 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):
|
||||
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))
|
||||
|
||||
# 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):
|
||||
# check if solid black image with full transparency
|
||||
|
@ -287,7 +287,7 @@ class TestFilePng(PillowTestCase):
|
|||
|
||||
# There are 559 transparent pixels.
|
||||
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):
|
||||
in_file = "Tests/images/caption_6_33_22.png"
|
||||
|
@ -550,7 +550,7 @@ class TestTruncatedPngPLeaks(PillowTestCase):
|
|||
# linux
|
||||
# man 2 getrusage
|
||||
# ru_maxrss (since Linux 2.6.32)
|
||||
# This is the maximum resident set size used (in kilobytes).
|
||||
# This is the maximum resident set size used (in kilobytes).
|
||||
return mem / 1024 # megs
|
||||
|
||||
def test_leak_load(self):
|
||||
|
|
|
@ -55,6 +55,22 @@ class TestFileSgi(PillowTestCase):
|
|||
for mode in ('L', 'RGB', 'RGBA'):
|
||||
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__':
|
||||
unittest.main()
|
||||
|
|
|
@ -103,11 +103,11 @@ class TestFormatHSV(PillowTestCase):
|
|||
# im.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")
|
||||
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")
|
||||
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")
|
||||
|
||||
# print(im.getpixel((192, 64)))
|
||||
|
@ -120,11 +120,11 @@ class TestFormatHSV(PillowTestCase):
|
|||
# print(im.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")
|
||||
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")
|
||||
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")
|
||||
|
||||
def test_convert(self):
|
||||
|
@ -137,11 +137,11 @@ class TestFormatHSV(PillowTestCase):
|
|||
# print(im.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")
|
||||
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")
|
||||
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")
|
||||
|
||||
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 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")
|
||||
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")
|
||||
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")
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,25 @@ import sys
|
|||
|
||||
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):
|
||||
|
||||
im = Image.new("L", (100, 100))
|
||||
|
@ -145,14 +164,28 @@ class TestImage(PillowTestCase):
|
|||
self.assertEqual(im.size[1], orig_size[1] + 2*ymargin)
|
||||
|
||||
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()
|
||||
|
||||
# Act
|
||||
bands = im.getbands()
|
||||
self.assertRaises(ValueError, im.getchannel, -1)
|
||||
self.assertRaises(ValueError, im.getchannel, 3)
|
||||
self.assertRaises(ValueError, im.getchannel, 'Z')
|
||||
self.assertRaises(ValueError, im.getchannel, '1')
|
||||
|
||||
# Assert
|
||||
self.assertEqual(bands, ('R', 'G', 'B'))
|
||||
def test_getchannel(self):
|
||||
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):
|
||||
# Arrange
|
||||
|
|
|
@ -133,7 +133,7 @@ class TestImageConvert(PillowTestCase):
|
|||
alpha = hopper('L')
|
||||
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)
|
||||
|
||||
|
@ -185,7 +185,7 @@ class TestImageConvert(PillowTestCase):
|
|||
if converted_im.mode == 'RGB':
|
||||
self.assert_image_similar(converted_im, target, 3)
|
||||
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('L')
|
||||
|
|
|
@ -94,6 +94,28 @@ class TestImageFilter(PillowTestCase):
|
|||
self.assertEqual(rankfilter.size, 1)
|
||||
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__':
|
||||
unittest.main()
|
||||
|
|
|
@ -360,8 +360,7 @@ class TestImageCms(PillowTestCase):
|
|||
return Image.merge(mode, chans)
|
||||
|
||||
source_image = create_test_image()
|
||||
preserved_channel_ndx = source_image.getbands().index(preserved_channel)
|
||||
source_image_aux = source_image.split()[preserved_channel_ndx]
|
||||
source_image_aux = source_image.getchannel(preserved_channel)
|
||||
|
||||
# create some transform, it doesn't matter which one
|
||||
source_profile = ImageCms.createProfile("sRGB")
|
||||
|
@ -374,7 +373,7 @@ class TestImageCms(PillowTestCase):
|
|||
result_image = source_image
|
||||
else:
|
||||
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)
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class TestImageEnhance(PillowTestCase):
|
|||
|
||||
def _check_alpha(self, im, original, op, amount):
|
||||
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))
|
||||
|
||||
def test_alpha(self):
|
||||
|
|
|
@ -40,13 +40,15 @@ class SimplePatcher(object):
|
|||
else:
|
||||
delattr(self._parent_obj, self._attr_name)
|
||||
|
||||
|
||||
@unittest.skipUnless(HAS_FREETYPE, "ImageFont not Available")
|
||||
class TestImageFont(PillowTestCase):
|
||||
LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC
|
||||
|
||||
# Freetype has different metrics depending on the version.
|
||||
# (and, other things, but first things first)
|
||||
METRICS = { ('2', '3'): {'multiline': 30,
|
||||
METRICS = {
|
||||
('2', '3'): {'multiline': 30,
|
||||
'textsize': 12,
|
||||
'getters': (13, 16)},
|
||||
('2', '7'): {'multiline': 6.2,
|
||||
|
@ -213,6 +215,14 @@ class TestImageFont(PillowTestCase):
|
|||
font=ttf,
|
||||
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):
|
||||
ttf = self.get_font()
|
||||
im = Image.new(mode='RGB', size=(300, 100))
|
||||
|
@ -395,7 +405,7 @@ class TestImageFont(PillowTestCase):
|
|||
|
||||
def test_getsize_empty(self):
|
||||
font = self.get_font()
|
||||
# should not crash.
|
||||
# should not crash.
|
||||
self.assertEqual((0, 0), font.getsize(''))
|
||||
|
||||
def _test_fake_loading_font(self, path_to_fake, fontname):
|
||||
|
@ -494,5 +504,6 @@ class TestImageFont(PillowTestCase):
|
|||
class TestImageFont_RaqmLayout(TestImageFont):
|
||||
LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -52,7 +52,7 @@ class TestNumpy(PillowTestCase):
|
|||
a = numpy.array([[x]*bands for x in data], dtype=dtype)
|
||||
a.shape = TEST_IMAGE_SIZE[0], TEST_IMAGE_SIZE[1], bands
|
||||
i = Image.fromarray(a)
|
||||
if list(i.split()[0].getdata()) != list(range(100)):
|
||||
if list(i.getchannel(0).getdata()) != list(range(100)):
|
||||
print("data mismatch for", dtype)
|
||||
# print(dtype, list(i.getdata()))
|
||||
return i
|
||||
|
|
60
_imaging.c
60
_imaging.c
|
@ -599,7 +599,7 @@ _fill(PyObject* self, PyObject* args)
|
|||
if (!PyArg_ParseTuple(args, "s|(ii)O", &mode, &xsize, &ysize, &color))
|
||||
return NULL;
|
||||
|
||||
im = ImagingNew(mode, xsize, ysize);
|
||||
im = ImagingNewDirty(mode, xsize, ysize);
|
||||
if (!im)
|
||||
return NULL;
|
||||
|
||||
|
@ -791,23 +791,6 @@ _copy(ImagingObject* self, PyObject* args)
|
|||
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*
|
||||
_crop(ImagingObject* self, PyObject* args)
|
||||
{
|
||||
|
@ -874,7 +857,7 @@ _gaussian_blur(ImagingObject* self, PyObject* args)
|
|||
return NULL;
|
||||
|
||||
imIn = self->image;
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -1539,7 +1522,7 @@ _resize(ImagingObject* self, PyObject* args)
|
|||
a[0] = (double) imIn->xsize / xsize;
|
||||
a[4] = (double) imIn->ysize / ysize;
|
||||
|
||||
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
|
||||
|
||||
imOut = ImagingTransform(
|
||||
imOut, imIn, IMAGING_TRANSFORM_AFFINE,
|
||||
|
@ -1665,12 +1648,12 @@ _transpose(ImagingObject* self, PyObject* args)
|
|||
case 0: /* flip left right */
|
||||
case 1: /* flip top bottom */
|
||||
case 3: /* rotate 180 */
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
break;
|
||||
case 2: /* rotate 90 */
|
||||
case 4: /* rotate 270 */
|
||||
case 5: /* transpose */
|
||||
imOut = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_ValueError, "No such transpose operation");
|
||||
|
@ -1715,7 +1698,7 @@ _unsharp_mask(ImagingObject* self, PyObject* args)
|
|||
return NULL;
|
||||
|
||||
imIn = self->image;
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -1738,7 +1721,7 @@ _box_blur(ImagingObject* self, PyObject* args)
|
|||
return NULL;
|
||||
|
||||
imIn = self->image;
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -1928,6 +1911,32 @@ _merge(PyObject* self, PyObject* args)
|
|||
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
|
||||
|
@ -2963,7 +2972,6 @@ static struct PyMethodDef methods[] = {
|
|||
{"convert_matrix", (PyCFunction)_convert_matrix, 1},
|
||||
{"convert_transparent", (PyCFunction)_convert_transparent, 1},
|
||||
{"copy", (PyCFunction)_copy, 1},
|
||||
{"copy2", (PyCFunction)_copy2, 1},
|
||||
{"crop", (PyCFunction)_crop, 1},
|
||||
{"expand", (PyCFunction)_expand_image, 1},
|
||||
{"filter", (PyCFunction)_filter, 1},
|
||||
|
@ -2995,6 +3003,7 @@ static struct PyMethodDef methods[] = {
|
|||
|
||||
{"getband", (PyCFunction)_getband, 1},
|
||||
{"putband", (PyCFunction)_putband, 1},
|
||||
{"split", (PyCFunction)_split, 1},
|
||||
{"fillband", (PyCFunction)_fillband, 1},
|
||||
|
||||
{"setmode", (PyCFunction)im_setmode, 1},
|
||||
|
@ -3345,7 +3354,6 @@ static PyMethodDef functions[] = {
|
|||
|
||||
/* Functions */
|
||||
{"convert", (PyCFunction)_convert2, 1},
|
||||
{"copy", (PyCFunction)_copy2, 1},
|
||||
|
||||
/* Codecs */
|
||||
{"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, 1},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# 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
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# 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
|
||||
|
||||
|
|
2
docs/_templates/sidebarhelp.html
vendored
2
docs/_templates/sidebarhelp.html
vendored
|
@ -1,4 +1,4 @@
|
|||
<h3>Need help?</h3>
|
||||
<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>
|
||||
|
|
|
@ -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.show
|
||||
.. automethod:: PIL.Image.Image.split
|
||||
.. automethod:: PIL.Image.Image.getchannel
|
||||
.. automethod:: PIL.Image.Image.tell
|
||||
.. automethod:: PIL.Image.Image.thumbnail
|
||||
.. 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::
|
||||
:maxdepth: 2
|
||||
|
||||
4.3.0
|
||||
4.2.1
|
||||
4.2.0
|
||||
4.1.1
|
||||
|
@ -21,5 +22,3 @@ Release Notes
|
|||
3.0.0
|
||||
2.8.0
|
||||
2.7.0
|
||||
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
|
|||
imDst->ysize != imSrc->ysize)
|
||||
return ImagingError_Mismatch();
|
||||
|
||||
imOut = ImagingNew(imDst->mode, imDst->xsize, imDst->ysize);
|
||||
imOut = ImagingNewDirty(imDst->mode, imDst->xsize, imDst->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ ImagingGetBand(Imaging imIn, int band)
|
|||
if (imIn->bands == 2 && band == 1)
|
||||
band = 3;
|
||||
|
||||
imOut = ImagingNew("L", imIn->xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -58,7 +58,12 @@ ImagingGetBand(Imaging imIn, int band)
|
|||
for (y = 0; y < imIn->ysize; y++) {
|
||||
UINT8* in = (UINT8*) imIn->image[y] + band;
|
||||
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;
|
||||
in += 4;
|
||||
}
|
||||
|
@ -67,6 +72,101 @@ ImagingGetBand(Imaging imIn, int band)
|
|||
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
|
||||
ImagingPutBand(Imaging imOut, Imaging imIn, int band)
|
||||
{
|
||||
|
|
|
@ -815,6 +815,7 @@ static int decode_bcn(Imaging im, ImagingCodecState state, const UINT8* src, int
|
|||
case NN: \
|
||||
while (bytes >= SZ) { \
|
||||
TY col[16]; \
|
||||
memset(col, 0, 16 * sizeof(col[0])); \
|
||||
decode_bc##NN##_block(col, ptr); \
|
||||
put_block(im, state, (const char *)col, sizeof(col[0]), C); \
|
||||
ptr += SZ; \
|
||||
|
|
|
@ -40,7 +40,7 @@ ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha)
|
|||
else if (alpha == 1.0)
|
||||
return ImagingCopy(imIn2);
|
||||
|
||||
imOut = ImagingNew(imIn1->mode, imIn1->xsize, imIn1->ysize);
|
||||
imOut = ImagingNewDirty(imIn1->mode, imIn1->xsize, imIn1->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n)
|
|||
strcmp(imIn->mode, "La") == 0))
|
||||
return ImagingError_ModeError();
|
||||
|
||||
imTransposed = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize);
|
||||
imTransposed = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
|
||||
if (!imTransposed)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -1035,7 +1035,7 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode)
|
|||
else
|
||||
return (Imaging) ImagingError_ValueError("conversion not supported");
|
||||
|
||||
imOut = ImagingNew2(mode, imOut, imIn);
|
||||
imOut = ImagingNew2Dirty(mode, imOut, imIn);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -1073,7 +1073,7 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
|
|||
if (!palette)
|
||||
return (Imaging) ImagingError_ValueError("no palette");
|
||||
|
||||
imOut = ImagingNew2("P", imOut, imIn);
|
||||
imOut = ImagingNew2Dirty("P", imOut, imIn);
|
||||
if (!imOut) {
|
||||
if (palette != inpalette)
|
||||
ImagingPaletteDelete(palette);
|
||||
|
@ -1211,7 +1211,7 @@ tobilevel(Imaging imOut, Imaging imIn, int dither)
|
|||
if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0)
|
||||
return (Imaging) ImagingError_ValueError("conversion not supported");
|
||||
|
||||
imOut = ImagingNew2("1", imOut, imIn);
|
||||
imOut = ImagingNew2Dirty("1", imOut, imIn);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -1344,7 +1344,7 @@ convert(Imaging imOut, Imaging imIn, const char *mode,
|
|||
}
|
||||
#endif
|
||||
|
||||
imOut = ImagingNew2(mode, imOut, imIn);
|
||||
imOut = ImagingNew2Dirty(mode, imOut, imIn);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -1407,7 +1407,7 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
|
|||
g = b = r;
|
||||
}
|
||||
|
||||
imOut = ImagingNew2(mode, imOut, imIn);
|
||||
imOut = ImagingNew2Dirty(mode, imOut, imIn);
|
||||
if (!imOut){
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ _copy(Imaging imOut, Imaging imIn)
|
|||
if (!imIn)
|
||||
return (Imaging) ImagingError_ValueError(NULL);
|
||||
|
||||
imOut = ImagingNew2(imIn->mode, imOut, imIn);
|
||||
imOut = ImagingNew2Dirty(imIn->mode, imOut, imIn);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1)
|
|||
if (ysize < 0)
|
||||
ysize = 0;
|
||||
|
||||
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ ImagingFillLinearGradient(const char *mode)
|
|||
return (Imaging) ImagingError_ModeError();
|
||||
}
|
||||
|
||||
im = ImagingNew(mode, 256, 256);
|
||||
im = ImagingNewDirty(mode, 256, 256);
|
||||
if (!im) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ ImagingFillRadialGradient(const char *mode)
|
|||
return (Imaging) ImagingError_ModeError();
|
||||
}
|
||||
|
||||
im = ImagingNew(mode, 256, 256);
|
||||
im = ImagingNewDirty(mode, 256, 256);
|
||||
if (!im) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
|
|||
{
|
||||
Imaging imOut;
|
||||
int x, y;
|
||||
ImagingSectionCookie cookie;
|
||||
|
||||
if (xmargin < 0 && ymargin < 0)
|
||||
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);\
|
||||
}
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
if (imIn->image8) {
|
||||
EXPAND(UINT8, image8);
|
||||
} else {
|
||||
EXPAND(INT32, image32);
|
||||
}
|
||||
ImagingSectionLeave(&cookie);
|
||||
|
||||
ImagingCopyInfo(imOut, imIn);
|
||||
|
||||
|
@ -78,6 +81,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
|||
Imaging imOut;
|
||||
int x, y;
|
||||
FLOAT32 sum;
|
||||
ImagingSectionCookie cookie;
|
||||
|
||||
if (!im || strcmp(im->mode, "L") != 0)
|
||||
return (Imaging) ImagingError_ModeError();
|
||||
|
@ -92,6 +96,9 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
|||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
|
||||
/* brute force kernel implementations */
|
||||
#define KERNEL3x3(image, kernel, d) ( \
|
||||
(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+d] * kernel[24])
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
if (xsize == 3) {
|
||||
/* 3x3 kernel. */
|
||||
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++)
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
}
|
||||
ImagingSectionLeave(&cookie);
|
||||
return imOut;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,11 +159,11 @@ struct ImagingPaletteInstance {
|
|||
extern int ImagingNewCount;
|
||||
|
||||
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 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,
|
||||
const char* mode, int xsize, int ysize);
|
||||
|
||||
|
@ -172,7 +172,6 @@ extern Imaging ImagingNewPrologue(const char *mode,
|
|||
extern Imaging ImagingNewPrologueSubtype(const char *mode,
|
||||
int xsize, int ysize,
|
||||
int structure_size);
|
||||
extern Imaging ImagingNewEpilogue(Imaging im);
|
||||
|
||||
extern void ImagingCopyInfo(Imaging destination, Imaging source);
|
||||
|
||||
|
@ -268,6 +267,7 @@ extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius,
|
|||
int passes);
|
||||
extern Imaging ImagingGetBand(Imaging im, int band);
|
||||
extern Imaging ImagingMerge(const char* mode, Imaging bands[4]);
|
||||
extern int ImagingSplit(Imaging im, Imaging bands[4]);
|
||||
extern int ImagingGetBBox(Imaging im, int bbox[4]);
|
||||
typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem;
|
||||
extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors,
|
||||
|
|
|
@ -32,7 +32,7 @@ ImagingConvertMatrix(Imaging im, const char *mode, float m[])
|
|||
|
||||
if (strcmp(mode, "L") == 0 && im->bands == 3) {
|
||||
|
||||
imOut = ImagingNew("L", im->xsize, im->ysize);
|
||||
imOut = ImagingNewDirty("L", im->xsize, im->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -49,7 +49,7 @@ ImagingConvertMatrix(Imaging im, const char *mode, float m[])
|
|||
|
||||
} else if (strlen(mode) == 3 && im->bands == 3) {
|
||||
|
||||
imOut = ImagingNew(mode, im->xsize, im->ysize);
|
||||
imOut = ImagingNewDirty(mode, im->xsize, im->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ ImagingNegative(Imaging im)
|
|||
if (!im)
|
||||
return (Imaging) ImagingError_ModeError();
|
||||
|
||||
imOut = ImagingNew(im->mode, im->xsize, im->ysize);
|
||||
imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ ImagingOffset(Imaging im, int xoffset, int yoffset)
|
|||
if (!im)
|
||||
return (Imaging) ImagingError_ModeError();
|
||||
|
||||
imOut = ImagingNew(im->mode, im->xsize, im->ysize);
|
||||
imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -5,6 +5,13 @@
|
|||
|
||||
#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 {
|
||||
double (*filter)(double x);
|
||||
double support;
|
||||
|
@ -249,7 +256,7 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
imOut = ImagingNew(imIn->mode, xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, xsize, imIn->ysize);
|
||||
if ( ! imOut) {
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
|
@ -281,8 +288,8 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
|
||||
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||
clip8(ss0), 0, 0, clip8(ss3));
|
||||
}
|
||||
}
|
||||
} else if (imIn->bands == 3) {
|
||||
|
@ -297,9 +304,8 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
ss1 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 1]) * k[x];
|
||||
ss2 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 2]) * k[x];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
||||
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -315,10 +321,8 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
ss2 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 2]) * k[x];
|
||||
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,7 +358,7 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
|||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
|
||||
if ( ! imOut) {
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
|
@ -386,8 +390,8 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
|||
ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
|
||||
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||
clip8(ss0), 0, 0, clip8(ss3));
|
||||
}
|
||||
}
|
||||
} else if (imIn->bands == 3) {
|
||||
|
@ -402,9 +406,8 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
|||
ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
|
||||
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
||||
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -420,10 +423,8 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
|||
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
||||
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +452,7 @@ ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
imOut = ImagingNew(imIn->mode, xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, xsize, imIn->ysize);
|
||||
if ( ! imOut) {
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
|
@ -511,7 +512,7 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
|
|||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
||||
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
|
||||
if ( ! imOut) {
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
|
|
|
@ -46,21 +46,20 @@ int ImagingNewCount = 0;
|
|||
*/
|
||||
|
||||
Imaging
|
||||
ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize,
|
||||
int size)
|
||||
ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size)
|
||||
{
|
||||
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 */
|
||||
if (xsize > (INT_MAX / 4) - 1) {
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
im = (Imaging) calloc(1, size);
|
||||
if (!im) {
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
/* Setup image descriptor */
|
||||
im->xsize = xsize;
|
||||
im->ysize = ysize;
|
||||
|
@ -206,47 +205,21 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize,
|
|||
|
||||
} else {
|
||||
free(im);
|
||||
return (Imaging) ImagingError_ValueError("unrecognized mode");
|
||||
return (Imaging) ImagingError_ValueError("unrecognized image mode");
|
||||
}
|
||||
|
||||
/* Setup image descriptor */
|
||||
strcpy(im->mode, mode);
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
|
||||
/* Pointer array (allocate at least one line, to avoid MemoryError
|
||||
exceptions on platforms where calloc(0, x) returns NULL) */
|
||||
im->image = (char **) calloc((ysize > 0) ? ysize : 1, sizeof(void *));
|
||||
|
||||
ImagingSectionLeave(&cookie);
|
||||
|
||||
if (!im->image) {
|
||||
if ( ! im->image) {
|
||||
free(im);
|
||||
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. */
|
||||
switch (im->pixelsize) {
|
||||
case 1: case 2: case 3:
|
||||
|
@ -257,9 +230,18 @@ ImagingNewEpilogue(Imaging im)
|
|||
break;
|
||||
}
|
||||
|
||||
ImagingNewCount++;
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingNewPrologue(const char *mode, int xsize, int ysize)
|
||||
{
|
||||
return ImagingNewPrologueSubtype(
|
||||
mode, xsize, ysize, sizeof(struct ImagingMemoryInstance));
|
||||
}
|
||||
|
||||
void
|
||||
ImagingDelete(Imaging im)
|
||||
{
|
||||
|
@ -295,24 +277,23 @@ ImagingDestroyArray(Imaging im)
|
|||
}
|
||||
|
||||
Imaging
|
||||
ImagingNewArray(const char *mode, int xsize, int ysize)
|
||||
ImagingAllocateArray(Imaging im, int dirty)
|
||||
{
|
||||
Imaging im;
|
||||
ImagingSectionCookie cookie;
|
||||
|
||||
int y;
|
||||
char* p;
|
||||
|
||||
im = ImagingNewPrologue(mode, xsize, ysize);
|
||||
if (!im)
|
||||
return NULL;
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
|
||||
/* Allocate image as an array of lines */
|
||||
for (y = 0; y < im->ysize; y++) {
|
||||
/* malloc check linesize checked in prologue */
|
||||
p = (char *) calloc(1, im->linesize);
|
||||
if (dirty) {
|
||||
p = (char *) malloc(im->linesize);
|
||||
} else {
|
||||
p = (char *) calloc(1, im->linesize);
|
||||
}
|
||||
if (!p) {
|
||||
ImagingDestroyArray(im);
|
||||
break;
|
||||
|
@ -322,10 +303,13 @@ ImagingNewArray(const char *mode, int xsize, int ysize)
|
|||
|
||||
ImagingSectionLeave(&cookie);
|
||||
|
||||
if (y == im->ysize)
|
||||
im->destroy = ImagingDestroyArray;
|
||||
if (y != im->ysize) {
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
return ImagingNewEpilogue(im);
|
||||
im->destroy = ImagingDestroyArray;
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
|
||||
|
@ -341,15 +325,10 @@ ImagingDestroyBlock(Imaging im)
|
|||
}
|
||||
|
||||
Imaging
|
||||
ImagingNewBlock(const char *mode, int xsize, int ysize)
|
||||
ImagingAllocateBlock(Imaging im, int dirty)
|
||||
{
|
||||
Imaging im;
|
||||
Py_ssize_t y, i;
|
||||
|
||||
im = ImagingNewPrologue(mode, xsize, ysize);
|
||||
if (!im)
|
||||
return NULL;
|
||||
|
||||
/* We shouldn't overflow, since the threshold defined
|
||||
below says that we're only going to allocate max 4M
|
||||
here before going to the array allocator. Check anyway.
|
||||
|
@ -357,7 +336,7 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
|||
if (im->linesize &&
|
||||
im->ysize > INT_MAX / im->linesize) {
|
||||
/* punt if we're going to overflow */
|
||||
return NULL;
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
if (im->ysize * im->linesize <= 0) {
|
||||
|
@ -366,21 +345,27 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
|||
platforms */
|
||||
im->block = (char *) malloc(1);
|
||||
} else {
|
||||
/* malloc check ok, overflow check above */
|
||||
im->block = (char *) calloc(im->ysize, im->linesize);
|
||||
}
|
||||
|
||||
if (im->block) {
|
||||
for (y = i = 0; y < im->ysize; y++) {
|
||||
im->image[y] = im->block + i;
|
||||
i += im->linesize;
|
||||
if (dirty) {
|
||||
/* malloc check ok, overflow check above */
|
||||
im->block = (char *) malloc(im->ysize * im->linesize);
|
||||
} else {
|
||||
/* malloc check ok, overflow check above */
|
||||
im->block = (char *) calloc(im->ysize, im->linesize);
|
||||
}
|
||||
|
||||
im->destroy = ImagingDestroyBlock;
|
||||
|
||||
}
|
||||
|
||||
return ImagingNewEpilogue(im);
|
||||
if ( ! im->block) {
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
for (y = i = 0; y < im->ysize; y++) {
|
||||
im->image[y] = im->block + i;
|
||||
i += im->linesize;
|
||||
}
|
||||
|
||||
im->destroy = ImagingDestroyBlock;
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
|
@ -393,39 +378,65 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
|
|||
#endif
|
||||
|
||||
Imaging
|
||||
ImagingNew(const char* mode, int xsize, int ysize)
|
||||
ImagingNewInternal(const char* mode, int xsize, int ysize, int dirty)
|
||||
{
|
||||
int bytes;
|
||||
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) {
|
||||
return (Imaging) ImagingError_ValueError("bad image size");
|
||||
}
|
||||
|
||||
if ((int64_t) xsize * (int64_t) ysize <= THRESHOLD / bytes) {
|
||||
im = ImagingNewBlock(mode, xsize, ysize);
|
||||
if (im)
|
||||
im = ImagingNewPrologue(mode, xsize, ysize);
|
||||
if ( ! im)
|
||||
return NULL;
|
||||
|
||||
if (im->ysize && im->linesize <= THRESHOLD / im->ysize) {
|
||||
if (ImagingAllocateBlock(im, dirty)) {
|
||||
return im;
|
||||
}
|
||||
/* assume memory error; try allocating in array mode instead */
|
||||
ImagingError_Clear();
|
||||
}
|
||||
|
||||
return ImagingNewArray(mode, xsize, ysize);
|
||||
if (ImagingAllocateArray(im, dirty)) {
|
||||
return im;
|
||||
}
|
||||
|
||||
ImagingDelete(im);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -438,7 +449,7 @@ ImagingNew2(const char* mode, Imaging imOut, Imaging imIn)
|
|||
}
|
||||
} else {
|
||||
/* create new image */
|
||||
imOut = ImagingNew(mode, imIn->xsize, imIn->ysize);
|
||||
imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
}
|
||||
|
|
9
map.c
9
map.c
|
@ -229,9 +229,6 @@ mapping_readimage(ImagingMapperObject* mapper, PyObject* args)
|
|||
|
||||
im->destroy = ImagingDestroyMap;
|
||||
|
||||
if (!ImagingNewEpilogue(im))
|
||||
return NULL;
|
||||
|
||||
mapper->offset += size;
|
||||
|
||||
return PyImagingNew(im);
|
||||
|
@ -368,8 +365,7 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
|
|||
}
|
||||
|
||||
im = ImagingNewPrologueSubtype(
|
||||
mode, xsize, ysize, sizeof(ImagingBufferInstance)
|
||||
);
|
||||
mode, xsize, ysize, sizeof(ImagingBufferInstance));
|
||||
if (!im)
|
||||
return NULL;
|
||||
|
||||
|
@ -387,9 +383,6 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
|
|||
((ImagingBufferInstance*) im)->target = target;
|
||||
((ImagingBufferInstance*) im)->view = view;
|
||||
|
||||
if (!ImagingNewEpilogue(im))
|
||||
return NULL;
|
||||
|
||||
return PyImagingNew(im);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,15 +55,15 @@ libs = {
|
|||
'version': '8.5.19',
|
||||
},
|
||||
'tcl-8.6': {
|
||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.6/tcl866-src.zip',
|
||||
'filename': PILLOW_DEPENDS_DIR + 'tcl866-src.zip',
|
||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.7/tcl867-src.zip',
|
||||
'filename': PILLOW_DEPENDS_DIR + 'tcl867-src.zip',
|
||||
'dir': '',
|
||||
},
|
||||
'tk-8.6': {
|
||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.6/tk866-src.zip',
|
||||
'filename': PILLOW_DEPENDS_DIR + 'tk866-src.zip',
|
||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.7/tk867-src.zip',
|
||||
'filename': PILLOW_DEPENDS_DIR + 'tk867-src.zip',
|
||||
'dir': '',
|
||||
'version': '8.6.6',
|
||||
'version': '8.6.7',
|
||||
},
|
||||
'webp': {
|
||||
'url': 'http://downloads.webmproject.org/releases/webp/libwebp-0.6.0.tar.gz',
|
||||
|
@ -71,9 +71,9 @@ libs = {
|
|||
'dir': 'libwebp-0.6.0',
|
||||
},
|
||||
'openjpeg': {
|
||||
'url': SF_MIRROR+'/project/openjpeg/openjpeg/2.1.2/openjpeg-2.1.2.tar.gz',
|
||||
'filename': PILLOW_DEPENDS_DIR + 'openjpeg-2.1.2.tar.gz',
|
||||
'dir': 'openjpeg-2.1.2',
|
||||
'url': SF_MIRROR+'/project/openjpeg/openjpeg/2.2.0/openjpeg-2.2.0.tar.gz',
|
||||
'filename': PILLOW_DEPENDS_DIR + 'openjpeg-2.2.0.tar.gz',
|
||||
'dir': 'openjpeg-2.2.0',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user