mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 18:06:18 +03:00
Merge branch 'master' into alpha-composite-box
This commit is contained in:
commit
5bc72dbc10
|
@ -10,8 +10,8 @@ notifications:
|
|||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- python: "pypy-5.7.1"
|
||||
- python: "pypy3.3-5.2-alpha1"
|
||||
- python: "pypy"
|
||||
- python: "pypy3"
|
||||
- python: '3.6'
|
||||
- python: '2.7'
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
|
|
40
CHANGES.rst
40
CHANGES.rst
|
@ -3,6 +3,46 @@ Changelog (Pillow)
|
|||
|
||||
4.3.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Faster filter operations for Kernel, Gaussian, and Unsharp Mask filters #2679
|
||||
[homm]
|
||||
|
||||
- EPS: Add showpage to force rendering of some EPS images #2636
|
||||
[kaplun]
|
||||
|
||||
- DOC: Fix type of palette parameter in Image.quantize. #2703
|
||||
[kkopachev]
|
||||
|
||||
- DOC: Fix Ico docs to match code #2712
|
||||
[hugovk]
|
||||
|
||||
- Added file pointer save to SpiderImagePlugin #2647
|
||||
[radarhere]
|
||||
|
||||
- Add targa version 2 footer #2713
|
||||
[jhultgre]
|
||||
|
||||
- Removed redundant lines #2714
|
||||
[radarhere]
|
||||
|
||||
- Travis CI: Use default pypy/pypy3 #2721
|
||||
[hugovk]
|
||||
|
||||
- Fix for SystemError when rendering an empty string, added in 4.2.0 #2706
|
||||
[wiredfool]
|
||||
|
||||
- Fix for memory leaks in font handling added in 4.2.0 #2634
|
||||
[wiredfool]
|
||||
|
||||
- Tests: cleanup, more tests. Fixed WMF save handler #2689
|
||||
[radarhere]
|
||||
|
||||
- Removed debugging interface for Image.core.grabclipboard #2708
|
||||
[radarhere]
|
||||
|
||||
- Doc syntax fix #2710
|
||||
[radarhere]
|
||||
|
||||
- Faster packing and unpacking for RGB, LA, and related storage modes #2693
|
||||
[homm]
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ def Ghostscript(tile, size, fp, scale=1):
|
|||
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
|
||||
# adjust for image origin
|
||||
"-f", infile, # input file
|
||||
"-c", "showpage", # showpage (see: https://bugs.ghostscript.com/show_bug.cgi?id=698272)
|
||||
]
|
||||
|
||||
if gs_windows_binary is not None:
|
||||
|
|
11
PIL/Image.py
11
PIL/Image.py
|
@ -992,7 +992,7 @@ class Image(object):
|
|||
2 = fast octree
|
||||
3 = libimagequant
|
||||
:param kmeans: Integer
|
||||
:param palette: Quantize to the :py:class:`PIL.ImagingPalette` palette.
|
||||
:param palette: Quantize to the palette of given :py:class:`PIL.Image.Image`.
|
||||
:returns: A new image
|
||||
|
||||
"""
|
||||
|
@ -1114,6 +1114,8 @@ class Image(object):
|
|||
:param filter: Filter kernel.
|
||||
:returns: An :py:class:`~PIL.Image.Image` object. """
|
||||
|
||||
from . import ImageFilter
|
||||
|
||||
self.load()
|
||||
|
||||
if isinstance(filter, collections.Callable):
|
||||
|
@ -1122,9 +1124,10 @@ class Image(object):
|
|||
raise TypeError("filter argument should be ImageFilter.Filter " +
|
||||
"instance or class")
|
||||
|
||||
if self.im.bands == 1:
|
||||
multiband = isinstance(filter, ImageFilter.MultibandFilter)
|
||||
if self.im.bands == 1 or multiband:
|
||||
return self._new(filter.filter(self.im))
|
||||
# fix to handle multiband images since _imaging doesn't
|
||||
|
||||
ims = []
|
||||
for c in range(self.im.bands):
|
||||
ims.append(self._new(filter.filter(self.im.getband(c))))
|
||||
|
@ -1494,7 +1497,6 @@ class Image(object):
|
|||
mode = getmodebase(self.mode) + "A"
|
||||
try:
|
||||
self.im.setmode(mode)
|
||||
self.pyaccess = None
|
||||
except (AttributeError, ValueError):
|
||||
# do things the hard way
|
||||
im = self.im.convert(mode)
|
||||
|
@ -1602,7 +1604,6 @@ class Image(object):
|
|||
self.load()
|
||||
if self.readonly:
|
||||
self._copy()
|
||||
self.pyaccess = None
|
||||
self.load()
|
||||
|
||||
if self.pyaccess:
|
||||
|
|
|
@ -22,7 +22,11 @@ class Filter(object):
|
|||
pass
|
||||
|
||||
|
||||
class Kernel(Filter):
|
||||
class MultibandFilter(Filter):
|
||||
pass
|
||||
|
||||
|
||||
class Kernel(MultibandFilter):
|
||||
"""
|
||||
Create a convolution kernel. The current version only
|
||||
supports 3x3 and 5x5 integer and floating point kernels.
|
||||
|
@ -142,7 +146,7 @@ class ModeFilter(Filter):
|
|||
return image.modefilter(self.size)
|
||||
|
||||
|
||||
class GaussianBlur(Filter):
|
||||
class GaussianBlur(MultibandFilter):
|
||||
"""Gaussian blur filter.
|
||||
|
||||
:param radius: Blur radius.
|
||||
|
@ -156,7 +160,7 @@ class GaussianBlur(Filter):
|
|||
return image.gaussian_blur(self.radius)
|
||||
|
||||
|
||||
class UnsharpMask(Filter):
|
||||
class UnsharpMask(MultibandFilter):
|
||||
"""Unsharp mask filter.
|
||||
|
||||
See Wikipedia's entry on `digital unsharp masking`_ for an explanation of
|
||||
|
|
|
@ -72,8 +72,7 @@ def grabclipboard():
|
|||
os.unlink(filepath)
|
||||
return im
|
||||
else:
|
||||
debug = 0 # temporary interface
|
||||
data = Image.core.grabclipboard(debug)
|
||||
data = Image.core.grabclipboard()
|
||||
if isinstance(data, bytes):
|
||||
from . import BmpImagePlugin
|
||||
import io
|
||||
|
|
|
@ -267,17 +267,11 @@ def _save(im, fp, filename):
|
|||
raise IOError("Error creating Spider header")
|
||||
|
||||
# write the SPIDER header
|
||||
try:
|
||||
fp = open(filename, 'wb')
|
||||
except:
|
||||
raise IOError("Unable to open %s for writing" % filename)
|
||||
fp.writelines(hdr)
|
||||
|
||||
rawmode = "F;32NF" # 32-bit native floating point
|
||||
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])
|
||||
|
||||
fp.close()
|
||||
|
||||
|
||||
def _save_spider(im, fp, filename):
|
||||
# get the filename extension and register it with Image
|
||||
|
|
|
@ -139,16 +139,13 @@ SAVE = {
|
|||
}
|
||||
|
||||
|
||||
def _save(im, fp, filename, check=0):
|
||||
def _save(im, fp, filename):
|
||||
|
||||
try:
|
||||
rawmode, bits, colormaptype, imagetype = SAVE[im.mode]
|
||||
except KeyError:
|
||||
raise IOError("cannot write mode %s as TGA" % im.mode)
|
||||
|
||||
if check:
|
||||
return check
|
||||
|
||||
if colormaptype:
|
||||
colormapfirst, colormaplength, colormapentry = 0, 256, 24
|
||||
else:
|
||||
|
@ -182,6 +179,9 @@ def _save(im, fp, filename, check=0):
|
|||
ImageFile._save(
|
||||
im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))])
|
||||
|
||||
# write targa version 2 footer
|
||||
fp.write(b"\000" * 8 + b"TRUEVISION-XFILE." + b"\000")
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
# Registry
|
||||
|
|
|
@ -153,7 +153,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
|
|||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
if _handler is None or not hasattr("_handler", "save"):
|
||||
if _handler is None or not hasattr(_handler, "save"):
|
||||
raise IOError("WMF save handler not installed")
|
||||
_handler.save(im, fp, filename)
|
||||
|
||||
|
|
|
@ -170,6 +170,41 @@ class PillowTestCase(unittest.TestCase):
|
|||
return Image.open(outfile)
|
||||
raise IOError()
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
|
||||
class PillowLeakTestCase(PillowTestCase):
|
||||
# requires unix/osx
|
||||
iterations = 100 # count
|
||||
mem_limit = 512 # k
|
||||
|
||||
def _get_mem_usage(self):
|
||||
"""
|
||||
Gets the RUSAGE memory usage, returns in K. Encapsulates the difference
|
||||
between OSX and Linux rss reporting
|
||||
|
||||
:returns; memory usage in kilobytes
|
||||
"""
|
||||
|
||||
from resource import getpagesize, getrusage, RUSAGE_SELF
|
||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||
if sys.platform == 'darwin':
|
||||
# man 2 getrusage:
|
||||
# ru_maxrss the maximum resident set size utilized (in bytes).
|
||||
return mem / 1024 # Kb
|
||||
else:
|
||||
# linux
|
||||
# man 2 getrusage
|
||||
# ru_maxrss (since Linux 2.6.32)
|
||||
# This is the maximum resident set size used (in kilobytes).
|
||||
return mem # Kb
|
||||
|
||||
def _test_leak(self, core):
|
||||
start_mem = self._get_mem_usage()
|
||||
for cycle in range(self.iterations):
|
||||
core()
|
||||
mem = (self._get_mem_usage() - start_mem)
|
||||
self.assertLess(mem, self.mem_limit,
|
||||
msg='memory usage limit exceeded in iteration %d' % cycle)
|
||||
|
||||
|
||||
# helpers
|
||||
|
||||
|
|
BIN
Tests/images/reqd_showpage.eps
Normal file
BIN
Tests/images/reqd_showpage.eps
Normal file
Binary file not shown.
BIN
Tests/images/reqd_showpage.png
Normal file
BIN
Tests/images/reqd_showpage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
|
@ -36,7 +36,7 @@ class TestDecompressionBomb(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assert_warning(Image.DecompressionBombWarning,
|
||||
lambda: Image.open(TEST_FILE))
|
||||
Image.open, TEST_FILE)
|
||||
|
||||
class TestDecompressionCrop(PillowTestCase):
|
||||
|
||||
|
@ -52,7 +52,7 @@ class TestDecompressionCrop(PillowTestCase):
|
|||
# same decompression bomb warnings on them.
|
||||
box = (0, 0, self.src.width * 2, self.src.height * 2)
|
||||
self.assert_warning(Image.DecompressionBombWarning,
|
||||
lambda: self.src.crop(box))
|
||||
self.src.crop, box)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -51,13 +51,13 @@ class TestFeatures(PillowTestCase):
|
|||
# Arrange
|
||||
codec = "unsupported_codec"
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError, lambda: features.check_codec(codec))
|
||||
self.assertRaises(ValueError, features.check_codec, codec)
|
||||
|
||||
def test_unsupported_module(self):
|
||||
# Arrange
|
||||
module = "unsupported_module"
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError, lambda: features.check_module(module))
|
||||
self.assertRaises(ValueError, features.check_module, module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -28,7 +28,7 @@ class TestFileBmp(PillowTestCase):
|
|||
def test_invalid_file(self):
|
||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: BmpImagePlugin.BmpImageFile(fp))
|
||||
BmpImagePlugin.BmpImageFile, fp)
|
||||
|
||||
def test_save_to_bytes(self):
|
||||
output = io.BytesIO()
|
||||
|
|
|
@ -24,8 +24,7 @@ class TestFileBufrStub(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
BufrStubImagePlugin.BufrStubImageFile(invalid_file))
|
||||
BufrStubImagePlugin.BufrStubImageFile, invalid_file)
|
||||
|
||||
def test_load(self):
|
||||
# Arrange
|
||||
|
@ -40,7 +39,7 @@ class TestFileBufrStub(PillowTestCase):
|
|||
tmpfile = self.tempfile("temp.bufr")
|
||||
|
||||
# Act / Assert: stub cannot save without an implemented handler
|
||||
self.assertRaises(IOError, lambda: im.save(tmpfile))
|
||||
self.assertRaises(IOError, im.save, tmpfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -21,7 +21,7 @@ class TestFileCur(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: CurImagePlugin.CurImageFile(invalid_file))
|
||||
CurImagePlugin.CurImageFile, invalid_file)
|
||||
|
||||
no_cursors_file = "Tests/images/no_cursors.cur"
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class TestFileDcx(PillowTestCase):
|
|||
def test_invalid_file(self):
|
||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: DcxImagePlugin.DcxImageFile(fp))
|
||||
DcxImagePlugin.DcxImageFile, fp)
|
||||
|
||||
def test_tell(self):
|
||||
# Arrange
|
||||
|
@ -58,7 +58,7 @@ class TestFileDcx(PillowTestCase):
|
|||
frame = 999 # too big on purpose
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(EOFError, lambda: im.seek(frame))
|
||||
self.assertRaises(EOFError, im.seek, frame)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -55,7 +55,7 @@ class TestFileEps(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: EpsImagePlugin.EpsImageFile(invalid_file))
|
||||
EpsImagePlugin.EpsImageFile, invalid_file)
|
||||
|
||||
def test_cmyk(self):
|
||||
cmyk_image = Image.open("Tests/images/pil_sample_cmyk.eps")
|
||||
|
@ -71,6 +71,16 @@ class TestFileEps(PillowTestCase):
|
|||
target = Image.open('Tests/images/pil_sample_rgb.jpg')
|
||||
self.assert_image_similar(cmyk_image, target, 10)
|
||||
|
||||
def test_showpage(self):
|
||||
# See https://github.com/python-pillow/Pillow/issues/2615
|
||||
plot_image = Image.open("Tests/images/reqd_showpage.eps")
|
||||
target = Image.open("Tests/images/reqd_showpage.png")
|
||||
|
||||
#should not crash/hang
|
||||
plot_image.load()
|
||||
# fonts could be slightly different
|
||||
self.assert_image_similar(plot_image, target, 2)
|
||||
|
||||
def test_file_object(self):
|
||||
# issue 479
|
||||
image1 = Image.open(file1)
|
||||
|
@ -97,7 +107,7 @@ class TestFileEps(PillowTestCase):
|
|||
def test_image_mode_not_supported(self):
|
||||
im = hopper("RGBA")
|
||||
tmpfile = self.tempfile('temp.eps')
|
||||
self.assertRaises(ValueError, lambda: im.save(tmpfile))
|
||||
self.assertRaises(ValueError, im.save, tmpfile)
|
||||
|
||||
def test_render_scale1(self):
|
||||
# We need png support for these render test
|
||||
|
|
|
@ -24,8 +24,7 @@ class TestFileFitsStub(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
FitsStubImagePlugin.FITSStubImageFile(invalid_file))
|
||||
FitsStubImagePlugin.FITSStubImageFile, invalid_file)
|
||||
|
||||
def test_load(self):
|
||||
# Arrange
|
||||
|
@ -41,10 +40,10 @@ class TestFileFitsStub(PillowTestCase):
|
|||
dummy_filename = "dummy.filename"
|
||||
|
||||
# Act / Assert: stub cannot save without an implemented handler
|
||||
self.assertRaises(IOError, lambda: im.save(dummy_filename))
|
||||
self.assertRaises(IOError, im.save, dummy_filename)
|
||||
self.assertRaises(
|
||||
IOError,
|
||||
lambda: FitsStubImagePlugin._save(im, dummy_fp, dummy_filename))
|
||||
FitsStubImagePlugin._save, im, dummy_fp, dummy_filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -41,7 +41,7 @@ class TestFileFli(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: FliImagePlugin.FliImageFile(invalid_file))
|
||||
FliImagePlugin.FliImageFile, invalid_file)
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open(static_test_file)
|
||||
|
@ -71,7 +71,7 @@ class TestFileFli(PillowTestCase):
|
|||
self.assertEqual(im.tell(), 0)
|
||||
|
||||
# Test seek past end of file
|
||||
self.assertRaises(EOFError, lambda: im.seek(2))
|
||||
self.assertRaises(EOFError, im.seek, 2)
|
||||
|
||||
def test_seek_tell(self):
|
||||
im = Image.open(animated_test_file)
|
||||
|
|
|
@ -9,12 +9,12 @@ class TestFileFpx(PillowTestCase):
|
|||
# Test an invalid OLE file
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: FpxImagePlugin.FpxImageFile(invalid_file))
|
||||
FpxImagePlugin.FpxImageFile, invalid_file)
|
||||
|
||||
# Test a valid OLE file, but not an FPX file
|
||||
ole_file = "Tests/images/test-ole-file.doc"
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: FpxImagePlugin.FpxImageFile(ole_file))
|
||||
FpxImagePlugin.FpxImageFile, ole_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -9,7 +9,7 @@ class TestFileGbr(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: GbrImagePlugin.GbrImageFile(invalid_file))
|
||||
GbrImagePlugin.GbrImageFile, invalid_file)
|
||||
|
||||
def test_gbr_file(self):
|
||||
im = Image.open('Tests/images/gbr.gbr')
|
||||
|
|
|
@ -31,7 +31,7 @@ class TestFileGif(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: GifImagePlugin.GifImageFile(invalid_file))
|
||||
GifImagePlugin.GifImageFile, invalid_file)
|
||||
|
||||
def test_optimize(self):
|
||||
def test_grayscale(optimize):
|
||||
|
@ -375,29 +375,31 @@ class TestFileGif(PillowTestCase):
|
|||
def test_version(self):
|
||||
out = self.tempfile('temp.gif')
|
||||
|
||||
# Test that GIF87a is used by default
|
||||
im = Image.new('L', (100, 100), '#000')
|
||||
def assertVersionAfterSave(im, version):
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
self.assertEqual(reread.info["version"], b"GIF87a")
|
||||
self.assertEqual(reread.info["version"], version)
|
||||
|
||||
# Test that GIF87a is used by default
|
||||
im = Image.new('L', (100, 100), '#000')
|
||||
assertVersionAfterSave(im, b"GIF87a")
|
||||
|
||||
# Test setting the version to 89a
|
||||
im = Image.new('L', (100, 100), '#000')
|
||||
im.info["version"] = b"89a"
|
||||
assertVersionAfterSave(im, b"GIF89a")
|
||||
|
||||
# Test that adding a GIF89a feature changes the version
|
||||
im.info["transparency"] = 1
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
self.assertEqual(reread.info["version"], b"GIF89a")
|
||||
assertVersionAfterSave(im, b"GIF89a")
|
||||
|
||||
# Test that a GIF87a image is also saved in that format
|
||||
im = Image.open("Tests/images/test.colors.gif")
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
self.assertEqual(reread.info["version"], b"GIF87a")
|
||||
assertVersionAfterSave(im, b"GIF87a")
|
||||
|
||||
# Test that a GIF89a image is also saved in that format
|
||||
im.info["version"] = b"GIF89a"
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
self.assertEqual(reread.info["version"], b"GIF87a")
|
||||
assertVersionAfterSave(im, b"GIF87a")
|
||||
|
||||
def test_append_images(self):
|
||||
out = self.tempfile('temp.gif')
|
||||
|
|
|
@ -10,13 +10,13 @@ class TestImage(PillowTestCase):
|
|||
GimpPaletteFile(fp)
|
||||
|
||||
with open('Tests/images/hopper.jpg', 'rb') as fp:
|
||||
self.assertRaises(SyntaxError, lambda: GimpPaletteFile(fp))
|
||||
self.assertRaises(SyntaxError, GimpPaletteFile, fp)
|
||||
|
||||
with open('Tests/images/bad_palette_file.gpl', 'rb') as fp:
|
||||
self.assertRaises(SyntaxError, lambda: GimpPaletteFile(fp))
|
||||
self.assertRaises(SyntaxError, GimpPaletteFile, fp)
|
||||
|
||||
with open('Tests/images/bad_palette_entry.gpl', 'rb') as fp:
|
||||
self.assertRaises(ValueError, lambda: GimpPaletteFile(fp))
|
||||
self.assertRaises(ValueError, GimpPaletteFile, fp)
|
||||
|
||||
def test_get_palette(self):
|
||||
# Arrange
|
||||
|
|
|
@ -24,8 +24,7 @@ class TestFileGribStub(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
GribStubImagePlugin.GribStubImageFile(invalid_file))
|
||||
GribStubImagePlugin.GribStubImageFile, invalid_file)
|
||||
|
||||
def test_load(self):
|
||||
# Arrange
|
||||
|
@ -40,7 +39,7 @@ class TestFileGribStub(PillowTestCase):
|
|||
tmpfile = self.tempfile("temp.grib")
|
||||
|
||||
# Act / Assert: stub cannot save without an implemented handler
|
||||
self.assertRaises(IOError, lambda: im.save(tmpfile))
|
||||
self.assertRaises(IOError, im.save, tmpfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -24,8 +24,7 @@ class TestFileHdf5Stub(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
Hdf5StubImagePlugin.HDF5StubImageFile(invalid_file))
|
||||
Hdf5StubImagePlugin.HDF5StubImageFile, invalid_file)
|
||||
|
||||
def test_load(self):
|
||||
# Arrange
|
||||
|
@ -41,10 +40,10 @@ class TestFileHdf5Stub(PillowTestCase):
|
|||
dummy_filename = "dummy.filename"
|
||||
|
||||
# Act / Assert: stub cannot save without an implemented handler
|
||||
self.assertRaises(IOError, lambda: im.save(dummy_filename))
|
||||
self.assertRaises(IOError, im.save, dummy_filename)
|
||||
self.assertRaises(
|
||||
IOError,
|
||||
lambda: Hdf5StubImagePlugin._save(im, dummy_fp, dummy_filename))
|
||||
Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
|
||||
from PIL import Image
|
||||
from PIL import Image, IcnsImagePlugin
|
||||
|
||||
import io
|
||||
import sys
|
||||
|
||||
# sample icon file
|
||||
|
@ -82,6 +83,23 @@ class TestFileIcns(PillowTestCase):
|
|||
self.assertEqual(im2.mode, 'RGBA')
|
||||
self.assertEqual(im2.size, (wr, hr))
|
||||
|
||||
def test_getimage(self):
|
||||
with open(TEST_FILE, 'rb') as fp:
|
||||
icns_file = IcnsImagePlugin.IcnsFile(fp)
|
||||
|
||||
im = icns_file.getimage()
|
||||
self.assertEqual(im.mode, "RGBA")
|
||||
self.assertEqual(im.size, (1024, 1024))
|
||||
|
||||
im = icns_file.getimage((512, 512))
|
||||
self.assertEqual(im.mode, "RGBA")
|
||||
self.assertEqual(im.size, (512, 512))
|
||||
|
||||
def test_not_an_icns_file(self):
|
||||
with io.BytesIO(b'invalid\n') as fp:
|
||||
self.assertRaises(SyntaxError,
|
||||
IcnsImagePlugin.IcnsFile, fp)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -18,7 +18,7 @@ class TestFileIco(PillowTestCase):
|
|||
def test_invalid_file(self):
|
||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: IcoImagePlugin.IcoImageFile(fp))
|
||||
IcoImagePlugin.IcoImageFile, fp)
|
||||
|
||||
def test_save_to_bytes(self):
|
||||
output = io.BytesIO()
|
||||
|
|
|
@ -43,18 +43,27 @@ class TestFileIm(PillowTestCase):
|
|||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_roundtrip(self):
|
||||
for mode in ["RGB", "P"]:
|
||||
out = self.tempfile('temp.im')
|
||||
im = hopper()
|
||||
im = hopper(mode)
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
|
||||
self.assert_image_equal(reread, im)
|
||||
|
||||
def test_save_unsupported_mode(self):
|
||||
out = self.tempfile('temp.im')
|
||||
im = hopper("HSV")
|
||||
self.assertRaises(ValueError, im.save, out)
|
||||
|
||||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: ImImagePlugin.ImImageFile(invalid_file))
|
||||
ImImagePlugin.ImImageFile, invalid_file)
|
||||
|
||||
def test_number(self):
|
||||
self.assertEqual(1.2, ImImagePlugin.number("1.2"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -314,7 +314,7 @@ class TestFileJpeg(PillowTestCase):
|
|||
self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
|
||||
|
||||
self.assertRaises(
|
||||
TypeError, lambda: self.roundtrip(hopper(), subsampling="1:1:1"))
|
||||
TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
|
||||
|
||||
def test_exif(self):
|
||||
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||
|
@ -423,18 +423,18 @@ class TestFileJpeg(PillowTestCase):
|
|||
self._n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
|
||||
|
||||
# not a sequence
|
||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables='a'))
|
||||
self.assertRaises(Exception, self.roundtrip, im, qtables='a')
|
||||
# sequence wrong length
|
||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[]))
|
||||
self.assertRaises(Exception, self.roundtrip, im, qtables=[])
|
||||
# sequence wrong length
|
||||
self.assertRaises(Exception,
|
||||
lambda: self.roundtrip(im, qtables=[1, 2, 3, 4, 5]))
|
||||
self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
|
||||
|
||||
# qtable entry not a sequence
|
||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[1]))
|
||||
self.assertRaises(Exception, self.roundtrip, im, qtables=[1])
|
||||
# qtable entry has wrong number of items
|
||||
self.assertRaises(Exception,
|
||||
lambda: self.roundtrip(im, qtables=[[1, 2, 3, 4]]))
|
||||
self.roundtrip, im, qtables=[[1, 2, 3, 4]])
|
||||
|
||||
@unittest.skipUnless(djpeg_available(), "djpeg not available")
|
||||
def test_load_djpeg(self):
|
||||
|
@ -479,7 +479,7 @@ class TestFileJpeg(PillowTestCase):
|
|||
# Act
|
||||
# Shouldn't raise error
|
||||
fn = "Tests/images/sugarshack_bad_mpo_header.jpg"
|
||||
im = self.assert_warning(UserWarning, lambda: Image.open(fn))
|
||||
im = self.assert_warning(UserWarning, Image.open, fn)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(im.format, "JPEG")
|
||||
|
@ -584,7 +584,7 @@ class TestFileCloseW32(PillowTestCase):
|
|||
im = Image.open(tmpfile)
|
||||
fp = im.fp
|
||||
self.assertFalse(fp.closed)
|
||||
self.assertRaises(Exception, lambda: os.remove(tmpfile))
|
||||
self.assertRaises(Exception, os.remove, tmpfile)
|
||||
im.load()
|
||||
self.assertTrue(fp.closed)
|
||||
# this should not fail, as load should have closed the file.
|
||||
|
|
|
@ -44,8 +44,7 @@ class TestFileJpeg2k(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file))
|
||||
Jpeg2KImagePlugin.Jpeg2KImageFile, invalid_file)
|
||||
|
||||
def test_bytesio(self):
|
||||
with open('Tests/images/test-card-lossless.jp2', 'rb') as f:
|
||||
|
|
|
@ -362,10 +362,9 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
im = hopper('RGB')
|
||||
out = self.tempfile('temp.tif')
|
||||
|
||||
self.assertRaises(
|
||||
IOError, lambda: im.save(out, compression='tiff_ccitt'))
|
||||
self.assertRaises(IOError, lambda: im.save(out, compression='group3'))
|
||||
self.assertRaises(IOError, lambda: im.save(out, compression='group4'))
|
||||
self.assertRaises(IOError, im.save, out, compression='tiff_ccitt')
|
||||
self.assertRaises(IOError, im.save, out, compression='group3')
|
||||
self.assertRaises(IOError, im.save, out, compression='group4')
|
||||
|
||||
def test_fp_leak(self):
|
||||
im = Image.open("Tests/images/hopper_g4_500.tif")
|
||||
|
@ -373,10 +372,10 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
|
||||
os.fstat(fn)
|
||||
im.load() # this should close it.
|
||||
self.assertRaises(OSError, lambda: os.fstat(fn))
|
||||
self.assertRaises(OSError, os.fstat, fn)
|
||||
im = None # this should force even more closed.
|
||||
self.assertRaises(OSError, lambda: os.fstat(fn))
|
||||
self.assertRaises(OSError, lambda: os.close(fn))
|
||||
self.assertRaises(OSError, os.fstat, fn)
|
||||
self.assertRaises(OSError, os.close, fn)
|
||||
|
||||
def test_multipage(self):
|
||||
# issue #862
|
||||
|
|
|
@ -9,8 +9,7 @@ class TestFileMcIdas(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
McIdasImagePlugin.McIdasImageFile(invalid_file))
|
||||
McIdasImagePlugin.McIdasImageFile, invalid_file)
|
||||
|
||||
def test_valid_file(self):
|
||||
# Arrange
|
||||
|
|
|
@ -42,19 +42,19 @@ class TestFileMic(PillowTestCase):
|
|||
im.seek(0)
|
||||
self.assertEqual(im.tell(), 0)
|
||||
|
||||
self.assertRaises(EOFError, lambda: im.seek(99))
|
||||
self.assertRaises(EOFError, im.seek, 99)
|
||||
self.assertEqual(im.tell(), 0)
|
||||
|
||||
def test_invalid_file(self):
|
||||
# Test an invalid OLE file
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: MicImagePlugin.MicImageFile(invalid_file))
|
||||
MicImagePlugin.MicImageFile, invalid_file)
|
||||
|
||||
# Test a valid OLE file, but not a MIC file
|
||||
ole_file = "Tests/images/test-ole-file.doc"
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: MicImagePlugin.MicImageFile(ole_file))
|
||||
MicImagePlugin.MicImageFile, ole_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -26,7 +26,7 @@ class TestFileMsp(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: MspImagePlugin.MspImageFile(invalid_file))
|
||||
MspImagePlugin.MspImageFile, invalid_file)
|
||||
|
||||
def test_bad_checksum(self):
|
||||
# Arrange
|
||||
|
@ -35,7 +35,7 @@ class TestFileMsp(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: MspImagePlugin.MspImageFile(bad_checksum))
|
||||
MspImagePlugin.MspImageFile, bad_checksum)
|
||||
|
||||
def test_open_windows_v1(self):
|
||||
# Arrange
|
||||
|
@ -77,7 +77,7 @@ class TestFileMsp(PillowTestCase):
|
|||
filename = self.tempfile("temp.msp")
|
||||
|
||||
# Act/Assert
|
||||
self.assertRaises(IOError, lambda: im.save(filename))
|
||||
self.assertRaises(IOError, im.save, filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -51,7 +51,7 @@ class TestFilePalm(PillowTestCase):
|
|||
mode = "RGB"
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(IOError, lambda: self.helper_save_as_palm(mode))
|
||||
self.assertRaises(IOError, self.helper_save_as_palm, mode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -21,13 +21,14 @@ class TestFilePcx(PillowTestCase):
|
|||
|
||||
# Test an unsupported mode
|
||||
f = self.tempfile("temp.pcx")
|
||||
self.assertRaises(ValueError, lambda: hopper("RGBA").save(f))
|
||||
im = hopper("RGBA")
|
||||
self.assertRaises(ValueError, im.save, f)
|
||||
|
||||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: PcxImagePlugin.PcxImageFile(invalid_file))
|
||||
PcxImagePlugin.PcxImageFile, invalid_file)
|
||||
|
||||
def test_odd(self):
|
||||
# see issue #523, odd sized images should have a stride that's even.
|
||||
|
|
|
@ -59,7 +59,7 @@ class TestFilePdf(PillowTestCase):
|
|||
im = hopper("LA")
|
||||
outfile = self.tempfile("temp_LA.pdf")
|
||||
|
||||
self.assertRaises(ValueError, lambda: im.save(outfile))
|
||||
self.assertRaises(ValueError, im.save, outfile)
|
||||
|
||||
def test_save_all(self):
|
||||
# Single frame image
|
||||
|
|
|
@ -22,7 +22,7 @@ class TestFilePixar(PillowTestCase):
|
|||
|
||||
self.assertRaises(
|
||||
SyntaxError,
|
||||
lambda: PixarImagePlugin.PixarImageFile(invalid_file))
|
||||
PixarImagePlugin.PixarImageFile, invalid_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from helper import unittest, PillowTestCase, PillowLeakTestCase, hopper
|
||||
from PIL import Image, ImageFile, PngImagePlugin
|
||||
|
||||
from io import BytesIO
|
||||
|
@ -7,9 +7,6 @@ import sys
|
|||
|
||||
codecs = dir(Image.core)
|
||||
|
||||
# For Truncated phng memory leak
|
||||
MEM_LIMIT = 2 # max increase in MB
|
||||
ITERATIONS = 100 # Leak is 56k/iteration, this will leak 5.6megs
|
||||
|
||||
# sample png stream
|
||||
|
||||
|
@ -87,14 +84,14 @@ class TestFilePng(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: PngImagePlugin.PngImageFile(invalid_file))
|
||||
PngImagePlugin.PngImageFile, invalid_file)
|
||||
|
||||
def test_broken(self):
|
||||
# Check reading of totally broken files. In this case, the test
|
||||
# file was checked into Subversion as a text file.
|
||||
|
||||
test_file = "Tests/images/broken.png"
|
||||
self.assertRaises(IOError, lambda: Image.open(test_file))
|
||||
self.assertRaises(IOError, Image.open, test_file)
|
||||
|
||||
def test_bad_text(self):
|
||||
# Make sure PIL can read malformed tEXt chunks (@PIL152)
|
||||
|
@ -424,7 +421,7 @@ class TestFilePng(PillowTestCase):
|
|||
data = b'\x89' + fd.read()
|
||||
|
||||
pngfile = BytesIO(data)
|
||||
self.assertRaises(IOError, lambda: Image.open(pngfile))
|
||||
self.assertRaises(IOError, Image.open, pngfile)
|
||||
|
||||
def test_trns_rgb(self):
|
||||
# Check writing and reading of tRNS chunks for RGB images.
|
||||
|
@ -505,7 +502,7 @@ class TestFilePng(PillowTestCase):
|
|||
im.convert("P").save(test_file, dpi=(100, 100))
|
||||
|
||||
chunks = []
|
||||
fp = open(test_file, "rb")
|
||||
with open(test_file, "rb") as fp:
|
||||
fp.read(8)
|
||||
png = PngImagePlugin.PngStream(fp)
|
||||
while True:
|
||||
|
@ -531,28 +528,22 @@ class TestFilePng(PillowTestCase):
|
|||
# pHYs - before IDAT
|
||||
self.assertLess(chunks.index(b"pHYs"), chunks.index(b"IDAT"))
|
||||
|
||||
def test_getchunks(self):
|
||||
im = hopper()
|
||||
|
||||
chunks = PngImagePlugin.getchunks(im)
|
||||
self.assertEqual(len(chunks), 3)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
|
||||
class TestTruncatedPngPLeaks(PillowTestCase):
|
||||
class TestTruncatedPngPLeaks(PillowLeakTestCase):
|
||||
mem_limit = 2*1024 # max increase in K
|
||||
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs
|
||||
|
||||
def setUp(self):
|
||||
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
|
||||
self.skipTest("zip/deflate support not available")
|
||||
|
||||
def _get_mem_usage(self):
|
||||
from resource import getpagesize, getrusage, RUSAGE_SELF
|
||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||
if sys.platform == 'darwin':
|
||||
# man 2 getrusage:
|
||||
# ru_maxrss the maximum resident set size utilized (in bytes).
|
||||
return mem / 1024 / 1024 # megs
|
||||
else:
|
||||
# linux
|
||||
# man 2 getrusage
|
||||
# ru_maxrss (since Linux 2.6.32)
|
||||
# This is the maximum resident set size used (in kilobytes).
|
||||
return mem / 1024 # megs
|
||||
|
||||
def test_leak_load(self):
|
||||
with open('Tests/images/hopper.png', 'rb') as f:
|
||||
DATA = BytesIO(f.read(16 * 1024))
|
||||
|
@ -560,13 +551,13 @@ class TestTruncatedPngPLeaks(PillowTestCase):
|
|||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
with Image.open(DATA) as im:
|
||||
im.load()
|
||||
start_mem = self._get_mem_usage()
|
||||
try:
|
||||
for _ in range(ITERATIONS):
|
||||
|
||||
def core():
|
||||
with Image.open(DATA) as im:
|
||||
im.load()
|
||||
mem = (self._get_mem_usage() - start_mem)
|
||||
self.assertLess(mem, MEM_LIMIT, msg='memory usage limit exceeded')
|
||||
|
||||
try:
|
||||
self._test_leak(core)
|
||||
finally:
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestFilePpm(PillowTestCase):
|
|||
with open(path, 'w') as f:
|
||||
f.write('P6')
|
||||
|
||||
self.assertRaises(ValueError, lambda: Image.open(path))
|
||||
self.assertRaises(ValueError, Image.open, path)
|
||||
|
||||
def test_neg_ppm(self):
|
||||
# Storage.c accepted negative values for xsize, ysize. the
|
||||
|
|
|
@ -21,7 +21,7 @@ class TestImagePsd(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: PsdImagePlugin.PsdImageFile(invalid_file))
|
||||
PsdImagePlugin.PsdImageFile, invalid_file)
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open("Tests/images/hopper_merged.psd")
|
||||
|
@ -66,7 +66,7 @@ class TestImagePsd(PillowTestCase):
|
|||
def test_seek_eoferror(self):
|
||||
im = Image.open(test_file)
|
||||
|
||||
self.assertRaises(EOFError, lambda: im.seek(-1))
|
||||
self.assertRaises(EOFError, im.seek, -1)
|
||||
|
||||
def test_icc_profile(self):
|
||||
im = Image.open(test_file)
|
||||
|
|
|
@ -42,8 +42,7 @@ class TestFileSgi(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(ValueError,
|
||||
lambda:
|
||||
SgiImagePlugin.SgiImageFile(invalid_file))
|
||||
SgiImagePlugin.SgiImageFile, invalid_file)
|
||||
|
||||
def test_write(self):
|
||||
def roundtrip(img):
|
||||
|
@ -62,14 +61,14 @@ class TestFileSgi(PillowTestCase):
|
|||
im = hopper('LA')
|
||||
out = self.tempfile('temp.sgi')
|
||||
|
||||
self.assertRaises(ValueError, lambda: im.save(out, format='sgi'))
|
||||
self.assertRaises(ValueError, 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'))
|
||||
self.assertRaises(ValueError, im.save, out, format='sgi')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -4,6 +4,8 @@ from PIL import Image
|
|||
from PIL import ImageSequence
|
||||
from PIL import SpiderImagePlugin
|
||||
|
||||
import tempfile
|
||||
|
||||
TEST_FILE = "Tests/images/hopper.spider"
|
||||
|
||||
|
||||
|
@ -30,6 +32,21 @@ class TestImageSpider(PillowTestCase):
|
|||
self.assertEqual(im2.size, (128, 128))
|
||||
self.assertEqual(im2.format, "SPIDER")
|
||||
|
||||
def test_tempfile(self):
|
||||
# Arrange
|
||||
im = hopper()
|
||||
|
||||
# Act
|
||||
with tempfile.TemporaryFile() as fp:
|
||||
im.save(fp, "SPIDER")
|
||||
|
||||
# Assert
|
||||
fp.seek(0)
|
||||
reloaded = Image.open(fp)
|
||||
self.assertEqual(reloaded.mode, "F")
|
||||
self.assertEqual(reloaded.size, (128, 128))
|
||||
self.assertEqual(reloaded.format, "SPIDER")
|
||||
|
||||
def test_isSpiderImage(self):
|
||||
self.assertTrue(SpiderImagePlugin.isSpiderImage(TEST_FILE))
|
||||
|
||||
|
@ -84,12 +101,12 @@ class TestImageSpider(PillowTestCase):
|
|||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/invalid.spider"
|
||||
|
||||
self.assertRaises(IOError, lambda: Image.open(invalid_file))
|
||||
self.assertRaises(IOError, Image.open, invalid_file)
|
||||
|
||||
def test_nonstack_file(self):
|
||||
im = Image.open(TEST_FILE)
|
||||
|
||||
self.assertRaises(EOFError, lambda: im.seek(0))
|
||||
self.assertRaises(EOFError, im.seek, 0)
|
||||
|
||||
def test_nonstack_dos(self):
|
||||
im = Image.open(TEST_FILE)
|
||||
|
|
|
@ -24,7 +24,7 @@ class TestFileSun(PillowTestCase):
|
|||
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: SunImagePlugin.SunImageFile(invalid_file))
|
||||
SunImagePlugin.SunImageFile, invalid_file)
|
||||
|
||||
def test_im1(self):
|
||||
im = Image.open('Tests/images/sunraster.im1')
|
||||
|
|
|
@ -85,6 +85,10 @@ class TestFileTiff(PillowTestCase):
|
|||
im = Image.open("Tests/images/copyleft.tiff")
|
||||
self.assertEqual(im.mode, 'RGB')
|
||||
|
||||
def test_set_legacy_api(self):
|
||||
with self.assertRaises(Exception):
|
||||
ImageFileDirectory_v2.legacy_api = None
|
||||
|
||||
def test_xyres_tiff(self):
|
||||
filename = "Tests/images/pil168.tif"
|
||||
im = Image.open(filename)
|
||||
|
@ -140,11 +144,11 @@ class TestFileTiff(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: TiffImagePlugin.TiffImageFile(invalid_file))
|
||||
TiffImagePlugin.TiffImageFile, invalid_file)
|
||||
|
||||
TiffImagePlugin.PREFIXES.append(b"\xff\xd8\xff\xe0")
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: TiffImagePlugin.TiffImageFile(invalid_file))
|
||||
TiffImagePlugin.TiffImageFile, invalid_file)
|
||||
TiffImagePlugin.PREFIXES.pop()
|
||||
|
||||
def test_bad_exif(self):
|
||||
|
@ -163,7 +167,7 @@ class TestFileTiff(PillowTestCase):
|
|||
def test_save_unsupported_mode(self):
|
||||
im = hopper("HSV")
|
||||
outfile = self.tempfile("temp.tif")
|
||||
self.assertRaises(IOError, lambda: im.save(outfile))
|
||||
self.assertRaises(IOError, im.save, outfile)
|
||||
|
||||
def test_little_endian(self):
|
||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
||||
|
@ -340,7 +344,7 @@ class TestFileTiff(PillowTestCase):
|
|||
filename = "Tests/images/pil136.tiff"
|
||||
im = Image.open(filename)
|
||||
self.assertEqual(im.tell(), 0)
|
||||
self.assertRaises(EOFError, lambda: im.seek(1))
|
||||
self.assertRaises(EOFError, im.seek, 1)
|
||||
|
||||
def test__limit_rational_int(self):
|
||||
from PIL.TiffImagePlugin import _limit_rational
|
||||
|
@ -495,7 +499,7 @@ class TestFileTiff(PillowTestCase):
|
|||
with Image.open("Tests/images/uint16_1_4660.tif") as im:
|
||||
im.save(tmpfile)
|
||||
|
||||
f = open(tmpfile, 'rb')
|
||||
with open(tmpfile, 'rb') as f:
|
||||
im = Image.open(f)
|
||||
fp = im.fp
|
||||
self.assertFalse(fp.closed)
|
||||
|
@ -515,7 +519,7 @@ class TestFileTiffW32(PillowTestCase):
|
|||
im = Image.open(tmpfile)
|
||||
fp = im.fp
|
||||
self.assertFalse(fp.closed)
|
||||
self.assertRaises(Exception, lambda: os.remove(tmpfile))
|
||||
self.assertRaises(Exception, os.remove, tmpfile)
|
||||
im.load()
|
||||
self.assertTrue(fp.closed)
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
head = f.read(8)
|
||||
info = TiffImagePlugin.ImageFileDirectory(head)
|
||||
try:
|
||||
self.assert_warning(UserWarning, lambda: info.load(f))
|
||||
self.assert_warning(UserWarning, info.load, f)
|
||||
except struct.error:
|
||||
self.fail("Should not be struct errors there.")
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ class TestFileWebp(PillowTestCase):
|
|||
def test_write_unsupported_mode(self):
|
||||
temp_file = self.tempfile("temp.webp")
|
||||
|
||||
self.assertRaises(IOError, lambda: hopper("L").save(temp_file))
|
||||
im = hopper("L")
|
||||
self.assertRaises(IOError, im.save, temp_file)
|
||||
|
||||
def test_WebPEncode_with_invalid_args(self):
|
||||
self.assertRaises(TypeError, _webp.WebPEncode)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image
|
||||
from PIL import WmfImagePlugin
|
||||
|
||||
|
||||
class TestFileWmf(PillowTestCase):
|
||||
|
@ -26,12 +28,29 @@ class TestFileWmf(PillowTestCase):
|
|||
imref.load()
|
||||
self.assert_image_similar(im, imref, 2.0)
|
||||
|
||||
def test_register_handler(self):
|
||||
class TestHandler:
|
||||
methodCalled = False
|
||||
|
||||
def save(self, im, fp, filename):
|
||||
self.methodCalled = True
|
||||
handler = TestHandler()
|
||||
WmfImagePlugin.register_handler(handler)
|
||||
|
||||
im = hopper()
|
||||
tmpfile = self.tempfile("temp.wmf")
|
||||
im.save(tmpfile)
|
||||
self.assertTrue(handler.methodCalled)
|
||||
|
||||
# Restore the state before this test
|
||||
WmfImagePlugin.register_handler(None)
|
||||
|
||||
def test_save(self):
|
||||
im = hopper()
|
||||
|
||||
for ext in [".wmf", ".emf"]:
|
||||
tmpfile = self.tempfile("temp"+ext)
|
||||
self.assertRaises(IOError, lambda: im.save(tmpfile))
|
||||
self.assertRaises(IOError, im.save, tmpfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -21,7 +21,7 @@ class TestFileXpm(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda: XpmImagePlugin.XpmImageFile(invalid_file))
|
||||
XpmImagePlugin.XpmImageFile, invalid_file)
|
||||
|
||||
def test_load_read(self):
|
||||
# Arrange
|
||||
|
|
|
@ -25,8 +25,7 @@ class TestFileXVThumb(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
XVThumbImagePlugin.XVThumbImageFile(bad_file))
|
||||
XVThumbImagePlugin.XVThumbImageFile, bad_file)
|
||||
|
||||
def test_invalid_file(self):
|
||||
# Arrange
|
||||
|
@ -34,8 +33,7 @@ class TestFileXVThumb(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(SyntaxError,
|
||||
lambda:
|
||||
XVThumbImagePlugin.XVThumbImageFile(invalid_file))
|
||||
XVThumbImagePlugin.XVThumbImageFile, invalid_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -9,7 +9,7 @@ class TestFontBdf(PillowTestCase):
|
|||
|
||||
def test_sanity(self):
|
||||
|
||||
test_file = open(filename, "rb")
|
||||
with open(filename, "rb") as test_file:
|
||||
font = BdfFontFile.BdfFontFile(test_file)
|
||||
|
||||
self.assertIsInstance(font, FontFile.FontFile)
|
||||
|
@ -17,7 +17,7 @@ class TestFontBdf(PillowTestCase):
|
|||
|
||||
def test_invalid_file(self):
|
||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||
self.assertRaises(SyntaxError, lambda: BdfFontFile.BdfFontFile(fp))
|
||||
self.assertRaises(SyntaxError, BdfFontFile.BdfFontFile, fp)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
34
Tests/test_font_leaks.py
Normal file
34
Tests/test_font_leaks.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
from __future__ import division
|
||||
from helper import unittest, PillowLeakTestCase
|
||||
import sys
|
||||
from PIL import Image, features, ImageDraw, ImageFont
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
|
||||
class TestTTypeFontLeak(PillowLeakTestCase):
|
||||
# fails at iteration 3 in master
|
||||
iterations = 10
|
||||
mem_limit = 4096 #k
|
||||
|
||||
def _test_font(self, font):
|
||||
im = Image.new('RGB', (255,255), 'white')
|
||||
draw = ImageDraw.ImageDraw(im)
|
||||
self._test_leak(lambda: draw.text((0, 0), "some text "*1024, #~10k
|
||||
font=font, fill="black"))
|
||||
|
||||
@unittest.skipIf(not features.check('freetype2'), "Test requires freetype2")
|
||||
def test_leak(self):
|
||||
ttype = ImageFont.truetype('Tests/fonts/FreeMono.ttf', 20)
|
||||
self._test_font(ttype)
|
||||
|
||||
class TestDefaultFontLeak(TestTTypeFontLeak):
|
||||
# fails at iteration 37 in master
|
||||
iterations = 100
|
||||
mem_limit = 1024 #k
|
||||
|
||||
def test_leak(self):
|
||||
default_font = ImageFont.load_default()
|
||||
self._test_font(default_font)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -17,7 +17,7 @@ class TestFontPcf(PillowTestCase):
|
|||
self.skipTest("zlib support not available")
|
||||
|
||||
def save_font(self):
|
||||
test_file = open(fontname, "rb")
|
||||
with open(fontname, "rb") as test_file:
|
||||
font = PcfFontFile.PcfFontFile(test_file)
|
||||
self.assertIsInstance(font, FontFile.FontFile)
|
||||
self.assertEqual(len([_f for _f in font.glyph if _f]), 192)
|
||||
|
@ -32,7 +32,7 @@ class TestFontPcf(PillowTestCase):
|
|||
|
||||
def test_invalid_file(self):
|
||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||
self.assertRaises(SyntaxError, lambda: PcfFontFile.PcfFontFile(fp))
|
||||
self.assertRaises(SyntaxError, PcfFontFile.PcfFontFile, fp)
|
||||
|
||||
def xtest_draw(self):
|
||||
|
||||
|
|
|
@ -47,10 +47,9 @@ class TestImage(PillowTestCase):
|
|||
self.assertEqual(im2.getcolors(), [(10000, 0)])
|
||||
self.assertEqual(im3.getcolors(), [(10000, 0)])
|
||||
|
||||
self.assertRaises(ValueError, lambda: Image.new("X", (100, 100)))
|
||||
self.assertRaises(ValueError, lambda: Image.new("", (100, 100)))
|
||||
# self.assertRaises(
|
||||
# MemoryError, lambda: Image.new("L", (1000000, 1000000)))
|
||||
self.assertRaises(ValueError, Image.new, "X", (100, 100))
|
||||
self.assertRaises(ValueError, Image.new, "", (100, 100))
|
||||
# self.assertRaises(MemoryError, Image.new, "L", (1000000, 1000000))
|
||||
|
||||
def test_width_height(self):
|
||||
im = Image.new("RGB", (1, 2))
|
||||
|
@ -68,7 +67,10 @@ class TestImage(PillowTestCase):
|
|||
else:
|
||||
import io
|
||||
im = io.BytesIO(b'')
|
||||
self.assertRaises(IOError, lambda: Image.open(im))
|
||||
self.assertRaises(IOError, Image.open, im)
|
||||
|
||||
def test_bad_mode(self):
|
||||
self.assertRaises(ValueError, Image.open, "filename", "bad mode")
|
||||
|
||||
@unittest.skipIf(sys.version_info < (3, 4),
|
||||
"pathlib only available in Python 3.4 or later")
|
||||
|
@ -109,7 +111,7 @@ class TestImage(PillowTestCase):
|
|||
def test_unknown_extension(self):
|
||||
im = hopper()
|
||||
temp_file = self.tempfile("temp.unknown")
|
||||
self.assertRaises(ValueError, lambda: im.save(temp_file))
|
||||
self.assertRaises(ValueError, im.save, temp_file)
|
||||
|
||||
def test_internals(self):
|
||||
|
||||
|
@ -273,6 +275,20 @@ class TestImage(PillowTestCase):
|
|||
target.crop((32, 32, 96, 96)))
|
||||
self.assertEqual(source.size, (128, 128))
|
||||
|
||||
# errors
|
||||
self.assertRaises(ValueError,
|
||||
source.alpha_composite, over, "invalid source")
|
||||
self.assertRaises(ValueError,
|
||||
source.alpha_composite, over, (0, 0), "invalid destination")
|
||||
self.assertRaises(ValueError,
|
||||
source.alpha_composite, over, (0))
|
||||
self.assertRaises(ValueError,
|
||||
source.alpha_composite, over, (0, 0), (0))
|
||||
self.assertRaises(ValueError,
|
||||
source.alpha_composite, over, (0, -1))
|
||||
self.assertRaises(ValueError,
|
||||
source.alpha_composite, over, (0, 0), (0, -1))
|
||||
|
||||
def test_registered_extensions_uninitialized(self):
|
||||
# Arrange
|
||||
Image._initialized = 0
|
||||
|
@ -327,7 +343,7 @@ class TestImage(PillowTestCase):
|
|||
# Act/Assert
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
lambda: Image.effect_mandelbrot(size, extent, quality))
|
||||
Image.effect_mandelbrot, size, extent, quality)
|
||||
|
||||
def test_effect_noise(self):
|
||||
# Arrange
|
||||
|
@ -388,7 +404,7 @@ class TestImage(PillowTestCase):
|
|||
im = hopper()
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(NotImplementedError, lambda: im.offset(None))
|
||||
self.assertRaises(NotImplementedError, im.offset, None)
|
||||
|
||||
def test_fromstring(self):
|
||||
self.assertRaises(NotImplementedError, Image.fromstring)
|
||||
|
@ -399,8 +415,7 @@ class TestImage(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError,
|
||||
lambda: Image.linear_gradient(wrong_mode))
|
||||
return
|
||||
Image.linear_gradient, wrong_mode)
|
||||
|
||||
def test_linear_gradient(self):
|
||||
|
||||
|
@ -425,8 +440,7 @@ class TestImage(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError,
|
||||
lambda: Image.radial_gradient(wrong_mode))
|
||||
return
|
||||
Image.radial_gradient, wrong_mode)
|
||||
|
||||
def test_radial_gradient(self):
|
||||
|
||||
|
@ -445,6 +459,11 @@ class TestImage(PillowTestCase):
|
|||
target = Image.open(target_file).convert(mode)
|
||||
self.assert_image_equal(im, target)
|
||||
|
||||
def test_remap_palette(self):
|
||||
# Test illegal image mode
|
||||
im = hopper()
|
||||
self.assertRaises(ValueError, im.remap_palette, None)
|
||||
|
||||
|
||||
def test__new(self):
|
||||
from PIL import ImagePalette
|
||||
|
@ -496,10 +515,10 @@ class TestRegistry(PillowTestCase):
|
|||
self.assertEqual(enc.args, ('RGB', 'args', 'extra'))
|
||||
|
||||
def test_encode_registry_fail(self):
|
||||
self.assertRaises(IOError, lambda: Image._getencoder('RGB',
|
||||
self.assertRaises(IOError, Image._getencoder, 'RGB',
|
||||
'DoesNotExist',
|
||||
('args',),
|
||||
extra=('extra',)))
|
||||
extra=('extra',))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -107,7 +107,7 @@ class TestImageConvert(PillowTestCase):
|
|||
|
||||
p = self.assert_warning(
|
||||
UserWarning,
|
||||
lambda: im.convert('P', palette=Image.ADAPTIVE))
|
||||
im.convert, 'P', palette=Image.ADAPTIVE)
|
||||
self.assertNotIn('transparency', p.info)
|
||||
p.save(f)
|
||||
|
||||
|
@ -131,7 +131,7 @@ class TestImageConvert(PillowTestCase):
|
|||
|
||||
p = self.assert_warning(
|
||||
UserWarning,
|
||||
lambda: im.convert('P', palette=Image.ADAPTIVE))
|
||||
im.convert, 'P', palette=Image.ADAPTIVE)
|
||||
self.assertNotIn('transparency', p.info)
|
||||
p.save(f)
|
||||
|
||||
|
@ -155,7 +155,7 @@ class TestImageConvert(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError,
|
||||
lambda: im.convert(mode='CMYK', matrix=matrix))
|
||||
im.convert, mode='CMYK', matrix=matrix)
|
||||
|
||||
def test_matrix_wrong_mode(self):
|
||||
# Arrange
|
||||
|
@ -168,7 +168,7 @@ class TestImageConvert(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError,
|
||||
lambda: im.convert(mode='L', matrix=matrix))
|
||||
im.convert, mode='L', matrix=matrix)
|
||||
|
||||
def test_matrix_xyz(self):
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class TestImageFilter(PillowTestCase):
|
|||
filter(ImageFilter.UnsharpMask)
|
||||
filter(ImageFilter.UnsharpMask(10))
|
||||
|
||||
self.assertRaises(TypeError, lambda: filter("hello"))
|
||||
self.assertRaises(TypeError, filter, "hello")
|
||||
|
||||
def test_crash(self):
|
||||
|
||||
|
@ -83,7 +83,7 @@ class TestImageFilter(PillowTestCase):
|
|||
|
||||
self.assertEqual(rankfilter("1"), (0, 4, 8))
|
||||
self.assertEqual(rankfilter("L"), (0, 4, 8))
|
||||
self.assertRaises(ValueError, lambda: rankfilter("P"))
|
||||
self.assertRaises(ValueError, rankfilter, "P")
|
||||
self.assertEqual(rankfilter("RGB"), ((0, 0, 0), (4, 0, 0), (8, 0, 0)))
|
||||
self.assertEqual(rankfilter("I"), (0, 4, 8))
|
||||
self.assertEqual(rankfilter("F"), (0.0, 4.0, 8.0))
|
||||
|
@ -95,26 +95,38 @@ class TestImageFilter(PillowTestCase):
|
|||
self.assertEqual(rankfilter.rank, 2)
|
||||
|
||||
def test_consistency_3x3(self):
|
||||
im = Image.open("Tests/images/hopper.bmp")
|
||||
emboss = im.filter(ImageFilter.Kernel((3, 3),
|
||||
source = Image.open("Tests/images/hopper.bmp")
|
||||
reference = Image.open("Tests/images/hopper_emboss.bmp")
|
||||
kernel = ImageFilter.Kernel((3, 3),
|
||||
(-1, -1, 0,
|
||||
-1, 0, 1,
|
||||
0, 1, 1), .3))
|
||||
0, 1, 1), .3)
|
||||
source = source.split() * 2
|
||||
reference = reference.split() * 2
|
||||
|
||||
for mode in ['L', 'LA', 'RGB', 'CMYK']:
|
||||
self.assert_image_equal(
|
||||
emboss, Image.open("Tests/images/hopper_emboss.bmp"))
|
||||
Image.merge(mode, source[:len(mode)]).filter(kernel),
|
||||
Image.merge(mode, reference[:len(mode)]),
|
||||
)
|
||||
|
||||
def test_consistency_5x5(self):
|
||||
im = Image.open("Tests/images/hopper.bmp")
|
||||
emboss = im.filter(ImageFilter.Kernel((5, 5),
|
||||
source = Image.open("Tests/images/hopper.bmp")
|
||||
reference = Image.open("Tests/images/hopper_emboss_more.bmp")
|
||||
kernel = 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))
|
||||
0, 1, 1, 1, 1), 0.3)
|
||||
source = source.split() * 2
|
||||
reference = reference.split() * 2
|
||||
|
||||
for mode in ['L', 'LA', 'RGB', 'CMYK']:
|
||||
self.assert_image_equal(
|
||||
emboss, Image.open("Tests/images/hopper_emboss_more.bmp"))
|
||||
Image.merge(mode, source[:len(mode)]).filter(kernel),
|
||||
Image.merge(mode, reference[:len(mode)]),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -11,6 +11,9 @@ class TestImageFromBytes(PillowTestCase):
|
|||
|
||||
self.assert_image_equal(im1, im2)
|
||||
|
||||
def test_not_implemented(self):
|
||||
self.assertRaises(NotImplementedError, Image.fromstring)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -19,7 +19,7 @@ class TestImageLoad(PillowTestCase):
|
|||
im = Image.open("Tests/images/hopper.gif")
|
||||
im.close()
|
||||
self.assertRaises(ValueError, im.load)
|
||||
self.assertRaises(ValueError, lambda: im.getpixel((0, 0)))
|
||||
self.assertRaises(ValueError, im.getpixel, (0, 0))
|
||||
|
||||
def test_contextmanager(self):
|
||||
fn = None
|
||||
|
@ -27,7 +27,7 @@ class TestImageLoad(PillowTestCase):
|
|||
fn = im.fp.fileno()
|
||||
os.fstat(fn)
|
||||
|
||||
self.assertRaises(OSError, lambda: os.fstat(fn))
|
||||
self.assertRaises(OSError, os.fstat, fn)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -6,17 +6,17 @@ class TestImagePoint(PillowTestCase):
|
|||
def test_sanity(self):
|
||||
im = hopper()
|
||||
|
||||
self.assertRaises(ValueError, lambda: im.point(list(range(256))))
|
||||
self.assertRaises(ValueError, im.point, list(range(256)))
|
||||
im.point(list(range(256))*3)
|
||||
im.point(lambda x: x)
|
||||
|
||||
im = im.convert("I")
|
||||
self.assertRaises(ValueError, lambda: im.point(list(range(256))))
|
||||
self.assertRaises(ValueError, im.point, list(range(256)))
|
||||
im.point(lambda x: x*1)
|
||||
im.point(lambda x: x+1)
|
||||
im.point(lambda x: x*1+1)
|
||||
self.assertRaises(TypeError, lambda: im.point(lambda x: x-1))
|
||||
self.assertRaises(TypeError, lambda: im.point(lambda x: x/1))
|
||||
self.assertRaises(TypeError, im.point, lambda x: x-1)
|
||||
self.assertRaises(TypeError, im.point, lambda x: x/1)
|
||||
|
||||
def test_16bit_lut(self):
|
||||
""" Tests for 16 bit -> 8 bit lut for converting I->L images
|
||||
|
@ -36,7 +36,8 @@ class TestImagePoint(PillowTestCase):
|
|||
self.assert_image_equal(out.convert('L'), im.point(int_lut, 'L'))
|
||||
|
||||
def test_f_mode(self):
|
||||
self.assertRaises(ValueError, lambda: hopper('F').point(None))
|
||||
im = hopper('F')
|
||||
self.assertRaises(ValueError, im.point, None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -13,14 +13,14 @@ class TestImagePutPalette(PillowTestCase):
|
|||
if p:
|
||||
return im.mode, p[:10]
|
||||
return im.mode
|
||||
self.assertRaises(ValueError, lambda: palette("1"))
|
||||
self.assertRaises(ValueError, palette, "1")
|
||||
self.assertEqual(palette("L"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
|
||||
self.assertEqual(palette("P"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
|
||||
self.assertRaises(ValueError, lambda: palette("I"))
|
||||
self.assertRaises(ValueError, lambda: palette("F"))
|
||||
self.assertRaises(ValueError, lambda: palette("RGB"))
|
||||
self.assertRaises(ValueError, lambda: palette("RGBA"))
|
||||
self.assertRaises(ValueError, lambda: palette("YCbCr"))
|
||||
self.assertRaises(ValueError, palette, "I")
|
||||
self.assertRaises(ValueError, palette, "F")
|
||||
self.assertRaises(ValueError, palette, "RGB")
|
||||
self.assertRaises(ValueError, palette, "RGBA")
|
||||
self.assertRaises(ValueError, palette, "YCbCr")
|
||||
|
||||
def test_imagepalette(self):
|
||||
im = hopper("P")
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestImageQuantize(PillowTestCase):
|
|||
def test_rgba_quantize(self):
|
||||
image = hopper('RGBA')
|
||||
image.quantize()
|
||||
self.assertRaises(Exception, lambda: image.quantize(method=0))
|
||||
self.assertRaises(Exception, image.quantize, method=0)
|
||||
|
||||
def test_quantize(self):
|
||||
image = Image.open('Tests/images/caption_6_33_22.png').convert('RGB')
|
||||
|
|
|
@ -460,7 +460,7 @@ class CoreResampleBoxTest(PillowTestCase):
|
|||
self.assert_image_similar(cropped, with_box, 0.4)
|
||||
|
||||
def test_passthrough(self):
|
||||
"When no resize is required"
|
||||
# When no resize is required
|
||||
im = hopper()
|
||||
|
||||
for size, box in [
|
||||
|
@ -478,7 +478,7 @@ class CoreResampleBoxTest(PillowTestCase):
|
|||
raise
|
||||
|
||||
def test_no_passthrough(self):
|
||||
"When resize is required"
|
||||
# When resize is required
|
||||
im = hopper()
|
||||
|
||||
for size, box in [
|
||||
|
@ -498,7 +498,7 @@ class CoreResampleBoxTest(PillowTestCase):
|
|||
raise
|
||||
|
||||
def test_skip_horizontal(self):
|
||||
"Can skip resize in one dimension"
|
||||
# Can skip resize for one dimension
|
||||
im = hopper()
|
||||
|
||||
for flt in [Image.NEAREST, Image.BICUBIC]:
|
||||
|
@ -519,7 +519,7 @@ class CoreResampleBoxTest(PillowTestCase):
|
|||
raise
|
||||
|
||||
def test_skip_vertical(self):
|
||||
"Can skip resize in one dimension"
|
||||
# Can skip resize for one dimension
|
||||
im = hopper()
|
||||
|
||||
for flt in [Image.NEAREST, Image.BICUBIC]:
|
||||
|
|
|
@ -112,6 +112,10 @@ class TestImageResize(PillowTestCase):
|
|||
resize(mode, (112, 103))
|
||||
resize(mode, (188, 214))
|
||||
|
||||
# Test unknown resampling filter
|
||||
im = hopper()
|
||||
self.assertRaises(ValueError, im.resize, (10, 10), "unknown")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -141,8 +141,8 @@ class TestImageTransform(PillowTestCase):
|
|||
self.test_mesh()
|
||||
|
||||
def test_missing_method_data(self):
|
||||
self.assertRaises(ValueError, lambda:
|
||||
hopper().transform((100, 100), None))
|
||||
im = hopper()
|
||||
self.assertRaises(ValueError, im.transform, (100, 100), None)
|
||||
|
||||
|
||||
class TestImageTransformAffine(PillowTestCase):
|
||||
|
|
|
@ -144,20 +144,26 @@ class TestImageCms(PillowTestCase):
|
|||
'IEC 61966-2.1 Default RGB colour space - sRGB')
|
||||
|
||||
def test_exceptions(self):
|
||||
# Test mode mismatch
|
||||
psRGB = ImageCms.createProfile("sRGB")
|
||||
pLab = ImageCms.createProfile("LAB")
|
||||
t = ImageCms.buildTransform(pLab, psRGB, "LAB", "RGB")
|
||||
self.assertRaises(ValueError, t.apply_in_place, hopper("RGBA"))
|
||||
|
||||
# the procedural pyCMS API uses PyCMSError for all sorts of errors
|
||||
self.assertRaises(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.profileToProfile(hopper(), "foo", "bar"))
|
||||
ImageCms.profileToProfile, hopper(), "foo", "bar")
|
||||
self.assertRaises(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB"))
|
||||
ImageCms.buildTransform, "foo", "bar", "RGB", "RGB")
|
||||
self.assertRaises(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.getProfileName(None))
|
||||
ImageCms.getProfileName, None)
|
||||
self.skip_missing()
|
||||
self.assertRaises(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.isIntentSupported(SRGB, None, None))
|
||||
ImageCms.isIntentSupported, SRGB, None, None)
|
||||
|
||||
def test_display_profile(self):
|
||||
# try fetching the profile for the current display device
|
||||
|
@ -167,6 +173,14 @@ class TestImageCms(PillowTestCase):
|
|||
ImageCms.createProfile("LAB", 5000)
|
||||
ImageCms.createProfile("LAB", 6500)
|
||||
|
||||
def test_unsupported_color_space(self):
|
||||
self.assertRaises(ImageCms.PyCMSError,
|
||||
ImageCms.createProfile, "unsupported")
|
||||
|
||||
def test_invalid_color_temperature(self):
|
||||
self.assertRaises(ImageCms.PyCMSError,
|
||||
ImageCms.createProfile, "LAB", "invalid")
|
||||
|
||||
def test_simple_lab(self):
|
||||
i = Image.new('RGB', (10, 10), (128, 128, 128))
|
||||
|
||||
|
|
|
@ -51,13 +51,11 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.line(((0, 0)), fill=(0, 0, 0))
|
||||
del draw
|
||||
|
||||
def test_mode_mismatch(self):
|
||||
im = hopper("RGB").copy()
|
||||
|
||||
self.assertRaises(ValueError,
|
||||
lambda: ImageDraw.ImageDraw(im, mode="L"))
|
||||
self.assertRaises(ValueError, ImageDraw.ImageDraw, im, mode="L")
|
||||
|
||||
def helper_arc(self, bbox, start, end):
|
||||
# Arrange
|
||||
|
@ -66,7 +64,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.arc(bbox, start, end)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
|
@ -89,7 +86,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.arc(BBOX1, start=start, end=end)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -105,7 +101,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.arc(BBOX1, start=start, end=end)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
|
@ -119,7 +114,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.bitmap((10, 10), small)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -133,7 +127,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.chord(bbox, start, end, fill="red", outline="yellow")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
@ -156,7 +149,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.ellipse(bbox, fill="green", outline="blue")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
@ -176,7 +168,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.ellipse(((0, 0), (W-1, H)), fill="white")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
|
@ -189,7 +180,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.line(points, fill="yellow", width=2)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -217,7 +207,6 @@ class TestImageDraw(PillowTestCase):
|
|||
s.line(x0, y0)
|
||||
|
||||
draw.shape(s, fill=1)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -239,7 +228,6 @@ class TestImageDraw(PillowTestCase):
|
|||
s.line(x0, y0)
|
||||
|
||||
draw.shape(s, outline="blue")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -252,7 +240,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.pieslice(bbox, start, end, fill="white", outline="blue")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
|
@ -273,7 +260,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.point(points, fill="yellow")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -292,7 +278,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.polygon(points, fill="red", outline="blue")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -316,7 +301,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.polygon(KITE_POINTS, fill="blue", outline="yellow")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(im, Image.open(expected))
|
||||
|
@ -328,7 +312,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.rectangle(bbox, fill="black", outline="green")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -350,7 +333,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.rectangle(bbox, fill="orange")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
@ -377,7 +359,6 @@ class TestImageDraw(PillowTestCase):
|
|||
# Test that filling outside the image does not change the image
|
||||
ImageDraw.floodfill(im, (W, H), red)
|
||||
self.assert_image_equal(im, im_floodfill)
|
||||
del draw
|
||||
|
||||
@unittest.skipIf(hasattr(sys, 'pypy_version_info'),
|
||||
"Causes fatal RPython error on PyPy")
|
||||
|
@ -394,7 +375,6 @@ class TestImageDraw(PillowTestCase):
|
|||
ImageDraw.floodfill(
|
||||
im, centre_point, ImageColor.getrgb("red"),
|
||||
border=ImageColor.getrgb("black"))
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -414,7 +394,6 @@ class TestImageDraw(PillowTestCase):
|
|||
ImageDraw.floodfill(
|
||||
im, centre_point, ImageColor.getrgb("red"),
|
||||
thresh=30)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
|
@ -577,7 +556,6 @@ class TestImageDraw(PillowTestCase):
|
|||
|
||||
# Act
|
||||
draw.line([(50, 50), (50, 50)], width=3)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
|
|
@ -69,7 +69,7 @@ class TestImageFile(PillowTestCase):
|
|||
im1, im2 = roundtrip("JPEG") # lossy compression
|
||||
self.assert_image(im1, im2.mode, im2.size)
|
||||
|
||||
self.assertRaises(IOError, lambda: roundtrip("PDF"))
|
||||
self.assertRaises(IOError, roundtrip, "PDF")
|
||||
|
||||
def test_ico(self):
|
||||
with open('Tests/images/python.ico', 'rb') as f:
|
||||
|
@ -93,7 +93,7 @@ class TestImageFile(PillowTestCase):
|
|||
self.assert_image_equal(im1, im2)
|
||||
|
||||
def test_raise_ioerror(self):
|
||||
self.assertRaises(IOError, lambda: ImageFile.raise_ioerror(1))
|
||||
self.assertRaises(IOError, ImageFile.raise_ioerror, 1)
|
||||
|
||||
def test_raise_typeerror(self):
|
||||
with self.assertRaises(TypeError):
|
||||
|
@ -182,7 +182,7 @@ class TestPyDecoder(PillowTestCase):
|
|||
self.assertEqual(d.state.xsize, xsize)
|
||||
self.assertEqual(d.state.ysize, ysize)
|
||||
|
||||
self.assertRaises(ValueError, lambda: d.set_as_raw(b'\x00'))
|
||||
self.assertRaises(ValueError, d.set_as_raw, b'\x00')
|
||||
|
||||
def test_extents_none(self):
|
||||
buf = BytesIO(b'\x00'*255)
|
||||
|
|
|
@ -106,7 +106,7 @@ class TestImageFont(PillowTestCase):
|
|||
# Usage note: making two fonts from the same buffer fails.
|
||||
# shared_bytes = self._font_as_bytes()
|
||||
# self._render(shared_bytes)
|
||||
# self.assertRaises(Exception, lambda: _render(shared_bytes))
|
||||
# self.assertRaises(Exception, _render, shared_bytes)
|
||||
|
||||
def test_font_with_open_file(self):
|
||||
with open(FONT_PATH, 'rb') as f:
|
||||
|
@ -141,7 +141,6 @@ class TestImageFont(PillowTestCase):
|
|||
size = draw.textsize(txt, ttf)
|
||||
draw.text((10, 10), txt, font=ttf)
|
||||
draw.rectangle((10, 10, 10 + size[0], 10 + size[1]))
|
||||
del draw
|
||||
|
||||
target = 'Tests/images/rectangle_surrounding_text.png'
|
||||
target_img = Image.open(target)
|
||||
|
@ -188,7 +187,6 @@ class TestImageFont(PillowTestCase):
|
|||
draw.text((0, 0), TEST_TEXT, fill=None, font=ttf, anchor=None,
|
||||
spacing=4, align="left")
|
||||
draw.text((0, 0), TEST_TEXT, None, ttf, None, 4, "left")
|
||||
del draw
|
||||
|
||||
# Test align center and right
|
||||
for align, ext in {"center": "_center",
|
||||
|
@ -196,7 +194,6 @@ class TestImageFont(PillowTestCase):
|
|||
im = Image.new(mode='RGB', size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.multiline_text((0, 0), TEST_TEXT, font=ttf, align=align)
|
||||
del draw
|
||||
|
||||
target = 'Tests/images/multiline_text'+ext+'.png'
|
||||
target_img = Image.open(target)
|
||||
|
@ -211,9 +208,9 @@ class TestImageFont(PillowTestCase):
|
|||
|
||||
# Act/Assert
|
||||
self.assertRaises(AssertionError,
|
||||
lambda: draw.multiline_text((0, 0), TEST_TEXT,
|
||||
draw.multiline_text, (0, 0), TEST_TEXT,
|
||||
font=ttf,
|
||||
align="unknown"))
|
||||
align="unknown")
|
||||
|
||||
def test_draw_align(self):
|
||||
im = Image.new('RGB', (300, 100), 'white')
|
||||
|
@ -221,7 +218,6 @@ class TestImageFont(PillowTestCase):
|
|||
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()
|
||||
|
@ -236,7 +232,6 @@ class TestImageFont(PillowTestCase):
|
|||
# to multiline_textsize()
|
||||
draw.textsize(TEST_TEXT, font=ttf, spacing=4)
|
||||
draw.textsize(TEST_TEXT, ttf, 4)
|
||||
del draw
|
||||
|
||||
def test_multiline_width(self):
|
||||
ttf = self.get_font()
|
||||
|
@ -246,7 +241,6 @@ class TestImageFont(PillowTestCase):
|
|||
self.assertEqual(draw.textsize("longest line", font=ttf)[0],
|
||||
draw.multiline_textsize("longest line\nline",
|
||||
font=ttf)[0])
|
||||
del draw
|
||||
|
||||
def test_multiline_spacing(self):
|
||||
ttf = self.get_font()
|
||||
|
@ -254,7 +248,6 @@ class TestImageFont(PillowTestCase):
|
|||
im = Image.new(mode='RGB', size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.multiline_text((0, 0), TEST_TEXT, font=ttf, spacing=10)
|
||||
del draw
|
||||
|
||||
target = 'Tests/images/multiline_text_spacing.png'
|
||||
target_img = Image.open(target)
|
||||
|
@ -279,7 +272,6 @@ class TestImageFont(PillowTestCase):
|
|||
# Rotated font
|
||||
draw.font = transposed_font
|
||||
box_size_b = draw.textsize(word)
|
||||
del draw
|
||||
|
||||
# Check (w,h) of box a is (h,w) of box b
|
||||
self.assertEqual(box_size_a[0], box_size_b[1])
|
||||
|
@ -302,7 +294,6 @@ class TestImageFont(PillowTestCase):
|
|||
# Rotated font
|
||||
draw.font = transposed_font
|
||||
box_size_b = draw.textsize(word)
|
||||
del draw
|
||||
|
||||
# Check boxes a and b are same size
|
||||
self.assertEqual(box_size_a, box_size_b)
|
||||
|
@ -384,7 +375,7 @@ class TestImageFont(PillowTestCase):
|
|||
filename = "somefilenamethatdoesntexist.ttf"
|
||||
|
||||
# Act/Assert
|
||||
self.assertRaises(IOError, lambda: ImageFont.load_path(filename))
|
||||
self.assertRaises(IOError, ImageFont.load_path, filename)
|
||||
|
||||
def test_default_font(self):
|
||||
# Arrange
|
||||
|
@ -398,16 +389,29 @@ class TestImageFont(PillowTestCase):
|
|||
# Act
|
||||
default_font = ImageFont.load_default()
|
||||
draw.text((10, 10), txt, font=default_font)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(im, target_img)
|
||||
|
||||
def test_getsize_empty(self):
|
||||
# issue #2614
|
||||
font = self.get_font()
|
||||
# should not crash.
|
||||
self.assertEqual((0, 0), font.getsize(''))
|
||||
|
||||
def test_render_empty(self):
|
||||
# issue 2666
|
||||
font = self.get_font()
|
||||
im = Image.new(mode='RGB', size=(300, 100))
|
||||
target = im.copy()
|
||||
draw = ImageDraw.Draw(im)
|
||||
#should not crash here.
|
||||
draw.text((10, 10), '', font=font)
|
||||
self.assert_image_equal(im, target)
|
||||
|
||||
|
||||
|
||||
|
||||
def _test_fake_loading_font(self, path_to_fake, fontname):
|
||||
# Make a copy of FreeTypeFont so we can patch the original
|
||||
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
|
||||
|
|
|
@ -81,9 +81,9 @@ class MorphTests(PillowTestCase):
|
|||
|
||||
def test_no_operator_loaded(self):
|
||||
mop = ImageMorph.MorphOp()
|
||||
self.assertRaises(Exception, lambda: mop.apply(None))
|
||||
self.assertRaises(Exception, lambda: mop.match(None))
|
||||
self.assertRaises(Exception, lambda: mop.save_lut(None))
|
||||
self.assertRaises(Exception, mop.apply, None)
|
||||
self.assertRaises(Exception, mop.match, None)
|
||||
self.assertRaises(Exception, mop.save_lut, None)
|
||||
|
||||
# Test the named patterns
|
||||
def test_erosion8(self):
|
||||
|
@ -214,9 +214,9 @@ class MorphTests(PillowTestCase):
|
|||
im = hopper('RGB')
|
||||
mop = ImageMorph.MorphOp(op_name="erosion8")
|
||||
|
||||
self.assertRaises(Exception, lambda: mop.apply(im))
|
||||
self.assertRaises(Exception, lambda: mop.match(im))
|
||||
self.assertRaises(Exception, lambda: mop.get_on_pixels(im))
|
||||
self.assertRaises(Exception, mop.apply, im)
|
||||
self.assertRaises(Exception, mop.match, im)
|
||||
self.assertRaises(Exception, mop.get_on_pixels, im)
|
||||
|
||||
def test_add_patterns(self):
|
||||
# Arrange
|
||||
|
@ -240,7 +240,7 @@ class MorphTests(PillowTestCase):
|
|||
def test_unknown_pattern(self):
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: ImageMorph.LutBuilder(op_name='unknown'))
|
||||
ImageMorph.LutBuilder, op_name='unknown')
|
||||
|
||||
def test_pattern_syntax_error(self):
|
||||
# Arrange
|
||||
|
@ -249,9 +249,7 @@ class MorphTests(PillowTestCase):
|
|||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: lb.build_lut())
|
||||
self.assertRaises(Exception, lb.build_lut)
|
||||
|
||||
def test_load_invalid_mrl(self):
|
||||
# Arrange
|
||||
|
@ -259,7 +257,7 @@ class MorphTests(PillowTestCase):
|
|||
mop = ImageMorph.MorphOp()
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(Exception, lambda: mop.load_lut(invalid_mrl))
|
||||
self.assertRaises(Exception, mop.load_lut, invalid_mrl)
|
||||
|
||||
def test_roundtrip_mrl(self):
|
||||
# Arrange
|
||||
|
|
|
@ -37,26 +37,26 @@ class TestImageOpsUsm(PillowTestCase):
|
|||
def test_usm_formats(self):
|
||||
|
||||
usm = ImageOps.unsharp_mask
|
||||
self.assertRaises(ValueError, lambda: usm(im.convert("1")))
|
||||
self.assertRaises(ValueError, usm, im.convert("1"))
|
||||
usm(im.convert("L"))
|
||||
self.assertRaises(ValueError, lambda: usm(im.convert("I")))
|
||||
self.assertRaises(ValueError, lambda: usm(im.convert("F")))
|
||||
self.assertRaises(ValueError, usm, im.convert("I"))
|
||||
self.assertRaises(ValueError, usm, im.convert("F"))
|
||||
usm(im.convert("RGB"))
|
||||
usm(im.convert("RGBA"))
|
||||
usm(im.convert("CMYK"))
|
||||
self.assertRaises(ValueError, lambda: usm(im.convert("YCbCr")))
|
||||
self.assertRaises(ValueError, usm, im.convert("YCbCr"))
|
||||
|
||||
def test_blur_formats(self):
|
||||
|
||||
blur = ImageOps.gaussian_blur
|
||||
self.assertRaises(ValueError, lambda: blur(im.convert("1")))
|
||||
self.assertRaises(ValueError, blur, im.convert("1"))
|
||||
blur(im.convert("L"))
|
||||
self.assertRaises(ValueError, lambda: blur(im.convert("I")))
|
||||
self.assertRaises(ValueError, lambda: blur(im.convert("F")))
|
||||
self.assertRaises(ValueError, blur, im.convert("I"))
|
||||
self.assertRaises(ValueError, blur, im.convert("F"))
|
||||
blur(im.convert("RGB"))
|
||||
blur(im.convert("RGBA"))
|
||||
blur(im.convert("CMYK"))
|
||||
self.assertRaises(ValueError, lambda: blur(im.convert("YCbCr")))
|
||||
self.assertRaises(ValueError, blur, im.convert("YCbCr"))
|
||||
|
||||
def test_usm_accuracy(self):
|
||||
|
||||
|
|
|
@ -2,56 +2,54 @@ from helper import unittest, PillowTestCase
|
|||
|
||||
from PIL import ImagePalette, Image
|
||||
|
||||
ImagePalette = ImagePalette.ImagePalette
|
||||
|
||||
|
||||
class TestImagePalette(PillowTestCase):
|
||||
|
||||
def test_sanity(self):
|
||||
|
||||
ImagePalette("RGB", list(range(256))*3)
|
||||
self.assertRaises(
|
||||
ValueError, lambda: ImagePalette("RGB", list(range(256))*2))
|
||||
ImagePalette.ImagePalette("RGB", list(range(256))*3)
|
||||
self.assertRaises(ValueError,
|
||||
ImagePalette.ImagePalette, "RGB", list(range(256))*2)
|
||||
|
||||
def test_getcolor(self):
|
||||
|
||||
palette = ImagePalette()
|
||||
palette = ImagePalette.ImagePalette()
|
||||
|
||||
test_map = {}
|
||||
for i in range(256):
|
||||
test_map[palette.getcolor((i, i, i))] = i
|
||||
|
||||
self.assertEqual(len(test_map), 256)
|
||||
self.assertRaises(ValueError, lambda: palette.getcolor((1, 2, 3)))
|
||||
self.assertRaises(ValueError, palette.getcolor, (1, 2, 3))
|
||||
|
||||
# Test unknown color specifier
|
||||
self.assertRaises(ValueError, palette.getcolor, "unknown")
|
||||
|
||||
def test_file(self):
|
||||
|
||||
palette = ImagePalette("RGB", list(range(256))*3)
|
||||
palette = ImagePalette.ImagePalette("RGB", list(range(256))*3)
|
||||
|
||||
f = self.tempfile("temp.lut")
|
||||
|
||||
palette.save(f)
|
||||
|
||||
from PIL.ImagePalette import load, raw
|
||||
|
||||
p = load(f)
|
||||
p = ImagePalette.load(f)
|
||||
|
||||
# load returns raw palette information
|
||||
self.assertEqual(len(p[0]), 768)
|
||||
self.assertEqual(p[1], "RGB")
|
||||
|
||||
p = raw(p[1], p[0])
|
||||
self.assertIsInstance(p, ImagePalette)
|
||||
p = ImagePalette.raw(p[1], p[0])
|
||||
self.assertIsInstance(p, ImagePalette.ImagePalette)
|
||||
self.assertEqual(p.palette, palette.tobytes())
|
||||
|
||||
def test_make_linear_lut(self):
|
||||
# Arrange
|
||||
from PIL.ImagePalette import make_linear_lut
|
||||
black = 0
|
||||
white = 255
|
||||
|
||||
# Act
|
||||
lut = make_linear_lut(black, white)
|
||||
lut = ImagePalette.make_linear_lut(black, white)
|
||||
|
||||
# Assert
|
||||
self.assertIsInstance(lut, list)
|
||||
|
@ -63,22 +61,19 @@ class TestImagePalette(PillowTestCase):
|
|||
def test_make_linear_lut_not_yet_implemented(self):
|
||||
# Update after FIXME
|
||||
# Arrange
|
||||
from PIL.ImagePalette import make_linear_lut
|
||||
black = 1
|
||||
white = 255
|
||||
|
||||
# Act
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
lambda: make_linear_lut(black, white))
|
||||
self.assertRaises(NotImplementedError,
|
||||
ImagePalette.make_linear_lut, black, white)
|
||||
|
||||
def test_make_gamma_lut(self):
|
||||
# Arrange
|
||||
from PIL.ImagePalette import make_gamma_lut
|
||||
exp = 5
|
||||
|
||||
# Act
|
||||
lut = make_gamma_lut(exp)
|
||||
lut = ImagePalette.make_gamma_lut(exp)
|
||||
|
||||
# Assert
|
||||
self.assertIsInstance(lut, list)
|
||||
|
@ -92,19 +87,18 @@ class TestImagePalette(PillowTestCase):
|
|||
|
||||
def test_rawmode_valueerrors(self):
|
||||
# Arrange
|
||||
from PIL.ImagePalette import raw
|
||||
palette = raw("RGB", list(range(256))*3)
|
||||
palette = ImagePalette.raw("RGB", list(range(256))*3)
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError, palette.tobytes)
|
||||
self.assertRaises(ValueError, lambda: palette.getcolor((1, 2, 3)))
|
||||
self.assertRaises(ValueError, palette.getcolor, (1, 2, 3))
|
||||
f = self.tempfile("temp.lut")
|
||||
self.assertRaises(ValueError, lambda: palette.save(f))
|
||||
self.assertRaises(ValueError, palette.save, f)
|
||||
|
||||
def test_getdata(self):
|
||||
# Arrange
|
||||
data_in = list(range(256))*3
|
||||
palette = ImagePalette("RGB", data_in)
|
||||
palette = ImagePalette.ImagePalette("RGB", data_in)
|
||||
|
||||
# Act
|
||||
mode, data_out = palette.getdata()
|
||||
|
@ -114,9 +108,8 @@ class TestImagePalette(PillowTestCase):
|
|||
|
||||
def test_rawmode_getdata(self):
|
||||
# Arrange
|
||||
from PIL.ImagePalette import raw
|
||||
data_in = list(range(256))*3
|
||||
palette = raw("RGB", data_in)
|
||||
palette = ImagePalette.raw("RGB", data_in)
|
||||
|
||||
# Act
|
||||
rawmode, data_out = palette.getdata()
|
||||
|
@ -138,6 +131,10 @@ class TestImagePalette(PillowTestCase):
|
|||
|
||||
self.assert_image_equal(img, reloaded)
|
||||
|
||||
def test_invalid_palette(self):
|
||||
self.assertRaises(IOError,
|
||||
ImagePalette.load, "Tests/images/hopper.jpg")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -22,7 +22,7 @@ class TestImageSequence(PillowTestCase):
|
|||
|
||||
self.assertEqual(index, 1)
|
||||
|
||||
self.assertRaises(AttributeError, lambda: ImageSequence.Iterator(0))
|
||||
self.assertRaises(AttributeError, ImageSequence.Iterator, 0)
|
||||
|
||||
def test_iterator(self):
|
||||
im = Image.open('Tests/images/multipage.tiff')
|
||||
|
@ -30,7 +30,7 @@ class TestImageSequence(PillowTestCase):
|
|||
for index in range(0, im.n_frames):
|
||||
self.assertEqual(i[index], next(i))
|
||||
self.assertRaises(IndexError, lambda: i[index+1])
|
||||
self.assertRaises(StopIteration, lambda: next(i))
|
||||
self.assertRaises(StopIteration, next, i)
|
||||
|
||||
def _test_multipage_tiff(self):
|
||||
im = Image.open('Tests/images/multipage.tiff')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageShow
|
||||
|
@ -10,12 +10,30 @@ class TestImageShow(PillowTestCase):
|
|||
dir(Image)
|
||||
dir(ImageShow)
|
||||
|
||||
def test_register(self):
|
||||
# Test registering a viewer that is not a class
|
||||
ImageShow.register("not a class")
|
||||
|
||||
def test_show(self):
|
||||
class TestViewer:
|
||||
methodCalled = False
|
||||
|
||||
def show(self, image, title=None, **options):
|
||||
self.methodCalled = True
|
||||
return True
|
||||
viewer = TestViewer()
|
||||
ImageShow.register(viewer, -1)
|
||||
|
||||
im = hopper()
|
||||
self.assertTrue(ImageShow.show(im))
|
||||
self.assertTrue(viewer.methodCalled)
|
||||
|
||||
def test_viewer(self):
|
||||
viewer = ImageShow.Viewer()
|
||||
|
||||
self.assertIsNone(viewer.get_format(None))
|
||||
|
||||
self.assertRaises(NotImplementedError, lambda: viewer.get_command(None))
|
||||
self.assertRaises(NotImplementedError, viewer.get_command, None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -26,7 +26,7 @@ class TestImageStat(PillowTestCase):
|
|||
|
||||
self.assertRaises(AttributeError, lambda: st.spam)
|
||||
|
||||
self.assertRaises(TypeError, lambda: ImageStat.Stat(1))
|
||||
self.assertRaises(TypeError, ImageStat.Stat, 1)
|
||||
|
||||
def test_hopper(self):
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ class TestLibImage(PillowTestCase):
|
|||
im.im.setmode("RGB")
|
||||
self.assertEqual(im.im.getpixel((0, 0)), (1, 2, 3))
|
||||
|
||||
self.assertRaises(ValueError, lambda: im.im.setmode("L"))
|
||||
self.assertRaises(ValueError, lambda: im.im.setmode("RGBABCDE"))
|
||||
self.assertRaises(ValueError, im.im.setmode, "L")
|
||||
self.assertRaises(ValueError, im.im.setmode, "RGBABCDE")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -86,12 +86,12 @@ class TestNumpy(PillowTestCase):
|
|||
self.assert_image(to_image(numpy.int32), "I", TEST_IMAGE_SIZE)
|
||||
|
||||
# Check 64-bit integer formats
|
||||
self.assertRaises(TypeError, lambda: to_image(numpy.uint64))
|
||||
self.assertRaises(TypeError, lambda: to_image(numpy.int64))
|
||||
self.assertRaises(TypeError, to_image, numpy.uint64)
|
||||
self.assertRaises(TypeError, to_image, numpy.int64)
|
||||
|
||||
# Check floating-point formats
|
||||
self.assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE)
|
||||
self.assertRaises(TypeError, lambda: to_image(numpy.float16))
|
||||
self.assertRaises(TypeError, to_image, numpy.float16)
|
||||
self.assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE)
|
||||
self.assert_image(to_image(numpy.float64), "F", TEST_IMAGE_SIZE)
|
||||
|
||||
|
|
41
_imaging.c
41
_imaging.c
|
@ -819,7 +819,7 @@ _filter(ImagingObject* self, PyObject* args)
|
|||
Py_ssize_t kernelsize;
|
||||
FLOAT32* kerneldata;
|
||||
|
||||
int xsize, ysize;
|
||||
int xsize, ysize, i;
|
||||
float divisor, offset;
|
||||
PyObject* kernel = NULL;
|
||||
if (!PyArg_ParseTuple(args, "(ii)ffO", &xsize, &ysize,
|
||||
|
@ -835,8 +835,12 @@ _filter(ImagingObject* self, PyObject* args)
|
|||
return ImagingError_ValueError("bad kernel size");
|
||||
}
|
||||
|
||||
for (i = 0; i < kernelsize; ++i) {
|
||||
kerneldata[i] /= divisor;
|
||||
}
|
||||
|
||||
imOut = PyImagingNew(
|
||||
ImagingFilter(self->image, xsize, ysize, kerneldata, offset, divisor)
|
||||
ImagingFilter(self->image, xsize, ysize, kerneldata, offset)
|
||||
);
|
||||
|
||||
free(kerneldata);
|
||||
|
@ -2198,26 +2202,45 @@ textwidth(ImagingFontObject* self, const unsigned char* text)
|
|||
}
|
||||
|
||||
void _font_text_asBytes(PyObject* encoded_string, unsigned char** text){
|
||||
/* Allocates *text, returns a 'new reference'. Caller is required to free */
|
||||
|
||||
PyObject* bytes = NULL;
|
||||
Py_ssize_t len = 0;
|
||||
char *buffer;
|
||||
|
||||
*text = NULL;
|
||||
|
||||
if (PyUnicode_CheckExact(encoded_string)){
|
||||
bytes = PyUnicode_AsLatin1String(encoded_string);
|
||||
PyBytes_AsStringAndSize(bytes, &buffer, &len);
|
||||
} else if (PyBytes_Check(encoded_string)) {
|
||||
bytes = encoded_string;
|
||||
PyBytes_AsStringAndSize(encoded_string, &buffer, &len);
|
||||
}
|
||||
|
||||
if (len) {
|
||||
*text = calloc(len,1);
|
||||
if (*text) {
|
||||
memcpy(*text, buffer, len);
|
||||
}
|
||||
if(bytes) {
|
||||
*text = (unsigned char*)PyBytes_AsString(bytes);
|
||||
Py_DECREF(bytes);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
/* likely case here is py2.x with an ordinary string.
|
||||
but this isn't defined in Py3.x */
|
||||
if (PyString_Check(encoded_string)) {
|
||||
*text = (unsigned char *)PyString_AsString(encoded_string);
|
||||
PyString_AsStringAndSize(encoded_string, &buffer, &len);
|
||||
*text = calloc(len,1);
|
||||
if (*text) {
|
||||
memcpy(*text, buffer, len);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2248,6 +2271,7 @@ _font_getmask(ImagingFontObject* self, PyObject* args)
|
|||
|
||||
im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize);
|
||||
if (!im) {
|
||||
free(text);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2273,9 +2297,11 @@ _font_getmask(ImagingFontObject* self, PyObject* args)
|
|||
x = x + glyph->dx;
|
||||
b = b + glyph->dy;
|
||||
}
|
||||
free(text);
|
||||
return PyImagingNew(im);
|
||||
|
||||
failed:
|
||||
free(text);
|
||||
ImagingDelete(im);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2285,6 +2311,7 @@ _font_getsize(ImagingFontObject* self, PyObject* args)
|
|||
{
|
||||
unsigned char* text;
|
||||
PyObject* encoded_string;
|
||||
PyObject* val;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:getsize", &encoded_string))
|
||||
return NULL;
|
||||
|
@ -2294,7 +2321,9 @@ _font_getsize(ImagingFontObject* self, PyObject* args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return Py_BuildValue("ii", textwidth(self, text), self->ysize);
|
||||
val = Py_BuildValue("ii", textwidth(self, text), self->ysize);
|
||||
free(text);
|
||||
return val;
|
||||
}
|
||||
|
||||
static struct PyMethodDef _font_methods[] = {
|
||||
|
|
22
_imagingft.c
22
_imagingft.c
|
@ -225,6 +225,11 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
|||
if (PyUnicode_Check(string)) {
|
||||
Py_UNICODE *text = PyUnicode_AS_UNICODE(string);
|
||||
Py_ssize_t size = PyUnicode_GET_SIZE(string);
|
||||
if (! size) {
|
||||
/* return 0 and clean up, no glyphs==no size,
|
||||
and raqm fails with empty strings */
|
||||
goto failed;
|
||||
}
|
||||
if (!raqm_set_text(rq, (const uint32_t *)(text), size)) {
|
||||
PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
|
||||
goto failed;
|
||||
|
@ -234,6 +239,9 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
|||
else if (PyString_Check(string)) {
|
||||
char *text = PyString_AS_STRING(string);
|
||||
int size = PyString_GET_SIZE(string);
|
||||
if (! size) {
|
||||
goto failed;
|
||||
}
|
||||
if (!raqm_set_text_utf8(rq, text, size)) {
|
||||
PyErr_SetString(PyExc_ValueError, "raqm_set_text_utf8() failed");
|
||||
goto failed;
|
||||
|
@ -450,6 +458,10 @@ font_getsize(FontObject* self, PyObject* args)
|
|||
y_max = y_min = 0;
|
||||
|
||||
count = text_layout(string, self, dir, features, &glyph_info, 0);
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
for (x = i = 0; i < count; i++) {
|
||||
int index, error;
|
||||
|
@ -497,6 +509,11 @@ font_getsize(FontObject* self, PyObject* args)
|
|||
FT_Done_Glyph(glyph);
|
||||
}
|
||||
|
||||
if (glyph_info) {
|
||||
PyMem_Free(glyph_info);
|
||||
glyph_info = NULL;
|
||||
}
|
||||
|
||||
if (face) {
|
||||
|
||||
/* left bearing */
|
||||
|
@ -584,9 +601,12 @@ font_render(FontObject* self, PyObject* args)
|
|||
|
||||
glyph_info = NULL;
|
||||
count = text_layout(string, self, dir, features, &glyph_info, mask);
|
||||
if (count == 0) {
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
if (count == 0) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
im = (Imaging) id;
|
||||
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
|
||||
|
|
83
display.c
83
display.c
|
@ -452,84 +452,9 @@ PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args)
|
|||
void* data;
|
||||
PyObject* result;
|
||||
|
||||
int verbose = 0; /* debugging; will be removed in future versions */
|
||||
if (!PyArg_ParseTuple(args, "|i", &verbose))
|
||||
return NULL;
|
||||
|
||||
|
||||
clip = OpenClipboard(NULL);
|
||||
/* FIXME: check error status */
|
||||
|
||||
if (verbose) {
|
||||
UINT format = EnumClipboardFormats(0);
|
||||
char buffer[200];
|
||||
char* result;
|
||||
while (format != 0) {
|
||||
if (GetClipboardFormatName(format, buffer, sizeof buffer) > 0)
|
||||
result = buffer;
|
||||
else
|
||||
switch (format) {
|
||||
case CF_BITMAP:
|
||||
result = "CF_BITMAP";
|
||||
break;
|
||||
case CF_DIB:
|
||||
result = "CF_DIB";
|
||||
break;
|
||||
case CF_DIF:
|
||||
result = "CF_DIF";
|
||||
break;
|
||||
case CF_ENHMETAFILE:
|
||||
result = "CF_ENHMETAFILE";
|
||||
break;
|
||||
case CF_HDROP:
|
||||
result = "CF_HDROP";
|
||||
break;
|
||||
case CF_LOCALE:
|
||||
result = "CF_LOCALE";
|
||||
break;
|
||||
case CF_METAFILEPICT:
|
||||
result = "CF_METAFILEPICT";
|
||||
break;
|
||||
case CF_OEMTEXT:
|
||||
result = "CF_OEMTEXT";
|
||||
break;
|
||||
case CF_OWNERDISPLAY:
|
||||
result = "CF_OWNERDISPLAY";
|
||||
break;
|
||||
case CF_PALETTE:
|
||||
result = "CF_PALETTE";
|
||||
break;
|
||||
case CF_PENDATA:
|
||||
result = "CF_PENDATA";
|
||||
break;
|
||||
case CF_RIFF:
|
||||
result = "CF_RIFF";
|
||||
break;
|
||||
case CF_SYLK:
|
||||
result = "CF_SYLK";
|
||||
break;
|
||||
case CF_TEXT:
|
||||
result = "CF_TEXT";
|
||||
break;
|
||||
case CF_WAVE:
|
||||
result = "CF_WAVE";
|
||||
break;
|
||||
case CF_TIFF:
|
||||
result = "CF_TIFF";
|
||||
break;
|
||||
case CF_UNICODETEXT:
|
||||
result = "CF_UNICODETEXT";
|
||||
break;
|
||||
default:
|
||||
sprintf(buffer, "[%d]", format);
|
||||
result = buffer;
|
||||
break;
|
||||
}
|
||||
printf("%s (%d)\n", result, format);
|
||||
format = EnumClipboardFormats(format);
|
||||
}
|
||||
}
|
||||
|
||||
handle = GetClipboardData(CF_DIB);
|
||||
if (!handle) {
|
||||
/* FIXME: add CF_HDROP support to allow cut-and-paste from
|
||||
|
@ -542,14 +467,6 @@ PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args)
|
|||
size = GlobalSize(handle);
|
||||
data = GlobalLock(handle);
|
||||
|
||||
#if 0
|
||||
/* calculate proper size for string formats */
|
||||
if (format == CF_TEXT || format == CF_OEMTEXT)
|
||||
size = strlen(data);
|
||||
else if (format == CF_UNICODETEXT)
|
||||
size = wcslen(data) * 2;
|
||||
#endif
|
||||
|
||||
result = PyBytes_FromStringAndSize(data, size);
|
||||
|
||||
GlobalUnlock(handle);
|
||||
|
|
|
@ -178,8 +178,8 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
|||
**sizes**
|
||||
A list of sizes including in this ico file; these are a 2-tuple,
|
||||
``(width, height)``; Default to ``[(16, 16), (24, 24), (32, 32), (48, 48),
|
||||
(64, 64), (128, 128), (255, 255)]``. Any sizes bigger than the original
|
||||
size or 255 will be ignored.
|
||||
(64, 64), (128, 128), (256, 256)]``. Any sizes bigger than the original
|
||||
size or 256 will be ignored.
|
||||
|
||||
IM
|
||||
^^
|
||||
|
|
|
@ -262,6 +262,7 @@ The easiest way to install external libraries is via `Homebrew
|
|||
$ brew install libtiff libjpeg webp little-cms2
|
||||
|
||||
To install libraqm on macOS use Homebrew to install its dependencies::
|
||||
|
||||
$ brew install freetype harfbuzz fribidi
|
||||
|
||||
Then see ``depends/install_raqm_cmake.sh`` to install libraqm.
|
||||
|
|
|
@ -265,7 +265,7 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
Calculates the white point temperature (see the LCMS documentation
|
||||
for more information).
|
||||
|
||||
:type: :py:class:`float` or `None`
|
||||
:type: :py:class:`float` or ``None``
|
||||
|
||||
.. py:attribute:: viewing_condition
|
||||
|
||||
|
|
|
@ -6,4 +6,49 @@ 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.
|
||||
``image.getchannel("A")`` will return alpha channel as separate image.
|
||||
``getchannel`` should work up to 6 times faster than ``image.split()[0]``
|
||||
in previous Pillow versions.
|
||||
|
||||
|
||||
Partial Resampling
|
||||
==================
|
||||
|
||||
Added new argument ``box`` for :py:meth:`PIL.Image.Image.resize`. This
|
||||
argument defines a source rectangle from within the source image to be
|
||||
resized. This is very similar to the ``image.crop(box).resize(size)``
|
||||
sequence except that ``box`` can be specified with subpixel accuracy.
|
||||
|
||||
|
||||
Loading 16-bit TIFF Images
|
||||
==========================
|
||||
|
||||
Pillow now can read 16-bit multichannel TIFF files including files
|
||||
with alpha transparency. The image data is truncated to 8-bit
|
||||
precision.
|
||||
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
This release contains several performance improvements:
|
||||
|
||||
* Many memory bandwidth-bounded operations such as crop, image allocation,
|
||||
conversion, split into bands and merging from bands are up to 2x faster.
|
||||
* Upscaling of multichannel images (such as RGB) is accelerated by 5-10%
|
||||
* JPEG loading is accelerated up to 15% and JPEG saving up to 20% when
|
||||
using a recent version of libjpeg-turbo.
|
||||
|
||||
|
||||
Core Image API Changes
|
||||
======================
|
||||
|
||||
These are internal functions that should not have been used by user
|
||||
code, but they were accessible from the python layer.
|
||||
|
||||
Debugging code within ``Image.core.grabclipboard`` was removed. It had been
|
||||
marked as ``will be removed in future versions`` since PIL. When enabled, it
|
||||
identified the format of the clipboard data.
|
||||
|
||||
The ``PIL.Image.core.copy`` and ``PIL.Image.Image.im.copy2`` methods
|
||||
have been removed.
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
/* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
|
||||
#define L(rgb)\
|
||||
((INT32) (rgb)[0]*299 + (INT32) (rgb)[1]*587 + (INT32) (rgb)[2]*114)
|
||||
#define L24(rgb)\
|
||||
((rgb)[0]*19595 + (rgb)[1]*38470 + (rgb)[2]*7471)
|
||||
|
||||
#ifndef round
|
||||
double round(double x) {
|
||||
|
@ -210,7 +212,7 @@ rgb2l(UINT8* out, const UINT8* in, int xsize)
|
|||
int x;
|
||||
for (x = 0; x < xsize; x++, in += 4)
|
||||
/* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
|
||||
*out++ = L(in) / 1000;
|
||||
*out++ = L24(in) >> 16;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -219,7 +221,7 @@ rgb2la(UINT8* out, const UINT8* in, int xsize)
|
|||
int x;
|
||||
for (x = 0; x < xsize; x++, in += 4, out += 4) {
|
||||
/* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
|
||||
out[0] = out[1] = out[2] = L(in) / 1000;
|
||||
out[0] = out[1] = out[2] = L24(in) >> 16;
|
||||
out[3] = 255;
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +232,7 @@ rgb2i(UINT8* out_, const UINT8* in, int xsize)
|
|||
int x;
|
||||
INT32* out = (INT32*) out_;
|
||||
for (x = 0; x < xsize; x++, in += 4)
|
||||
*out++ = L(in) / 1000;
|
||||
*out++ = L24(in) >> 16;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -419,7 +421,7 @@ rgba2la(UINT8* out, const UINT8* in, int xsize)
|
|||
int x;
|
||||
for (x = 0; x < xsize; x++, in += 4, out += 4) {
|
||||
/* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
|
||||
out[0] = out[1] = out[2] = L(in) / 1000;
|
||||
out[0] = out[1] = out[2] = L24(in) >> 16;
|
||||
out[3] = in[3];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,23 @@
|
|||
|
||||
#include "Imaging.h"
|
||||
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define MAKE_UINT32(u0, u1, u2, u3) (u3 | (u2<<8) | (u1<<16) | (u0<<24))
|
||||
#else
|
||||
#define MAKE_UINT32(u0, u1, u2, u3) (u0 | (u1<<8) | (u2<<16) | (u3<<24))
|
||||
#endif
|
||||
|
||||
|
||||
static inline UINT8 clip8(float in)
|
||||
{
|
||||
if (in <= 0.0)
|
||||
return 0;
|
||||
if (in >= 255.0)
|
||||
return 255;
|
||||
return (UINT8) in;
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
|
||||
{
|
||||
|
@ -36,9 +53,8 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
|
|||
if (xmargin < 0 && ymargin < 0)
|
||||
return (Imaging) ImagingError_ValueError("bad kernel size");
|
||||
|
||||
imOut = ImagingNew(
|
||||
imIn->mode, imIn->xsize+2*xmargin, imIn->ysize+2*ymargin
|
||||
);
|
||||
imOut = ImagingNewDirty(
|
||||
imIn->mode, imIn->xsize+2*xmargin, imIn->ysize+2*ymargin);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
|
||||
|
@ -74,16 +90,259 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
|
|||
return imOut;
|
||||
}
|
||||
|
||||
|
||||
/* This is work around bug in GCC prior 4.9 in 64 bit mode.
|
||||
GCC generates code with partial dependency which 3 times slower.
|
||||
See: http://stackoverflow.com/a/26588074/253146 */
|
||||
#if defined(__x86_64__) && defined(__SSE__) && ! defined(__NO_INLINE__) && \
|
||||
! defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
|
||||
static float __attribute__((always_inline)) inline i2f(int v) {
|
||||
float x;
|
||||
__asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=X"(x) : "r"(v) );
|
||||
return x;
|
||||
}
|
||||
#else
|
||||
static float inline i2f(int v) { return (float) v; }
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel,
|
||||
float offset)
|
||||
{
|
||||
#define KERNEL1x3(in0, x, kernel, d) ( \
|
||||
i2f((UINT8) in0[x-d]) * (kernel)[0] + \
|
||||
i2f((UINT8) in0[x]) * (kernel)[1] + \
|
||||
i2f((UINT8) in0[x+d]) * (kernel)[2])
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
memcpy(imOut->image[0], im->image[0], im->linesize);
|
||||
if (im->bands == 1) {
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
for (y = 1; y < im->ysize-1; y++) {
|
||||
UINT8* in_1 = (UINT8*) im->image[y-1];
|
||||
UINT8* in0 = (UINT8*) im->image[y];
|
||||
UINT8* in1 = (UINT8*) im->image[y+1];
|
||||
UINT8* out = (UINT8*) imOut->image[y];
|
||||
|
||||
out[0] = in0[0];
|
||||
for (x = 1; x < im->xsize-1; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x3(in1, x, &kernel[0], 1);
|
||||
ss += KERNEL1x3(in0, x, &kernel[3], 1);
|
||||
ss += KERNEL1x3(in_1, x, &kernel[6], 1);
|
||||
out[x] = clip8(ss);
|
||||
}
|
||||
out[x] = in0[x];
|
||||
}
|
||||
} else {
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
for (y = 1; y < im->ysize-1; y++) {
|
||||
UINT8* in_1 = (UINT8*) im->image[y-1];
|
||||
UINT8* in0 = (UINT8*) im->image[y];
|
||||
UINT8* in1 = (UINT8*) im->image[y+1];
|
||||
UINT32* out = (UINT32*) imOut->image[y];
|
||||
|
||||
out[0] = ((UINT32*) in0)[0];
|
||||
if (im->bands == 2) {
|
||||
for (x = 1; x < im->xsize-1; x++) {
|
||||
float ss0 = offset;
|
||||
float ss3 = offset;
|
||||
ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4);
|
||||
ss3 += KERNEL1x3(in1, x*4+3, &kernel[0], 4);
|
||||
ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4);
|
||||
ss3 += KERNEL1x3(in0, x*4+3, &kernel[3], 4);
|
||||
ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4);
|
||||
ss3 += KERNEL1x3(in_1, x*4+3, &kernel[6], 4);
|
||||
out[x] = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
|
||||
}
|
||||
} else if (im->bands == 3) {
|
||||
for (x = 1; x < im->xsize-1; x++) {
|
||||
float ss0 = offset;
|
||||
float ss1 = offset;
|
||||
float ss2 = offset;
|
||||
ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4);
|
||||
ss1 += KERNEL1x3(in1, x*4+1, &kernel[0], 4);
|
||||
ss2 += KERNEL1x3(in1, x*4+2, &kernel[0], 4);
|
||||
ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4);
|
||||
ss1 += KERNEL1x3(in0, x*4+1, &kernel[3], 4);
|
||||
ss2 += KERNEL1x3(in0, x*4+2, &kernel[3], 4);
|
||||
ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4);
|
||||
ss1 += KERNEL1x3(in_1, x*4+1, &kernel[6], 4);
|
||||
ss2 += KERNEL1x3(in_1, x*4+2, &kernel[6], 4);
|
||||
out[x] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), 0);
|
||||
}
|
||||
} else if (im->bands == 4) {
|
||||
for (x = 1; x < im->xsize-1; x++) {
|
||||
float ss0 = offset;
|
||||
float ss1 = offset;
|
||||
float ss2 = offset;
|
||||
float ss3 = offset;
|
||||
ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4);
|
||||
ss1 += KERNEL1x3(in1, x*4+1, &kernel[0], 4);
|
||||
ss2 += KERNEL1x3(in1, x*4+2, &kernel[0], 4);
|
||||
ss3 += KERNEL1x3(in1, x*4+3, &kernel[0], 4);
|
||||
ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4);
|
||||
ss1 += KERNEL1x3(in0, x*4+1, &kernel[3], 4);
|
||||
ss2 += KERNEL1x3(in0, x*4+2, &kernel[3], 4);
|
||||
ss3 += KERNEL1x3(in0, x*4+3, &kernel[3], 4);
|
||||
ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4);
|
||||
ss1 += KERNEL1x3(in_1, x*4+1, &kernel[6], 4);
|
||||
ss2 += KERNEL1x3(in_1, x*4+2, &kernel[6], 4);
|
||||
ss3 += KERNEL1x3(in_1, x*4+3, &kernel[6], 4);
|
||||
out[x] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
|
||||
}
|
||||
}
|
||||
out[x] = ((UINT32*) in0)[x];
|
||||
}
|
||||
}
|
||||
memcpy(imOut->image[y], im->image[y], im->linesize);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImagingFilter5x5(Imaging imOut, Imaging im, const float* kernel,
|
||||
float offset)
|
||||
{
|
||||
#define KERNEL1x5(in0, x, kernel, d) ( \
|
||||
i2f((UINT8) in0[x-d-d]) * (kernel)[0] + \
|
||||
i2f((UINT8) in0[x-d]) * (kernel)[1] + \
|
||||
i2f((UINT8) in0[x]) * (kernel)[2] + \
|
||||
i2f((UINT8) in0[x+d]) * (kernel)[3] + \
|
||||
i2f((UINT8) in0[x+d+d]) * (kernel)[4])
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
memcpy(imOut->image[0], im->image[0], im->linesize);
|
||||
memcpy(imOut->image[1], im->image[1], im->linesize);
|
||||
if (im->bands == 1) {
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
for (y = 2; y < im->ysize-2; y++) {
|
||||
UINT8* in_2 = (UINT8*) im->image[y-2];
|
||||
UINT8* in_1 = (UINT8*) im->image[y-1];
|
||||
UINT8* in0 = (UINT8*) im->image[y];
|
||||
UINT8* in1 = (UINT8*) im->image[y+1];
|
||||
UINT8* in2 = (UINT8*) im->image[y+2];
|
||||
UINT8* out = (UINT8*) imOut->image[y];
|
||||
|
||||
out[0] = in0[0];
|
||||
out[1] = in0[1];
|
||||
for (x = 2; x < im->xsize-2; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x5(in2, x, &kernel[0], 1);
|
||||
ss += KERNEL1x5(in1, x, &kernel[5], 1);
|
||||
ss += KERNEL1x5(in0, x, &kernel[10], 1);
|
||||
ss += KERNEL1x5(in_1, x, &kernel[15], 1);
|
||||
ss += KERNEL1x5(in_2, x, &kernel[20], 1);
|
||||
out[x] = clip8(ss);
|
||||
}
|
||||
out[x+0] = in0[x+0];
|
||||
out[x+1] = in0[x+1];
|
||||
}
|
||||
} else {
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
for (y = 2; y < im->ysize-2; y++) {
|
||||
UINT8* in_2 = (UINT8*) im->image[y-2];
|
||||
UINT8* in_1 = (UINT8*) im->image[y-1];
|
||||
UINT8* in0 = (UINT8*) im->image[y];
|
||||
UINT8* in1 = (UINT8*) im->image[y+1];
|
||||
UINT8* in2 = (UINT8*) im->image[y+2];
|
||||
UINT32* out = (UINT32*) imOut->image[y];
|
||||
|
||||
out[0] = ((UINT32*) in0)[0];
|
||||
out[1] = ((UINT32*) in0)[1];
|
||||
if (im->bands == 2) {
|
||||
for (x = 2; x < im->xsize-2; x++) {
|
||||
float ss0 = offset;
|
||||
float ss3 = offset;
|
||||
ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4);
|
||||
ss3 += KERNEL1x5(in2, x*4+3, &kernel[0], 4);
|
||||
ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4);
|
||||
ss3 += KERNEL1x5(in1, x*4+3, &kernel[5], 4);
|
||||
ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4);
|
||||
ss3 += KERNEL1x5(in0, x*4+3, &kernel[10], 4);
|
||||
ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4);
|
||||
ss3 += KERNEL1x5(in_1, x*4+3, &kernel[15], 4);
|
||||
ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4);
|
||||
ss3 += KERNEL1x5(in_2, x*4+3, &kernel[20], 4);
|
||||
out[x] = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
|
||||
}
|
||||
} else if (im->bands == 3) {
|
||||
for (x = 2; x < im->xsize-2; x++) {
|
||||
float ss0 = offset;
|
||||
float ss1 = offset;
|
||||
float ss2 = offset;
|
||||
ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4);
|
||||
ss1 += KERNEL1x5(in2, x*4+1, &kernel[0], 4);
|
||||
ss2 += KERNEL1x5(in2, x*4+2, &kernel[0], 4);
|
||||
ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4);
|
||||
ss1 += KERNEL1x5(in1, x*4+1, &kernel[5], 4);
|
||||
ss2 += KERNEL1x5(in1, x*4+2, &kernel[5], 4);
|
||||
ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4);
|
||||
ss1 += KERNEL1x5(in0, x*4+1, &kernel[10], 4);
|
||||
ss2 += KERNEL1x5(in0, x*4+2, &kernel[10], 4);
|
||||
ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4);
|
||||
ss1 += KERNEL1x5(in_1, x*4+1, &kernel[15], 4);
|
||||
ss2 += KERNEL1x5(in_1, x*4+2, &kernel[15], 4);
|
||||
ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4);
|
||||
ss1 += KERNEL1x5(in_2, x*4+1, &kernel[20], 4);
|
||||
ss2 += KERNEL1x5(in_2, x*4+2, &kernel[20], 4);
|
||||
out[x] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), 0);
|
||||
}
|
||||
} else if (im->bands == 4) {
|
||||
for (x = 2; x < im->xsize-2; x++) {
|
||||
float ss0 = offset;
|
||||
float ss1 = offset;
|
||||
float ss2 = offset;
|
||||
float ss3 = offset;
|
||||
ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4);
|
||||
ss1 += KERNEL1x5(in2, x*4+1, &kernel[0], 4);
|
||||
ss2 += KERNEL1x5(in2, x*4+2, &kernel[0], 4);
|
||||
ss3 += KERNEL1x5(in2, x*4+3, &kernel[0], 4);
|
||||
ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4);
|
||||
ss1 += KERNEL1x5(in1, x*4+1, &kernel[5], 4);
|
||||
ss2 += KERNEL1x5(in1, x*4+2, &kernel[5], 4);
|
||||
ss3 += KERNEL1x5(in1, x*4+3, &kernel[5], 4);
|
||||
ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4);
|
||||
ss1 += KERNEL1x5(in0, x*4+1, &kernel[10], 4);
|
||||
ss2 += KERNEL1x5(in0, x*4+2, &kernel[10], 4);
|
||||
ss3 += KERNEL1x5(in0, x*4+3, &kernel[10], 4);
|
||||
ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4);
|
||||
ss1 += KERNEL1x5(in_1, x*4+1, &kernel[15], 4);
|
||||
ss2 += KERNEL1x5(in_1, x*4+2, &kernel[15], 4);
|
||||
ss3 += KERNEL1x5(in_1, x*4+3, &kernel[15], 4);
|
||||
ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4);
|
||||
ss1 += KERNEL1x5(in_2, x*4+1, &kernel[20], 4);
|
||||
ss2 += KERNEL1x5(in_2, x*4+2, &kernel[20], 4);
|
||||
ss3 += KERNEL1x5(in_2, x*4+3, &kernel[20], 4);
|
||||
out[x] = MAKE_UINT32(
|
||||
clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
|
||||
}
|
||||
}
|
||||
out[x] = ((UINT32*) in0)[x];
|
||||
out[x+1] = ((UINT32*) in0)[x+1];
|
||||
}
|
||||
}
|
||||
memcpy(imOut->image[y], im->image[y], im->linesize);
|
||||
memcpy(imOut->image[y+1], im->image[y+1], im->linesize);
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
||||
FLOAT32 offset, FLOAT32 divisor)
|
||||
FLOAT32 offset)
|
||||
{
|
||||
Imaging imOut;
|
||||
int x, y;
|
||||
FLOAT32 sum;
|
||||
ImagingSectionCookie cookie;
|
||||
|
||||
if (!im || strcmp(im->mode, "L") != 0)
|
||||
if ( ! im || im->type != IMAGING_TYPE_UINT8)
|
||||
return (Imaging) ImagingError_ModeError();
|
||||
|
||||
if (im->xsize < xsize || im->ysize < ysize)
|
||||
|
@ -92,95 +351,17 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
|||
if ((xsize != 3 && xsize != 5) || xsize != ysize)
|
||||
return (Imaging) ImagingError_ValueError("bad kernel size");
|
||||
|
||||
imOut = ImagingNew(im->mode, im->xsize, im->ysize);
|
||||
imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
|
||||
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] + \
|
||||
(int) image[y+1][x] * kernel[1] + \
|
||||
(int) image[y+1][x+d] * kernel[2] + \
|
||||
(int) image[y][x-d] * kernel[3] + \
|
||||
(int) image[y][x] * kernel[4] + \
|
||||
(int) image[y][x+d] * kernel[5] + \
|
||||
(int) image[y-1][x-d] * kernel[6] + \
|
||||
(int) image[y-1][x] * kernel[7] + \
|
||||
(int) image[y-1][x+d] * kernel[8])
|
||||
|
||||
#define KERNEL5x5(image, kernel, d) ( \
|
||||
(int) image[y+2][x-d-d] * kernel[0] + \
|
||||
(int) image[y+2][x-d] * kernel[1] + \
|
||||
(int) image[y+2][x] * kernel[2] + \
|
||||
(int) image[y+2][x+d] * kernel[3] + \
|
||||
(int) image[y+2][x+d+d] * kernel[4] + \
|
||||
(int) image[y+1][x-d-d] * kernel[5] + \
|
||||
(int) image[y+1][x-d] * kernel[6] + \
|
||||
(int) image[y+1][x] * kernel[7] + \
|
||||
(int) image[y+1][x+d] * kernel[8] + \
|
||||
(int) image[y+1][x+d+d] * kernel[9] + \
|
||||
(int) image[y][x-d-d] * kernel[10] + \
|
||||
(int) image[y][x-d] * kernel[11] + \
|
||||
(int) image[y][x] * kernel[12] + \
|
||||
(int) image[y][x+d] * kernel[13] + \
|
||||
(int) image[y][x+d+d] * kernel[14] + \
|
||||
(int) image[y-1][x-d-d] * kernel[15] + \
|
||||
(int) image[y-1][x-d] * kernel[16] + \
|
||||
(int) image[y-1][x] * kernel[17] + \
|
||||
(int) image[y-1][x+d] * kernel[18] + \
|
||||
(int) image[y-1][x+d+d] * kernel[19] + \
|
||||
(int) image[y-2][x-d-d] * kernel[20] + \
|
||||
(int) image[y-2][x-d] * kernel[21] + \
|
||||
(int) image[y-2][x] * kernel[22] + \
|
||||
(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++)
|
||||
imOut->image[0][x] = im->image8[0][x];
|
||||
for (y = 1; y < im->ysize-1; y++) {
|
||||
imOut->image[y][0] = im->image8[y][0];
|
||||
for (x = 1; x < im->xsize-1; x++) {
|
||||
sum = KERNEL3x3(im->image8, kernel, 1) / divisor + offset;
|
||||
if (sum <= 0)
|
||||
imOut->image8[y][x] = 0;
|
||||
else if (sum >= 255)
|
||||
imOut->image8[y][x] = 255;
|
||||
else
|
||||
imOut->image8[y][x] = (UINT8) sum;
|
||||
}
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
}
|
||||
for (x = 0; x < im->xsize; x++)
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
ImagingFilter3x3(imOut, im, kernel, offset);
|
||||
} else {
|
||||
/* 5x5 kernel. */
|
||||
for (y = 0; y < 2; y++)
|
||||
for (x = 0; x < im->xsize; x++)
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
for (; y < im->ysize-2; y++) {
|
||||
for (x = 0; x < 2; x++)
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
for (; x < im->xsize-2; x++) {
|
||||
sum = KERNEL5x5(im->image8, kernel, 1) / divisor + offset;
|
||||
if (sum <= 0)
|
||||
imOut->image8[y][x] = 0;
|
||||
else if (sum >= 255)
|
||||
imOut->image8[y][x] = 255;
|
||||
else
|
||||
imOut->image8[y][x] = (UINT8) sum;
|
||||
}
|
||||
for (; x < im->xsize; x++)
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
}
|
||||
for (; y < im->ysize; y++)
|
||||
for (x = 0; x < im->xsize; x++)
|
||||
imOut->image8[y][x] = im->image8[y][x];
|
||||
ImagingFilter5x5(imOut, im, kernel, offset);
|
||||
}
|
||||
ImagingSectionLeave(&cookie);
|
||||
return imOut;
|
||||
|
|
|
@ -26,24 +26,30 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn)
|
|||
|
||||
ImagingCopyInfo(imOut, imIn);
|
||||
|
||||
#define FLIP_HORIZ(image)\
|
||||
for (y = 0; y < imIn->ysize; y++) {\
|
||||
xr = imIn->xsize-1;\
|
||||
for (x = 0; x < imIn->xsize; x++, xr--)\
|
||||
imOut->image[y][x] = imIn->image[y][xr];\
|
||||
}
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
|
||||
if (imIn->image8)
|
||||
FLIP_HORIZ(image8)
|
||||
else
|
||||
FLIP_HORIZ(image32)
|
||||
if (imIn->image8) {
|
||||
for (y = 0; y < imIn->ysize; y++) {
|
||||
UINT8* in = (UINT8*) imIn->image8[y];
|
||||
UINT8* out = (UINT8*) imOut->image8[y];
|
||||
x = 0;
|
||||
xr = imIn->xsize-1;
|
||||
for (; x < imIn->xsize; x++, xr--)
|
||||
out[xr] = in[x];
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < imIn->ysize; y++) {
|
||||
UINT32* in = (UINT32*) imIn->image32[y];
|
||||
UINT32* out = (UINT32*) imOut->image32[y];
|
||||
x = 0;
|
||||
xr = imIn->xsize-1;
|
||||
for (; x < imIn->xsize; x++, xr--)
|
||||
out[xr] = in[x];
|
||||
}
|
||||
}
|
||||
|
||||
ImagingSectionLeave(&cookie);
|
||||
|
||||
#undef FLIP_HORIZ
|
||||
|
||||
return imOut;
|
||||
}
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ extern Imaging ImagingFillLinearGradient(const char* mode);
|
|||
extern Imaging ImagingFillRadialGradient(const char* mode);
|
||||
extern Imaging ImagingFilter(
|
||||
Imaging im, int xsize, int ysize, const FLOAT32* kernel,
|
||||
FLOAT32 offset, FLOAT32 divisor);
|
||||
FLOAT32 offset);
|
||||
extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn);
|
||||
extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn);
|
||||
extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius,
|
||||
|
|
Loading…
Reference in New Issue
Block a user