Health fixes

This commit is contained in:
Andrew Murray 2016-02-05 09:57:13 +11:00
parent 0129c50933
commit 677b958a7f
20 changed files with 116 additions and 125 deletions

View File

@ -256,7 +256,6 @@ class DdsImageFile(ImageFile.ImageFile):
self.fp = BytesIO(decoded_data) self.fp = BytesIO(decoded_data)
def load_seek(self, pos): def load_seek(self, pos):
pass pass

View File

@ -83,7 +83,6 @@ class FtexImageFile(ImageFile.ImageFile):
self.fp.close() self.fp.close()
self.fp = BytesIO(data) self.fp = BytesIO(data)
def load_seek(self, pos): def load_seek(self, pos):
pass pass

View File

@ -30,7 +30,7 @@ i32 = _binary.i32be
def _accept(prefix): def _accept(prefix):
return len(prefix) >= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1,2) return len(prefix) >= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2)
## ##
@ -46,16 +46,16 @@ class GbrImageFile(ImageFile.ImageFile):
version = i32(self.fp.read(4)) version = i32(self.fp.read(4))
if header_size < 20: if header_size < 20:
raise SyntaxError("not a GIMP brush") raise SyntaxError("not a GIMP brush")
if version not in (1,2): if version not in (1, 2):
raise SyntaxError("Unsupported GIMP brush version: %s" %version) raise SyntaxError("Unsupported GIMP brush version: %s" % version)
width = i32(self.fp.read(4)) width = i32(self.fp.read(4))
height = i32(self.fp.read(4)) height = i32(self.fp.read(4))
color_depth = i32(self.fp.read(4)) color_depth = i32(self.fp.read(4))
if width <= 0 or height <= 0: if width <= 0 or height <= 0:
raise SyntaxError("not a GIMP brush") raise SyntaxError("not a GIMP brush")
if color_depth not in (1,4): if color_depth not in (1, 4):
raise SyntaxError("Unsupported GMP brush color depth: %s" %color_depth) raise SyntaxError("Unsupported GMP brush color depth: %s" % color_depth)
if version == 1: if version == 1:
comment_length = header_size-20 comment_length = header_size-20

View File

@ -57,7 +57,7 @@ import struct
import sys import sys
import warnings import warnings
from .TiffTags import TYPES, TagInfo from .TiffTags import TYPES
__version__ = "1.3.5" __version__ = "1.3.5"
@ -227,6 +227,7 @@ def _limit_rational(val, max_val):
_load_dispatch = {} _load_dispatch = {}
_write_dispatch = {} _write_dispatch = {}
class IFDRational(Rational): class IFDRational(Rational):
""" Implements a rational class where 0/0 is a legal value to match """ Implements a rational class where 0/0 is a legal value to match
the in the wild use of exif rationals. the in the wild use of exif rationals.
@ -266,7 +267,6 @@ class IFDRational(Rational):
self._val = float('nan') self._val = float('nan')
return return
elif denominator == 1: elif denominator == 1:
if sys.hexversion < 0x2070000 and type(value) == float: if sys.hexversion < 0x2070000 and type(value) == float:
# python 2.6 is different. # python 2.6 is different.
@ -284,7 +284,6 @@ class IFDRational(Rational):
def denominator(a): def denominator(a):
return a._denominator return a._denominator
def limit_rational(self, max_denominator): def limit_rational(self, max_denominator):
""" """
@ -304,12 +303,12 @@ class IFDRational(Rational):
def __hash__(self): def __hash__(self):
return self._val.__hash__() return self._val.__hash__()
def __eq__(self,other): def __eq__(self, other):
return self._val == other return self._val == other
def _delegate(op): def _delegate(op):
def delegate(self, *args): def delegate(self, *args):
return getattr(self._val,op)(*args) return getattr(self._val, op)(*args)
return delegate return delegate
""" a = ['add','radd', 'sub', 'rsub','div', 'rdiv', 'mul', 'rmul', """ a = ['add','radd', 'sub', 'rsub','div', 'rdiv', 'mul', 'rmul',
@ -350,7 +349,6 @@ class IFDRational(Rational):
__round__ = _delegate('__round__') __round__ = _delegate('__round__')
class ImageFileDirectory_v2(collections.MutableMapping): class ImageFileDirectory_v2(collections.MutableMapping):
"""This class represents a TIFF tag directory. To speed things up, we """This class represents a TIFF tag directory. To speed things up, we
don't decode tags unless they're asked for. don't decode tags unless they're asked for.
@ -1126,8 +1124,8 @@ class TiffImageFile(ImageFile.ImageFile):
self.info["compression"] = self._compression self.info["compression"] = self._compression
xres = self.tag_v2.get(X_RESOLUTION,1) xres = self.tag_v2.get(X_RESOLUTION, 1)
yres = self.tag_v2.get(Y_RESOLUTION,1) yres = self.tag_v2.get(Y_RESOLUTION, 1)
if xres and yres: if xres and yres:
resunit = self.tag_v2.get(RESOLUTION_UNIT, 1) resunit = self.tag_v2.get(RESOLUTION_UNIT, 1)
@ -1416,14 +1414,15 @@ def _save(im, fp, filename):
if hasattr(im, 'tag'): if hasattr(im, 'tag'):
legacy_ifd = im.tag.to_v2() legacy_ifd = im.tag.to_v2()
for tag, value in itertools.chain(ifd.items(), for tag, value in itertools.chain(ifd.items(),
getattr(im, 'tag_v2', {}).items(), getattr(im, 'tag_v2', {}).items(),
legacy_ifd.items()): legacy_ifd.items()):
# Libtiff can only process certain core items without adding # Libtiff can only process certain core items without adding
# them to the custom dictionary. It will segfault if it attempts # them to the custom dictionary. It will segfault if it attempts
# to add a custom tag without the dictionary entry # to add a custom tag without the dictionary entry
# #
# UNDONE -- add code for the custom dictionary # UNDONE -- add code for the custom dictionary
if tag not in TiffTags.LIBTIFF_CORE: continue if tag not in TiffTags.LIBTIFF_CORE:
continue
if tag not in atts and tag not in blocklist: if tag not in atts and tag not in blocklist:
if isinstance(value, unicode if bytes is str else str): if isinstance(value, unicode if bytes is str else str):
atts[tag] = value.encode('ascii', 'replace') + b"\0" atts[tag] = value.encode('ascii', 'replace') + b"\0"

View File

@ -30,6 +30,7 @@ class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
def cvt_enum(self, value): def cvt_enum(self, value):
return self.enum.get(value, value) return self.enum.get(value, value)
def lookup(tag): def lookup(tag):
""" """
:param tag: Integer tag number :param tag: Integer tag number
@ -378,22 +379,22 @@ TYPES = {}
# some of these are not in our TAGS_V2 dict and were included from tiff.h # some of these are not in our TAGS_V2 dict and were included from tiff.h
LIBTIFF_CORE = set ([255, 256, 257, 258, 259, 262, 263, 266, 274, 277, LIBTIFF_CORE = set([255, 256, 257, 258, 259, 262, 263, 266, 274, 277,
278, 280, 281, 340, 341, 282, 283, 284, 286, 287, 278, 280, 281, 340, 341, 282, 283, 284, 286, 287,
296, 297, 321, 320, 338, 32995, 322, 323, 32998, 296, 297, 321, 320, 338, 32995, 322, 323, 32998,
32996, 339, 32997, 330, 531, 530, 301, 532, 333, 32996, 339, 32997, 330, 531, 530, 301, 532, 333,
# as above # as above
269 # this has been in our tests forever, and works 269 # this has been in our tests forever, and works
]) ])
LIBTIFF_CORE.remove(320) # Array of short, crashes LIBTIFF_CORE.remove(320) # Array of short, crashes
LIBTIFF_CORE.remove(301) # Array of short, crashes LIBTIFF_CORE.remove(301) # Array of short, crashes
LIBTIFF_CORE.remove(532) # Array of long, crashes LIBTIFF_CORE.remove(532) # Array of long, crashes
LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes
LIBTIFF_CORE.remove(322) # We don't have support for tiled images in libtiff LIBTIFF_CORE.remove(322) # We don't have support for tiled images in libtiff
LIBTIFF_CORE.remove(323) # Tiled images LIBTIFF_CORE.remove(323) # Tiled images
LIBTIFF_CORE.remove(333) # Ink Names either LIBTIFF_CORE.remove(333) # Ink Names either
# Note to advanced users: There may be combinations of these # Note to advanced users: There may be combinations of these
# parameters and values that when added properly, will work and # parameters and values that when added properly, will work and

View File

@ -3,6 +3,7 @@ from PIL import Image
TEST_FILE = "Tests/images/libtiff_segfault.tif" TEST_FILE = "Tests/images/libtiff_segfault.tif"
class TestLibtiffSegfault(PillowTestCase): class TestLibtiffSegfault(PillowTestCase):
def test_segfault(self): def test_segfault(self):
""" This test should not segfault. It will on Pillow <= 3.1.0 and """ This test should not segfault. It will on Pillow <= 3.1.0 and
@ -18,6 +19,5 @@ class TestLibtiffSegfault(PillowTestCase):
self.fail("Should have returned IOError") self.fail("Should have returned IOError")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -78,7 +78,7 @@ class TestFileDds(PillowTestCase):
img_file = f.read() img_file = f.read()
def short_header(): def short_header():
im = Image.open(BytesIO(img_file[:119])) Image.open(BytesIO(img_file[:119]))
self.assertRaises(IOError, short_header) self.assertRaises(IOError, short_header)
@ -89,7 +89,7 @@ class TestFileDds(PillowTestCase):
img_file = f.read() img_file = f.read()
def short_file(): def short_file():
im = Image.open(BytesIO(img_file[:-100])) Image.open(BytesIO(img_file[:-100]))
self.assertRaises(IOError, short_file) self.assertRaises(IOError, short_file)

View File

@ -1,6 +1,7 @@
from helper import unittest, PillowTestCase from helper import PillowTestCase
from PIL import Image from PIL import Image
class TestFileFtex(PillowTestCase): class TestFileFtex(PillowTestCase):
def test_load_raw(self): def test_load_raw(self):

View File

@ -11,7 +11,6 @@ class TestFileGbr(PillowTestCase):
self.assertRaises(SyntaxError, self.assertRaises(SyntaxError,
lambda: GbrImagePlugin.GbrImageFile(invalid_file)) lambda: GbrImagePlugin.GbrImageFile(invalid_file))
def test_gbr_file(self): def test_gbr_file(self):
im = Image.open('Tests/images/gbr.gbr') im = Image.open('Tests/images/gbr.gbr')

View File

@ -219,7 +219,6 @@ class TestFileJpeg(PillowTestCase):
for tag, value in expected_exif.items(): for tag, value in expected_exif.items():
self.assertEqual(value, exif[tag]) self.assertEqual(value, exif[tag])
def test_exif_gps_typeerror(self): def test_exif_gps_typeerror(self):
im = Image.open('Tests/images/exif_gps_typeerror.jpg') im = Image.open('Tests/images/exif_gps_typeerror.jpg')

View File

@ -179,7 +179,7 @@ class TestFileLibTiff(LibTiffTestCase):
# Get the list of the ones that we should be able to write # Get the list of the ones that we should be able to write
core_items = dict((tag, info) for tag, info in [(s,TiffTags.lookup(s)) for s core_items = dict((tag, info) for tag, info in [(s, TiffTags.lookup(s)) for s
in TiffTags.LIBTIFF_CORE] in TiffTags.LIBTIFF_CORE]
if info.type is not None) if info.type is not None)
@ -188,7 +188,8 @@ class TestFileLibTiff(LibTiffTestCase):
for tag in im.tag_v2.keys(): for tag in im.tag_v2.keys():
try: try:
del(core_items[tag]) del(core_items[tag])
except: pass except:
pass
# Type codes: # Type codes:
# 2: "ascii", # 2: "ascii",
@ -197,12 +198,11 @@ class TestFileLibTiff(LibTiffTestCase):
# 5: "rational", # 5: "rational",
# 12: "double", # 12: "double",
# type: dummy value # type: dummy value
values = { 2: 'test', values = {2: 'test',
3: 1, 3: 1,
4: 2**20, 4: 2**20,
5: TiffImagePlugin.IFDRational(100,1), 5: TiffImagePlugin.IFDRational(100, 1),
12: 1.05 } 12: 1.05}
new_ifd = TiffImagePlugin.ImageFileDirectory_v2() new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
for tag, info in core_items.items(): for tag, info in core_items.items():
@ -223,8 +223,6 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = False TiffImagePlugin.WRITE_LIBTIFF = False
def test_g3_compression(self): def test_g3_compression(self):
i = Image.open('Tests/images/hopper_g4_500.tif') i = Image.open('Tests/images/hopper_g4_500.tif')
out = self.tempfile("temp.tif") out = self.tempfile("temp.tif")
@ -459,7 +457,6 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = False TiffImagePlugin.WRITE_LIBTIFF = False
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -1,11 +1,12 @@
from helper import unittest, PillowTestCase, hopper from helper import unittest, PillowTestCase
from PIL import Image from PIL import Image
class TestFilePcd(PillowTestCase): class TestFilePcd(PillowTestCase):
def test_load_raw(self): def test_load_raw(self):
im = Image.open('Tests/images/hopper.pcd') im = Image.open('Tests/images/hopper.pcd')
im.load() # should not segfault. im.load() # should not segfault.
# Note that this image was created with a resized hopper # Note that this image was created with a resized hopper
# image, which was then converted to pcd with imagemagick # image, which was then converted to pcd with imagemagick
@ -13,10 +14,9 @@ class TestFilePcd(PillowTestCase):
# is a pillow or a convert issue, as other images not generated # is a pillow or a convert issue, as other images not generated
# from convert look find on pillow and not imagemagick. # from convert look find on pillow and not imagemagick.
#target = hopper().resize((768,512)) # target = hopper().resize((768,512))
#self.assert_image_similar(im, target, 10) # self.assert_image_similar(im, target, 10)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -84,7 +84,7 @@ class TestFileTiff(PillowTestCase):
self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple) self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple)
self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple) self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple)
#v2 api # v2 api
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational) self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational) self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)

View File

@ -122,21 +122,22 @@ class TestFileTiffMetadata(PillowTestCase):
original = img.tag_v2.named() original = img.tag_v2.named()
reloaded = loaded.tag_v2.named() reloaded = loaded.tag_v2.named()
for k,v in original.items(): for k, v in original.items():
if type(v) == IFDRational: if type(v) == IFDRational:
original[k] = IFDRational(*_limit_rational(v,2**31)) original[k] = IFDRational(*_limit_rational(v, 2**31))
if type(v) == tuple and \ if type(v) == tuple and \
type(v[0]) == IFDRational: type(v[0]) == IFDRational:
original[k] = tuple([IFDRational( original[k] = tuple([IFDRational(
*_limit_rational(elt, 2**31)) for elt in v]) *_limit_rational(elt, 2**31)) for elt in v])
ignored = ['StripByteCounts', 'RowsPerStrip', ignored = ['StripByteCounts', 'RowsPerStrip',
'PageNumber', 'StripOffsets'] 'PageNumber', 'StripOffsets']
for tag, value in reloaded.items(): for tag, value in reloaded.items():
if tag in ignored: continue if tag in ignored:
continue
if (type(original[tag]) == tuple if (type(original[tag]) == tuple
and type(original[tag][0]) == IFDRational): and type(original[tag][0]) == IFDRational):
# Need to compare element by element in the tuple, # Need to compare element by element in the tuple,
# not comparing tuples of object references # not comparing tuples of object references
self.assert_deep_equal(original[tag], self.assert_deep_equal(original[tag],
@ -188,7 +189,7 @@ class TestFileTiffMetadata(PillowTestCase):
def test_exif_div_zero(self): def test_exif_div_zero(self):
im = hopper() im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2() info = TiffImagePlugin.ImageFileDirectory_v2()
info[41988] = TiffImagePlugin.IFDRational(0,0) info[41988] = TiffImagePlugin.IFDRational(0, 0)
out = self.tempfile('temp.tiff') out = self.tempfile('temp.tiff')
im.save(out, tiffinfo=info, compression='raw') im.save(out, tiffinfo=info, compression='raw')
@ -198,8 +199,6 @@ class TestFileTiffMetadata(PillowTestCase):
self.assertEqual(0, reloaded.tag_v2[41988][0].denominator) self.assertEqual(0, reloaded.tag_v2[41988][0].denominator)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -1,6 +1,7 @@
from helper import unittest, PillowTestCase, hopper, py3 from helper import unittest, PillowTestCase, hopper, py3
import sys import sys
class TestImageGetIm(PillowTestCase): class TestImageGetIm(PillowTestCase):
def test_sanity(self): def test_sanity(self):
@ -10,7 +11,6 @@ class TestImageGetIm(PillowTestCase):
if py3: if py3:
self.assertIn("PyCapsule", type_repr) self.assertIn("PyCapsule", type_repr)
if sys.hexversion < 0x2070000: if sys.hexversion < 0x2070000:
# py2.6 x64, windows # py2.6 x64, windows
target_types = (int, long) target_types = (int, long)

View File

@ -1,12 +1,13 @@
from helper import unittest, PillowTestCase, hopper from helper import unittest, PillowTestCase, hopper
from PIL import Image from PIL import Image
class TestImagingCoreResize(PillowTestCase): class TestImagingCoreResize(PillowTestCase):
#see https://github.com/python-pillow/Pillow/issues/1710 # see https://github.com/python-pillow/Pillow/issues/1710
def test_overflow(self): def test_overflow(self):
im = hopper('L') im = hopper('L')
xsize = 0x100000008 // 4 xsize = 0x100000008 // 4
ysize = 1000 # unimportant ysize = 1000 # unimportant
try: try:
# any resampling filter will do here # any resampling filter will do here
im.im.resize((xsize, ysize), Image.LINEAR) im.im.resize((xsize, ysize), Image.LINEAR)
@ -17,17 +18,17 @@ class TestImagingCoreResize(PillowTestCase):
def test_invalid_size(self): def test_invalid_size(self):
im = hopper() im = hopper()
im.resize((100,100)) im.resize((100, 100))
self.assertTrue(True, "Should not Crash") self.assertTrue(True, "Should not Crash")
try: try:
im.resize((-100,100)) im.resize((-100, 100))
self.fail("Resize should raise a value error on x negative size") self.fail("Resize should raise a value error on x negative size")
except ValueError: except ValueError:
self.assertTrue(True, "Should raise ValueError") self.assertTrue(True, "Should raise ValueError")
try: try:
im.resize((100,-100)) im.resize((100, -100))
self.fail("Resize should raise a value error on y negative size") self.fail("Resize should raise a value error on y negative size")
except ValueError: except ValueError:
self.assertTrue(True, "Should raise ValueError") self.assertTrue(True, "Should raise ValueError")

View File

@ -7,8 +7,8 @@ from PIL.TiffImagePlugin import IFDRational
from fractions import Fraction from fractions import Fraction
class Test_IFDRational(PillowTestCase):
class Test_IFDRational(PillowTestCase):
def _test_equal(self, num, denom, target): def _test_equal(self, num, denom, target):
@ -20,17 +20,16 @@ class Test_IFDRational(PillowTestCase):
def test_sanity(self): def test_sanity(self):
self._test_equal(1, 1, 1) self._test_equal(1, 1, 1)
self._test_equal(1, 1, Fraction(1,1)) self._test_equal(1, 1, Fraction(1, 1))
self._test_equal(2, 2, 1) self._test_equal(2, 2, 1)
self._test_equal(1.0, 1, Fraction(1,1)) self._test_equal(1.0, 1, Fraction(1, 1))
self._test_equal(Fraction(1,1), 1, Fraction(1,1)) self._test_equal(Fraction(1, 1), 1, Fraction(1, 1))
self._test_equal(IFDRational(1,1), 1, 1) self._test_equal(IFDRational(1, 1), 1, 1)
self._test_equal(1, 2, Fraction(1, 2))
self._test_equal(1, 2, Fraction(1,2)) self._test_equal(1, 2, IFDRational(1, 2))
self._test_equal(1, 2, IFDRational(1,2))
def test_nonetype(self): def test_nonetype(self):
" Fails if the _delegate function doesn't return a valid function" " Fails if the _delegate function doesn't return a valid function"
@ -45,17 +44,15 @@ class Test_IFDRational(PillowTestCase):
self.assertTrue(xres and 1) self.assertTrue(xres and 1)
self.assertTrue(xres and yres) self.assertTrue(xres and yres)
def test_ifd_rational_save(self): def test_ifd_rational_save(self):
for libtiff in (True, False): for libtiff in (True, False):
TiffImagePlugin.WRITE_LIBTIFF = libtiff TiffImagePlugin.WRITE_LIBTIFF = libtiff
im = hopper() im = hopper()
out = self.tempfile('temp.tiff') out = self.tempfile('temp.tiff')
res = IFDRational(301,1) res = IFDRational(301, 1)
im.save(out, dpi=(res,res), compression='raw') im.save(out, dpi=(res, res), compression='raw')
reloaded = Image.open(out) reloaded = Image.open(out)
self.assertEqual(float(IFDRational(301,1)), self.assertEqual(float(IFDRational(301, 1)),
float(reloaded.tag_v2[282])) float(reloaded.tag_v2[282]))