diff --git a/CHANGES.rst b/CHANGES.rst index 6838185d3..89655a630 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,8 +4,17 @@ Changelog (Pillow) 2.9.0 (Unreleased) ------------------ -- Update tiff and tk tcl 8.5 versions #1303 +- Fixed ValueError in Python 2.6 #1315 #1316 + [cgohlke, radarhere] + +- Fixed tox test script path #1308 [radarhere] + +- Added width and height properties #1304 + [radarhere] + +- Update tiff and tk tcl 8.5 versions #1303 + [radarhere, wiredfool] - Add functions to convert: Image <-> QImage; Image <-> QPixmap #1217 [radarhere, rominf] diff --git a/MANIFEST.in b/MANIFEST.in index 30e73c075..ad5bc3bed 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,14 +1,16 @@ + include *.c include *.h +include *.in include *.md include *.py -include *.sh include *.rst +include *.sh include *.txt include *.yaml +include *.yml include .coveragerc include .gitattributes -include .travis.yml include LICENSE include Makefile include tox.ini @@ -16,7 +18,6 @@ recursive-include PIL *.md recursive-include Scripts *.py recursive-include Scripts *.rst recursive-include Scripts *.sh -recursive-include Scripts README.rst recursive-include Tests *.bdf recursive-include Tests *.bin recursive-include Tests *.bmp @@ -33,11 +34,13 @@ recursive-include Tests *.html recursive-include Tests *.icc recursive-include Tests *.icns recursive-include Tests *.ico +recursive-include Tests *.im recursive-include Tests *.j2k recursive-include Tests *.jp2 recursive-include Tests *.jpg recursive-include Tests *.lut recursive-include Tests *.mpo +recursive-include Tests *.msp recursive-include Tests *.pbm recursive-include Tests *.pcf recursive-include Tests *.pcx @@ -59,8 +62,8 @@ recursive-include Tests *.tiff recursive-include Tests *.ttf recursive-include Tests *.txt recursive-include Tests *.webp +recursive-include Tests *.xbm recursive-include Tests *.xpm -recursive-include Tests *.msp recursive-include Tk *.c recursive-include Tk *.rst recursive-include depends *.rst @@ -71,9 +74,13 @@ recursive-include docs *.html recursive-include docs *.py recursive-include docs *.rst recursive-include docs *.txt -recursive-include docs BUILDME -recursive-include docs COPYING -recursive-include docs Guardfile recursive-include docs Makefile +recursive-include docs Guardfile +recursive-include docs COPYING +recursive-include docs BUILDME recursive-include libImaging *.c recursive-include libImaging *.h +recursive-include winbuild *.gitignore +recursive-include winbuild *.md +recursive-include winbuild *.opt +recursive-include winbuild *.py diff --git a/Makefile b/Makefile index 4d96c497d..e123a74c7 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html .PHONY: clean coverage doc docserve help inplace install install-req release-test sdist test upload upload-test +.DEFAULT_GOAL := release-test clean: python setup.py clean diff --git a/PIL/FliImagePlugin.py b/PIL/FliImagePlugin.py index df6a4eb8e..772140076 100644 --- a/PIL/FliImagePlugin.py +++ b/PIL/FliImagePlugin.py @@ -127,8 +127,14 @@ class FliImageFile(ImageFile.ImageFile): return if frame < self.__frame: self._seek(0) + + last_frame = self.__frame for f in range(self.__frame + 1, frame + 1): - self._seek(f) + try: + self._seek(f) + except EOFError: + self.seek(last_frame) + raise EOFError("no more images in FLI file") def _seek(self, frame): if frame == 0: diff --git a/PIL/GifImagePlugin.py b/PIL/GifImagePlugin.py index bd974b651..35fb95164 100644 --- a/PIL/GifImagePlugin.py +++ b/PIL/GifImagePlugin.py @@ -107,8 +107,14 @@ class GifImageFile(ImageFile.ImageFile): return if frame < self.__frame: self._seek(0) + + last_frame = self.__frame for f in range(self.__frame + 1, frame + 1): - self._seek(f) + try: + self._seek(f) + except EOFError: + self.seek(last_frame) + raise EOFError("no more images in GIF file") def _seek(self, frame): @@ -241,7 +247,7 @@ class GifImageFile(ImageFile.ImageFile): if not self.tile: # self.__fp = None - raise EOFError("no more images in GIF file") + raise EOFError self.mode = "L" if self.palette: diff --git a/PIL/Image.py b/PIL/Image.py index a6b08d196..3740b51c6 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -504,6 +504,14 @@ class Image(object): self.readonly = 0 self.pyaccess = None + @property + def width(self): + return self.size[0] + + @property + def height(self): + return self.size[1] + def _new(self, im): new = Image() new.im = im diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 59de84273..83bbd3f93 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -548,7 +548,7 @@ class ImageFileDirectory(collections.MutableMapping): # and doesn't match the tiff spec: 8-bit byte that # contains a 7-bit ASCII code; the last byte must be # NUL (binary zero). Also, I don't think this was well - # excersized before. + # exercised before. data = value = b"" + value.encode('ascii', 'replace') + b"\0" else: # integer data diff --git a/PIL/__init__.py b/PIL/__init__.py index 6d51a5dcb..64f8953d6 100644 --- a/PIL/__init__.py +++ b/PIL/__init__.py @@ -12,7 +12,7 @@ # ;-) VERSION = '1.1.7' # PIL version -PILLOW_VERSION = '2.9.0.dev0' # Pillow +PILLOW_VERSION = '2.9.0.dev1' # Pillow _plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', diff --git a/Tests/test_file_dcx.py b/Tests/test_file_dcx.py index 7d2ae32d8..d59a5a785 100644 --- a/Tests/test_file_dcx.py +++ b/Tests/test_file_dcx.py @@ -34,6 +34,18 @@ class TestFileDcx(PillowTestCase): im = Image.open(TEST_FILE) self.assertEqual(im.n_frames, 1) + def test_eoferror(self): + im = Image.open(TEST_FILE) + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + im.seek(n_frames) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) + def test_seek_too_far(self): # Arrange im = Image.open(TEST_FILE) diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 04c2006c9..1b95f793f 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -20,7 +20,19 @@ class TestFileFli(PillowTestCase): def test_n_frames(self): im = Image.open(test_file) - self.assertEqual(im.n_frames, 2) + self.assertEqual(im.n_frames, 1) + + def test_eoferror(self): + im = Image.open(test_file) + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + im.seek(n_frames) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) if __name__ == '__main__': diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index b15d32097..a38c360c9 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -135,8 +135,23 @@ class TestFileGif(PillowTestCase): self.assertEqual(framecount, 5) def test_n_frames(self): + im = Image.open(TEST_GIF) + self.assertEqual(im.n_frames, 1) + im = Image.open("Tests/images/iss634.gif") - self.assertEqual(im.n_frames, 43) + self.assertEqual(im.n_frames, 42) + + def test_eoferror(self): + im = Image.open(TEST_GIF) + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + im.seek(n_frames) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) def test_dispose_none(self): img = Image.open("Tests/images/dispose_none.gif") diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py index 24e00b2f0..76bf250a0 100644 --- a/Tests/test_file_im.py +++ b/Tests/test_file_im.py @@ -19,6 +19,18 @@ class TestFileIm(PillowTestCase): im = Image.open(TEST_IM) self.assertEqual(im.n_frames, 1) + def test_eoferror(self): + im = Image.open(TEST_IM) + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + im.seek(n_frames) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) + def test_roundtrip(self): out = self.tempfile('temp.im') im = hopper() diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 1a0ebc453..c5562097d 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -99,6 +99,18 @@ class TestFileMpo(PillowTestCase): im = Image.open("Tests/images/sugarshack.mpo") self.assertEqual(im.n_frames, 2) + def test_eoferror(self): + im = Image.open("Tests/images/sugarshack.mpo") + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + im.seek(n_frames) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) + def test_image_grab(self): for test_file in test_files: im = Image.open(test_file) diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index dca3601b2..ea3856fce 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -23,6 +23,19 @@ class TestImagePsd(PillowTestCase): im = Image.open(test_file) self.assertEqual(im.n_frames, 2) + def test_eoferror(self): + im = Image.open(test_file) + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + # PSD seek index starts at 1 rather than 0 + im.seek(n_frames+1) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 02a63586c..a88b49d7f 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -157,6 +157,18 @@ class TestFileTiff(PillowTestCase): im = Image.open('Tests/images/multipage.tiff') self.assertEqual(im.n_frames, 3) + def test_eoferror(self): + im = Image.open('Tests/images/multipage-lastframe.tif') + + n_frames = im.n_frames + while True: + n_frames -= 1 + try: + im.seek(n_frames) + break + except EOFError: + self.assertTrue(im.tell() < n_frames) + def test_multipage(self): # issue #862 im = Image.open('Tests/images/multipage.tiff') diff --git a/Tests/test_image.py b/Tests/test_image.py index 469045909..bd5fd3522 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -30,6 +30,15 @@ class TestImage(PillowTestCase): # self.assertRaises( # MemoryError, lambda: Image.new("L", (1000000, 1000000))) + def test_width_height(self): + im = Image.new("RGB", (1, 2)) + self.assertEqual(im.width, 1) + self.assertEqual(im.height, 2) + + im.size = (3, 4) + self.assertEqual(im.width, 3) + self.assertEqual(im.height, 4) + def test_invalid_image(self): if str is bytes: import StringIO diff --git a/Tests/test_image_toqimage.py b/Tests/test_image_toqimage.py index 38b83c023..6c79b4c6d 100644 --- a/Tests/test_image_toqimage.py +++ b/Tests/test_image_toqimage.py @@ -19,7 +19,7 @@ class TestToQImage(PillowQtTestCase, PillowTestCase): self.assertFalse(data.isNull()) # Test saving the file - tempfile = self.tempfile('temp_{}.png'.format(mode)) + tempfile = self.tempfile('temp_{0}.png'.format(mode)) data.save(tempfile) diff --git a/Tests/test_image_toqpixmap.py b/Tests/test_image_toqpixmap.py index 95db2e8f7..8fabab13d 100644 --- a/Tests/test_image_toqpixmap.py +++ b/Tests/test_image_toqpixmap.py @@ -19,7 +19,7 @@ class TestToQPixmap(PillowQPixmapTestCase, PillowTestCase): self.assertFalse(data.isNull()) # Test saving the file - tempfile = self.tempfile('temp_{}.png'.format(mode)) + tempfile = self.tempfile('temp_{0}.png'.format(mode)) data.save(tempfile) diff --git a/_imaging.c b/_imaging.c index 09345c0dd..646fedf8b 100644 --- a/_imaging.c +++ b/_imaging.c @@ -71,7 +71,7 @@ * See the README file for information on usage and redistribution. */ -#define PILLOW_VERSION "2.9.0.dev0" +#define PILLOW_VERSION "2.9.0.dev1" #include "Python.h" diff --git a/appveyor.yml b/appveyor.yml index 868f34f7e..179c329a8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,4 @@ version: 2.9.pre.{build} -shallow_clone: true clone_folder: c:\pillow init: - ECHO %PYTHON% diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 974d84a6e..ac8b6f506 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -181,6 +181,18 @@ Instances of the :py:class:`Image` class have the following attributes: :type: ``(width, height)`` +.. py:attribute:: width + + Image width, in pixels. + + :type: :py:class:`int` + +.. py:attribute:: height + + Image height, in pixels. + + :type: :py:class:`int` + .. py:attribute:: palette Colour palette table, if any. If mode is ā€œPā€, this should be an instance of diff --git a/setup.py b/setup.py index f669873d6..7e9e3a37e 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ except (ImportError, OSError): NAME = 'Pillow' -PILLOW_VERSION = '2.9.0.dev0' +PILLOW_VERSION = '2.9.0.dev1' TCL_ROOT = None JPEG_ROOT = None JPEG2K_ROOT = None diff --git a/tox.ini b/tox.ini index 80f7edef4..ebc63d85a 100644 --- a/tox.ini +++ b/tox.ini @@ -11,4 +11,4 @@ commands = {envpython} setup.py clean {envpython} setup.py build_ext --inplace {envpython} selftest.py - {envpython} Tests/run.py --installed + {envpython} test-installed.py --installed diff --git a/winbuild/build_dep.py b/winbuild/build_dep.py index 827e8d53b..09587c26c 100644 --- a/winbuild/build_dep.py +++ b/winbuild/build_dep.py @@ -93,18 +93,19 @@ endlocal """ % compiler -def cp_tk(): +def cp_tk(ver_85, ver_86): + versions = {'ver_85':ver_85, 'ver_86':ver_86} return r""" -mkdir %INCLIB%\tcl85\include\X11 -copy /Y /B %BUILD%\tcl8.5.13\generic\*.h %INCLIB%\tcl85\include\ -copy /Y /B %BUILD%\tk8.5.13\generic\*.h %INCLIB%\tcl85\include\ -copy /Y /B %BUILD%\tk8.5.13\xlib\X11\* %INCLIB%\tcl85\include\X11\ +mkdir %%INCLIB%%\tcl85\include\X11 +copy /Y /B %%BUILD%%\tcl%(ver_85)s\generic\*.h %%INCLIB%%\tcl85\include\ +copy /Y /B %%BUILD%%\tk%(ver_85)s\generic\*.h %%INCLIB%%\tcl85\include\ +copy /Y /B %%BUILD%%\tk%(ver_85)s\xlib\X11\* %%INCLIB%%\tcl85\include\X11\ -mkdir %INCLIB%\tcl86\include\X11 -copy /Y /B %BUILD%\tcl8.6.4\generic\*.h %INCLIB%\tcl86\include\ -copy /Y /B %BUILD%\tk8.6.4\generic\*.h %INCLIB%\tcl86\include\ -copy /Y /B %BUILD%\tk8.6.4\xlib\X11\* %INCLIB%\tcl86\include\X11\ -""" +mkdir %%INCLIB%%\tcl86\include\X11 +copy /Y /B %%BUILD%%\tcl%(ver_86)s\generic\*.h %%INCLIB%%\tcl86\include\ +copy /Y /B %%BUILD%%\tk%(ver_86)s\generic\*.h %%INCLIB%%\tcl86\include\ +copy /Y /B %%BUILD%%\tk%(ver_86)s\xlib\X11\* %%INCLIB%%\tcl86\include\X11\ +""" % versions def header(): @@ -307,7 +308,7 @@ def add_compiler(compiler): mkdirs() fetch_libs() # extract_binlib() -script = [header(), cp_tk()] +script = [header(), cp_tk(libs['tk-8.5']['version'],libs['tk-8.6']['version'] )] if 'PYTHON' in os.environ: diff --git a/winbuild/config.py b/winbuild/config.py index 6846669bf..d3d2f97d7 100644 --- a/winbuild/config.py +++ b/winbuild/config.py @@ -24,7 +24,7 @@ libs = { }, 'tiff': { 'url': 'ftp://ftp.remotesensing.org/pub/libtiff/tiff-4.0.4.zip', - 'hash': 'md5:8f538a34156188f9a8dcddb679c65d1e', # not found - generated by wiredfool + 'hash': 'md5:8f538a34156188f9a8dcddb679c65d1e', 'dir': 'tiff-4.0.4', }, 'freetype': { @@ -46,6 +46,7 @@ libs = { 'url': SF_MIRROR+'/project/tcl/Tcl/8.5.18/tk8518-src.zip', 'hash': 'sha1:273f55148777413774aa722ecad25cabda1e31ae', 'dir': '', + 'version':'8.5.18', }, 'tcl-8.6': { 'url': SF_MIRROR+'/project/tcl/Tcl/8.6.4/tcl864-src.zip', @@ -56,6 +57,7 @@ libs = { 'url': SF_MIRROR+'/project/tcl/Tcl/8.6.4/tk864-src.zip', 'hash': 'md5:111d45061a69e7f5250b6ec8ca7c4f35', 'dir': '', + 'version':'8.6.4', }, 'webp': { 'url': 'http://downloads.webmproject.org/releases/webp/libwebp-0.4.3.tar.gz',