mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-10 07:14:46 +03:00
Merge branch 'master' into tiff_metadata_encoding_fix
Resolved conflict in PIL/TiffImagePlugin.py
This commit is contained in:
commit
e06c93c737
|
@ -1,2 +1,3 @@
|
||||||
strictness: medium
|
strictness: medium
|
||||||
test-warnings: yes
|
test-warnings: yes
|
||||||
|
max-line-length: 80
|
||||||
|
|
|
@ -20,6 +20,7 @@ install:
|
||||||
- "travis_retry sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick"
|
- "travis_retry sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick"
|
||||||
- "travis_retry pip install cffi"
|
- "travis_retry pip install cffi"
|
||||||
- "travis_retry pip install coverage nose"
|
- "travis_retry pip install coverage nose"
|
||||||
|
- "travis_retry pip install check-manifest"
|
||||||
# Pyroma tests sometimes hang on PyPy; skip for PyPy
|
# Pyroma tests sometimes hang on PyPy; skip for PyPy
|
||||||
- if [ $TRAVIS_PYTHON_VERSION != "pypy" ]; then travis_retry pip install pyroma; fi
|
- if [ $TRAVIS_PYTHON_VERSION != "pypy" ]; then travis_retry pip install pyroma; fi
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ script:
|
||||||
|
|
||||||
- coverage run --append --include=PIL/* selftest.py
|
- coverage run --append --include=PIL/* selftest.py
|
||||||
- coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py
|
- coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py
|
||||||
|
- check-manifest --ignore "depends/*"
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
# gather the coverage data
|
# gather the coverage data
|
||||||
|
|
33
CHANGES.rst
33
CHANGES.rst
|
@ -1,8 +1,39 @@
|
||||||
Changelog (Pillow)
|
Changelog (Pillow)
|
||||||
==================
|
==================
|
||||||
|
|
||||||
2.9.0 (Unreleased)
|
3.0.0 (Unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Treat MPO with unknown header as base JPEG file #1350
|
||||||
|
[hugovk, radarhere]
|
||||||
|
|
||||||
|
- Added various tests #1330, #1344
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- More ImageFont tests #1327
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Use logging instead of print #1207
|
||||||
|
[anntzer]
|
||||||
|
|
||||||
|
2.9.0 (2015-07-01)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- Added test for GimpPaletteFile #1324
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- 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
|
- Add functions to convert: Image <-> QImage; Image <-> QPixmap #1217
|
||||||
[radarhere, rominf]
|
[radarhere, rominf]
|
||||||
|
|
||||||
|
|
22
MANIFEST.in
22
MANIFEST.in
|
@ -1,14 +1,16 @@
|
||||||
|
|
||||||
include *.c
|
include *.c
|
||||||
include *.h
|
include *.h
|
||||||
|
include *.in
|
||||||
include *.md
|
include *.md
|
||||||
include *.py
|
include *.py
|
||||||
include *.sh
|
|
||||||
include *.rst
|
include *.rst
|
||||||
|
include *.sh
|
||||||
include *.txt
|
include *.txt
|
||||||
include *.yaml
|
include *.yaml
|
||||||
|
include *.yml
|
||||||
include .coveragerc
|
include .coveragerc
|
||||||
include .gitattributes
|
include .gitattributes
|
||||||
include .travis.yml
|
|
||||||
include LICENSE
|
include LICENSE
|
||||||
include Makefile
|
include Makefile
|
||||||
include tox.ini
|
include tox.ini
|
||||||
|
@ -16,7 +18,6 @@ recursive-include PIL *.md
|
||||||
recursive-include Scripts *.py
|
recursive-include Scripts *.py
|
||||||
recursive-include Scripts *.rst
|
recursive-include Scripts *.rst
|
||||||
recursive-include Scripts *.sh
|
recursive-include Scripts *.sh
|
||||||
recursive-include Scripts README.rst
|
|
||||||
recursive-include Tests *.bdf
|
recursive-include Tests *.bdf
|
||||||
recursive-include Tests *.bin
|
recursive-include Tests *.bin
|
||||||
recursive-include Tests *.bmp
|
recursive-include Tests *.bmp
|
||||||
|
@ -28,16 +29,19 @@ recursive-include Tests *.eps
|
||||||
recursive-include Tests *.fli
|
recursive-include Tests *.fli
|
||||||
recursive-include Tests *.ggr
|
recursive-include Tests *.ggr
|
||||||
recursive-include Tests *.gif
|
recursive-include Tests *.gif
|
||||||
|
recursive-include Tests *.gpl
|
||||||
recursive-include Tests *.gnuplot
|
recursive-include Tests *.gnuplot
|
||||||
recursive-include Tests *.html
|
recursive-include Tests *.html
|
||||||
recursive-include Tests *.icc
|
recursive-include Tests *.icc
|
||||||
recursive-include Tests *.icns
|
recursive-include Tests *.icns
|
||||||
recursive-include Tests *.ico
|
recursive-include Tests *.ico
|
||||||
|
recursive-include Tests *.im
|
||||||
recursive-include Tests *.j2k
|
recursive-include Tests *.j2k
|
||||||
recursive-include Tests *.jp2
|
recursive-include Tests *.jp2
|
||||||
recursive-include Tests *.jpg
|
recursive-include Tests *.jpg
|
||||||
recursive-include Tests *.lut
|
recursive-include Tests *.lut
|
||||||
recursive-include Tests *.mpo
|
recursive-include Tests *.mpo
|
||||||
|
recursive-include Tests *.msp
|
||||||
recursive-include Tests *.pbm
|
recursive-include Tests *.pbm
|
||||||
recursive-include Tests *.pcf
|
recursive-include Tests *.pcf
|
||||||
recursive-include Tests *.pcx
|
recursive-include Tests *.pcx
|
||||||
|
@ -59,8 +63,8 @@ recursive-include Tests *.tiff
|
||||||
recursive-include Tests *.ttf
|
recursive-include Tests *.ttf
|
||||||
recursive-include Tests *.txt
|
recursive-include Tests *.txt
|
||||||
recursive-include Tests *.webp
|
recursive-include Tests *.webp
|
||||||
|
recursive-include Tests *.xbm
|
||||||
recursive-include Tests *.xpm
|
recursive-include Tests *.xpm
|
||||||
recursive-include Tests *.msp
|
|
||||||
recursive-include Tk *.c
|
recursive-include Tk *.c
|
||||||
recursive-include Tk *.rst
|
recursive-include Tk *.rst
|
||||||
recursive-include depends *.rst
|
recursive-include depends *.rst
|
||||||
|
@ -71,9 +75,13 @@ recursive-include docs *.html
|
||||||
recursive-include docs *.py
|
recursive-include docs *.py
|
||||||
recursive-include docs *.rst
|
recursive-include docs *.rst
|
||||||
recursive-include docs *.txt
|
recursive-include docs *.txt
|
||||||
recursive-include docs BUILDME
|
|
||||||
recursive-include docs COPYING
|
|
||||||
recursive-include docs Guardfile
|
|
||||||
recursive-include docs Makefile
|
recursive-include docs Makefile
|
||||||
|
recursive-include docs Guardfile
|
||||||
|
recursive-include docs COPYING
|
||||||
|
recursive-include docs BUILDME
|
||||||
recursive-include libImaging *.c
|
recursive-include libImaging *.c
|
||||||
recursive-include libImaging *.h
|
recursive-include libImaging *.h
|
||||||
|
recursive-include winbuild *.gitignore
|
||||||
|
recursive-include winbuild *.md
|
||||||
|
recursive-include winbuild *.opt
|
||||||
|
recursive-include winbuild *.py
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -1,5 +1,6 @@
|
||||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
# 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
|
.PHONY: clean coverage doc docserve help inplace install install-req release-test sdist test upload upload-test
|
||||||
|
.DEFAULT_GOAL := release-test
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
python setup.py clean
|
python setup.py clean
|
||||||
|
|
|
@ -103,7 +103,9 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28]))
|
file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28]))
|
||||||
file_info['colors'] = i32(header_data[28:32])
|
file_info['colors'] = i32(header_data[28:32])
|
||||||
file_info['palette_padding'] = 4
|
file_info['palette_padding'] = 4
|
||||||
self.info["dpi"] = tuple(map(lambda x: math.ceil(x / 39.3701), file_info['pixels_per_meter']))
|
self.info["dpi"] = tuple(
|
||||||
|
map(lambda x: int(math.ceil(x / 39.3701)),
|
||||||
|
file_info['pixels_per_meter']))
|
||||||
if file_info['compression'] == self.BITFIELDS:
|
if file_info['compression'] == self.BITFIELDS:
|
||||||
if len(header_data) >= 52:
|
if len(header_data) >= 52:
|
||||||
for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']):
|
for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']):
|
||||||
|
|
|
@ -66,6 +66,10 @@ class DcxImageFile(PcxImageFile):
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
return len(self._offset)
|
return len(self._offset)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
return len(self._offset) > 1
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
if frame >= len(self._offset):
|
if frame >= len(self._offset):
|
||||||
raise EOFError("attempt to seek outside DCX directory")
|
raise EOFError("attempt to seek outside DCX directory")
|
||||||
|
|
|
@ -90,6 +90,7 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
self.__fp = self.fp
|
self.__fp = self.fp
|
||||||
self.__rewind = self.fp.tell()
|
self.__rewind = self.fp.tell()
|
||||||
self._n_frames = None
|
self._n_frames = None
|
||||||
|
self._is_animated = None
|
||||||
self.seek(0)
|
self.seek(0)
|
||||||
|
|
||||||
def _palette(self, palette, shift):
|
def _palette(self, palette, shift):
|
||||||
|
@ -122,13 +123,33 @@ class FliImageFile(ImageFile.ImageFile):
|
||||||
self.seek(current)
|
self.seek(current)
|
||||||
return self._n_frames
|
return self._n_frames
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
if self._is_animated is None:
|
||||||
|
current = self.tell()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.seek(1)
|
||||||
|
self._is_animated = True
|
||||||
|
except EOFError:
|
||||||
|
self._is_animated = False
|
||||||
|
|
||||||
|
self.seek(current)
|
||||||
|
return self._is_animated
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
if frame == self.__frame:
|
if frame == self.__frame:
|
||||||
return
|
return
|
||||||
if frame < self.__frame:
|
if frame < self.__frame:
|
||||||
self._seek(0)
|
self._seek(0)
|
||||||
|
|
||||||
|
last_frame = self.__frame
|
||||||
for f in range(self.__frame + 1, frame + 1):
|
for f in range(self.__frame + 1, frame + 1):
|
||||||
|
try:
|
||||||
self._seek(f)
|
self._seek(f)
|
||||||
|
except EOFError:
|
||||||
|
self.seek(last_frame)
|
||||||
|
raise EOFError("no more images in FLI file")
|
||||||
|
|
||||||
def _seek(self, frame):
|
def _seek(self, frame):
|
||||||
if frame == 0:
|
if frame == 0:
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
from PIL import Image, ImageFile, ImagePalette, ImageChops, ImageSequence, _binary
|
||||||
|
|
||||||
__version__ = "0.9"
|
__version__ = "0.9"
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
self.__fp = self.fp # FIXME: hack
|
self.__fp = self.fp # FIXME: hack
|
||||||
self.__rewind = self.fp.tell()
|
self.__rewind = self.fp.tell()
|
||||||
self._n_frames = None
|
self._n_frames = None
|
||||||
|
self._is_animated = None
|
||||||
self._seek(0) # get ready to read first frame
|
self._seek(0) # get ready to read first frame
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -102,13 +103,33 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
self.seek(current)
|
self.seek(current)
|
||||||
return self._n_frames
|
return self._n_frames
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
if self._is_animated is None:
|
||||||
|
current = self.tell()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.seek(1)
|
||||||
|
self._is_animated = True
|
||||||
|
except EOFError:
|
||||||
|
self._is_animated = False
|
||||||
|
|
||||||
|
self.seek(current)
|
||||||
|
return self._is_animated
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
if frame == self.__frame:
|
if frame == self.__frame:
|
||||||
return
|
return
|
||||||
if frame < self.__frame:
|
if frame < self.__frame:
|
||||||
self._seek(0)
|
self._seek(0)
|
||||||
|
|
||||||
|
last_frame = self.__frame
|
||||||
for f in range(self.__frame + 1, frame + 1):
|
for f in range(self.__frame + 1, frame + 1):
|
||||||
|
try:
|
||||||
self._seek(f)
|
self._seek(f)
|
||||||
|
except EOFError:
|
||||||
|
self.seek(last_frame)
|
||||||
|
raise EOFError("no more images in GIF file")
|
||||||
|
|
||||||
def _seek(self, frame):
|
def _seek(self, frame):
|
||||||
|
|
||||||
|
@ -241,7 +262,7 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
if not self.tile:
|
if not self.tile:
|
||||||
# self.__fp = None
|
# self.__fp = None
|
||||||
raise EOFError("no more images in GIF file")
|
raise EOFError
|
||||||
|
|
||||||
self.mode = "L"
|
self.mode = "L"
|
||||||
if self.palette:
|
if self.palette:
|
||||||
|
@ -279,7 +300,22 @@ RAWMODE = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _convert_mode(im):
|
||||||
|
# convert on the fly (EXPERIMENTAL -- I'm not sure PIL
|
||||||
|
# should automatically convert images on save...)
|
||||||
|
if Image.getmodebase(im.mode) == "RGB":
|
||||||
|
palette_size = 256
|
||||||
|
if im.palette:
|
||||||
|
palette_size = len(im.palette.getdata()[1]) // 3
|
||||||
|
return im.convert("P", palette=1, colors=palette_size)
|
||||||
|
return im.convert("L")
|
||||||
|
|
||||||
|
|
||||||
|
def _save_all(im, fp, filename):
|
||||||
|
_save(im, fp, filename, save_all=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _save(im, fp, filename, save_all=False):
|
||||||
|
|
||||||
if _imaging_gif:
|
if _imaging_gif:
|
||||||
# call external driver
|
# call external driver
|
||||||
|
@ -292,15 +328,7 @@ def _save(im, fp, filename):
|
||||||
if im.mode in RAWMODE:
|
if im.mode in RAWMODE:
|
||||||
im_out = im.copy()
|
im_out = im.copy()
|
||||||
else:
|
else:
|
||||||
# convert on the fly (EXPERIMENTAL -- I'm not sure PIL
|
im_out = _convert_mode(im)
|
||||||
# should automatically convert images on save...)
|
|
||||||
if Image.getmodebase(im.mode) == "RGB":
|
|
||||||
palette_size = 256
|
|
||||||
if im.palette:
|
|
||||||
palette_size = len(im.palette.getdata()[1]) // 3
|
|
||||||
im_out = im.convert("P", palette=1, colors=palette_size)
|
|
||||||
else:
|
|
||||||
im_out = im.convert("L")
|
|
||||||
|
|
||||||
# header
|
# header
|
||||||
try:
|
try:
|
||||||
|
@ -309,7 +337,33 @@ def _save(im, fp, filename):
|
||||||
palette = None
|
palette = None
|
||||||
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
||||||
|
|
||||||
header, used_palette_colors = getheader(im_out, palette, im.encoderinfo)
|
if save_all:
|
||||||
|
previous = None
|
||||||
|
|
||||||
|
for im_frame in ImageSequence.Iterator(im):
|
||||||
|
im_frame = _convert_mode(im_frame)
|
||||||
|
|
||||||
|
# To specify duration, add the time in milliseconds to getdata(),
|
||||||
|
# e.g. getdata(im_frame, duration=1000)
|
||||||
|
if not previous:
|
||||||
|
# global header
|
||||||
|
for s in getheader(im_frame, palette, im.encoderinfo)[0] + getdata(im_frame):
|
||||||
|
fp.write(s)
|
||||||
|
else:
|
||||||
|
# delta frame
|
||||||
|
delta = ImageChops.subtract_modulo(im_frame, previous)
|
||||||
|
bbox = delta.getbbox()
|
||||||
|
|
||||||
|
if bbox:
|
||||||
|
# compress difference
|
||||||
|
for s in getdata(im_frame.crop(bbox), offset=bbox[:2]):
|
||||||
|
fp.write(s)
|
||||||
|
else:
|
||||||
|
# FIXME: what should we do in this case?
|
||||||
|
pass
|
||||||
|
previous = im_frame.copy()
|
||||||
|
else:
|
||||||
|
header = getheader(im_out, palette, im.encoderinfo)[0]
|
||||||
for s in header:
|
for s in header:
|
||||||
fp.write(s)
|
fp.write(s)
|
||||||
|
|
||||||
|
@ -319,7 +373,7 @@ def _save(im, fp, filename):
|
||||||
flags = flags | 64
|
flags = flags | 64
|
||||||
|
|
||||||
# local image header
|
# local image header
|
||||||
get_local_header(fp, im, (0, 0), flags)
|
_get_local_header(fp, im, (0, 0), flags)
|
||||||
|
|
||||||
im_out.encoderconfig = (8, get_interlace(im))
|
im_out.encoderconfig = (8, get_interlace(im))
|
||||||
ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
|
ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
|
||||||
|
@ -348,7 +402,7 @@ def get_interlace(im):
|
||||||
return interlace
|
return interlace
|
||||||
|
|
||||||
|
|
||||||
def get_local_header(fp, im, offset, flags):
|
def _get_local_header(fp, im, offset, flags):
|
||||||
transparent_color_exists = False
|
transparent_color_exists = False
|
||||||
try:
|
try:
|
||||||
transparency = im.encoderinfo["transparency"]
|
transparency = im.encoderinfo["transparency"]
|
||||||
|
@ -571,7 +625,7 @@ def getdata(im, offset=(0, 0), **params):
|
||||||
im.encoderinfo = params
|
im.encoderinfo = params
|
||||||
|
|
||||||
# local image header
|
# local image header
|
||||||
get_local_header(fp, im, offset, 0)
|
_get_local_header(fp, im, offset, 0)
|
||||||
|
|
||||||
ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])
|
ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])
|
||||||
|
|
||||||
|
@ -588,6 +642,7 @@ def getdata(im, offset=(0, 0), **params):
|
||||||
|
|
||||||
Image.register_open(GifImageFile.format, GifImageFile, _accept)
|
Image.register_open(GifImageFile.format, GifImageFile, _accept)
|
||||||
Image.register_save(GifImageFile.format, _save)
|
Image.register_save(GifImageFile.format, _save)
|
||||||
|
Image.register_save_all(GifImageFile.format, _save_all)
|
||||||
Image.register_extension(GifImageFile.format, ".gif")
|
Image.register_extension(GifImageFile.format, ".gif")
|
||||||
Image.register_mime(GifImageFile.format, "image/gif")
|
Image.register_mime(GifImageFile.format, "image/gif")
|
||||||
|
|
||||||
|
|
|
@ -264,6 +264,10 @@ class ImImageFile(ImageFile.ImageFile):
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
return self.info[FRAMES]
|
return self.info[FRAMES]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
return self.info[FRAMES] > 1
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
|
|
||||||
if frame < 0 or frame >= self.info[FRAMES]:
|
if frame < 0 or frame >= self.info[FRAMES]:
|
||||||
|
|
71
PIL/Image.py
71
PIL/Image.py
|
@ -28,8 +28,11 @@ from __future__ import print_function
|
||||||
|
|
||||||
from PIL import VERSION, PILLOW_VERSION, _plugins
|
from PIL import VERSION, PILLOW_VERSION, _plugins
|
||||||
|
|
||||||
|
import logging
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DecompressionBombWarning(RuntimeWarning):
|
class DecompressionBombWarning(RuntimeWarning):
|
||||||
pass
|
pass
|
||||||
|
@ -138,11 +141,6 @@ def isImageType(t):
|
||||||
"""
|
"""
|
||||||
return hasattr(t, "im")
|
return hasattr(t, "im")
|
||||||
|
|
||||||
#
|
|
||||||
# Debug level
|
|
||||||
|
|
||||||
DEBUG = 0
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Constants (also defined in _imagingmodule.c!)
|
# Constants (also defined in _imagingmodule.c!)
|
||||||
|
|
||||||
|
@ -204,6 +202,7 @@ ID = []
|
||||||
OPEN = {}
|
OPEN = {}
|
||||||
MIME = {}
|
MIME = {}
|
||||||
SAVE = {}
|
SAVE = {}
|
||||||
|
SAVE_ALL = {}
|
||||||
EXTENSION = {}
|
EXTENSION = {}
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -386,13 +385,10 @@ def init():
|
||||||
|
|
||||||
for plugin in _plugins:
|
for plugin in _plugins:
|
||||||
try:
|
try:
|
||||||
if DEBUG:
|
logger.debug("Importing %s", plugin)
|
||||||
print("Importing %s" % plugin)
|
|
||||||
__import__("PIL.%s" % plugin, globals(), locals(), [])
|
__import__("PIL.%s" % plugin, globals(), locals(), [])
|
||||||
except ImportError:
|
except ImportError as e:
|
||||||
if DEBUG:
|
logger.debug("Image: failed to import %s: %s", plugin, e)
|
||||||
print("Image: failed to import", end=' ')
|
|
||||||
print(plugin, ":", sys.exc_info()[1])
|
|
||||||
|
|
||||||
if OPEN or SAVE:
|
if OPEN or SAVE:
|
||||||
_initialized = 2
|
_initialized = 2
|
||||||
|
@ -504,6 +500,14 @@ class Image(object):
|
||||||
self.readonly = 0
|
self.readonly = 0
|
||||||
self.pyaccess = None
|
self.pyaccess = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
return self.size[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
return self.size[1]
|
||||||
|
|
||||||
def _new(self, im):
|
def _new(self, im):
|
||||||
new = Image()
|
new = Image()
|
||||||
new.im = im
|
new.im = im
|
||||||
|
@ -546,8 +550,7 @@ class Image(object):
|
||||||
try:
|
try:
|
||||||
self.fp.close()
|
self.fp.close()
|
||||||
except Exception as msg:
|
except Exception as msg:
|
||||||
if DEBUG:
|
logger.debug("Error closing: %s" % msg)
|
||||||
print("Error closing: %s" % msg)
|
|
||||||
|
|
||||||
# Instead of simply setting to None, we're setting up a
|
# Instead of simply setting to None, we're setting up a
|
||||||
# deferred error that will better explain that the core image
|
# deferred error that will better explain that the core image
|
||||||
|
@ -1661,6 +1664,10 @@ class Image(object):
|
||||||
# may mutate self!
|
# may mutate self!
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
|
save_all = False
|
||||||
|
if 'save_all' in params:
|
||||||
|
save_all = params['save_all']
|
||||||
|
del params['save_all']
|
||||||
self.encoderinfo = params
|
self.encoderinfo = params
|
||||||
self.encoderconfig = ()
|
self.encoderconfig = ()
|
||||||
|
|
||||||
|
@ -1669,20 +1676,16 @@ class Image(object):
|
||||||
ext = os.path.splitext(filename)[1].lower()
|
ext = os.path.splitext(filename)[1].lower()
|
||||||
|
|
||||||
if not format:
|
if not format:
|
||||||
try:
|
if ext not in EXTENSION:
|
||||||
format = EXTENSION[ext]
|
|
||||||
except KeyError:
|
|
||||||
init()
|
init()
|
||||||
try:
|
|
||||||
format = EXTENSION[ext]
|
format = EXTENSION[ext]
|
||||||
except KeyError:
|
|
||||||
raise KeyError(ext) # unknown extension
|
|
||||||
|
|
||||||
try:
|
if format.upper() not in SAVE:
|
||||||
save_handler = SAVE[format.upper()]
|
|
||||||
except KeyError:
|
|
||||||
init()
|
init()
|
||||||
save_handler = SAVE[format.upper()] # unknown format
|
if save_all:
|
||||||
|
save_handler = SAVE_ALL[format.upper()]
|
||||||
|
else:
|
||||||
|
save_handler = SAVE[format.upper()]
|
||||||
|
|
||||||
if isPath(fp):
|
if isPath(fp):
|
||||||
fp = builtins.open(fp, "wb")
|
fp = builtins.open(fp, "wb")
|
||||||
|
@ -2262,7 +2265,7 @@ def open(fp, mode="r"):
|
||||||
:py:meth:`~PIL.Image.Image.load` method). See
|
:py:meth:`~PIL.Image.Image.load` method). See
|
||||||
:py:func:`~PIL.Image.new`.
|
:py:func:`~PIL.Image.new`.
|
||||||
|
|
||||||
:param file: A filename (string) or a file object. The file object
|
:param fp: A filename (string) or a file object. The file object
|
||||||
must implement :py:meth:`~file.read`, :py:meth:`~file.seek`, and
|
must implement :py:meth:`~file.read`, :py:meth:`~file.seek`, and
|
||||||
:py:meth:`~file.tell` methods, and be opened in binary mode.
|
:py:meth:`~file.tell` methods, and be opened in binary mode.
|
||||||
:param mode: The mode. If given, this argument must be "r".
|
:param mode: The mode. If given, this argument must be "r".
|
||||||
|
@ -2298,9 +2301,7 @@ def open(fp, mode="r"):
|
||||||
_decompression_bomb_check(im.size)
|
_decompression_bomb_check(im.size)
|
||||||
return im
|
return im
|
||||||
except (SyntaxError, IndexError, TypeError, struct.error):
|
except (SyntaxError, IndexError, TypeError, struct.error):
|
||||||
# import traceback
|
logger.debug("", exc_info=True)
|
||||||
# traceback.print_exc()
|
|
||||||
pass
|
|
||||||
|
|
||||||
if init():
|
if init():
|
||||||
|
|
||||||
|
@ -2313,9 +2314,7 @@ def open(fp, mode="r"):
|
||||||
_decompression_bomb_check(im.size)
|
_decompression_bomb_check(im.size)
|
||||||
return im
|
return im
|
||||||
except (SyntaxError, IndexError, TypeError, struct.error):
|
except (SyntaxError, IndexError, TypeError, struct.error):
|
||||||
# import traceback
|
logger.debug("", exc_info=True)
|
||||||
# traceback.print_exc()
|
|
||||||
pass
|
|
||||||
|
|
||||||
raise IOError("cannot identify image file %r"
|
raise IOError("cannot identify image file %r"
|
||||||
% (filename if filename else fp))
|
% (filename if filename else fp))
|
||||||
|
@ -2461,6 +2460,18 @@ def register_save(id, driver):
|
||||||
SAVE[id.upper()] = driver
|
SAVE[id.upper()] = driver
|
||||||
|
|
||||||
|
|
||||||
|
def register_save_all(id, driver):
|
||||||
|
"""
|
||||||
|
Registers an image function to save all the frames
|
||||||
|
of a multiframe format. This function should not be
|
||||||
|
used in application code.
|
||||||
|
|
||||||
|
:param id: An image format identifier.
|
||||||
|
:param driver: A function to save images in this format.
|
||||||
|
"""
|
||||||
|
SAVE_ALL[id.upper()] = driver
|
||||||
|
|
||||||
|
|
||||||
def register_extension(id, extension):
|
def register_extension(id, extension):
|
||||||
"""
|
"""
|
||||||
Registers an image extension. This function should not be
|
Registers an image extension. This function should not be
|
||||||
|
|
|
@ -30,10 +30,13 @@
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL._util import isPath
|
from PIL._util import isPath
|
||||||
import io
|
import io
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAXBLOCK = 65536
|
MAXBLOCK = 65536
|
||||||
|
|
||||||
SAFEBLOCK = 1024*1024
|
SAFEBLOCK = 1024*1024
|
||||||
|
@ -95,21 +98,11 @@ class ImageFile(Image.Image):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._open()
|
self._open()
|
||||||
except IndexError as v: # end of data
|
except (IndexError, # end of data
|
||||||
if Image.DEBUG > 1:
|
TypeError, # end of data (ord)
|
||||||
traceback.print_exc()
|
KeyError, # unsupported mode
|
||||||
raise SyntaxError(v)
|
EOFError) as v: # got header but not the first frame
|
||||||
except TypeError as v: # end of data (ord)
|
logger.exception("%s")
|
||||||
if Image.DEBUG > 1:
|
|
||||||
traceback.print_exc()
|
|
||||||
raise SyntaxError(v)
|
|
||||||
except KeyError as v: # unsupported mode
|
|
||||||
if Image.DEBUG > 1:
|
|
||||||
traceback.print_exc()
|
|
||||||
raise SyntaxError(v)
|
|
||||||
except EOFError as v: # got header but not the first frame
|
|
||||||
if Image.DEBUG > 1:
|
|
||||||
traceback.print_exc()
|
|
||||||
raise SyntaxError(v)
|
raise SyntaxError(v)
|
||||||
|
|
||||||
if not self.mode or self.size[0] <= 0:
|
if not self.mode or self.size[0] <= 0:
|
||||||
|
|
|
@ -37,6 +37,7 @@ __version__ = "0.6"
|
||||||
import array
|
import array
|
||||||
import struct
|
import struct
|
||||||
import io
|
import io
|
||||||
|
import warnings
|
||||||
from struct import unpack
|
from struct import unpack
|
||||||
from PIL import Image, ImageFile, TiffImagePlugin, _binary
|
from PIL import Image, ImageFile, TiffImagePlugin, _binary
|
||||||
from PIL.JpegPresets import presets
|
from PIL.JpegPresets import presets
|
||||||
|
@ -713,8 +714,8 @@ def _save_cjpeg(im, fp, filename):
|
||||||
# Factory for making JPEG and MPO instances
|
# Factory for making JPEG and MPO instances
|
||||||
def jpeg_factory(fp=None, filename=None):
|
def jpeg_factory(fp=None, filename=None):
|
||||||
im = JpegImageFile(fp, filename)
|
im = JpegImageFile(fp, filename)
|
||||||
mpheader = im._getmp()
|
|
||||||
try:
|
try:
|
||||||
|
mpheader = im._getmp()
|
||||||
if mpheader[45057] > 1:
|
if mpheader[45057] > 1:
|
||||||
# It's actually an MPO
|
# It's actually an MPO
|
||||||
from .MpoImagePlugin import MpoImageFile
|
from .MpoImagePlugin import MpoImageFile
|
||||||
|
@ -722,6 +723,10 @@ def jpeg_factory(fp=None, filename=None):
|
||||||
except (TypeError, IndexError):
|
except (TypeError, IndexError):
|
||||||
# It is really a JPEG
|
# It is really a JPEG
|
||||||
pass
|
pass
|
||||||
|
except SyntaxError:
|
||||||
|
warnings.warn("Image appears to be a malformed MPO file, it will be "
|
||||||
|
"interpreted as a base JPEG file")
|
||||||
|
pass
|
||||||
return im
|
return im
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,10 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
return len(self.images)
|
return len(self.images)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
return len(self.images) > 1
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -66,6 +66,10 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
return self.__framecount
|
return self.__framecount
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
return self.__framecount > 1
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
if frame < 0 or frame >= self.__framecount:
|
if frame < 0 or frame >= self.__framecount:
|
||||||
raise EOFError("no more images in MPO file")
|
raise EOFError("no more images in MPO file")
|
||||||
|
|
|
@ -27,8 +27,11 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import logging
|
||||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
i8 = _binary.i8
|
i8 = _binary.i8
|
||||||
i16 = _binary.i16le
|
i16 = _binary.i16le
|
||||||
o8 = _binary.o8
|
o8 = _binary.o8
|
||||||
|
@ -59,17 +62,15 @@ class PcxImageFile(ImageFile.ImageFile):
|
||||||
bbox = i16(s, 4), i16(s, 6), i16(s, 8)+1, i16(s, 10)+1
|
bbox = i16(s, 4), i16(s, 6), i16(s, 8)+1, i16(s, 10)+1
|
||||||
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
|
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
|
||||||
raise SyntaxError("bad PCX image size")
|
raise SyntaxError("bad PCX image size")
|
||||||
if Image.DEBUG:
|
logger.debug("BBox: %s %s %s %s", *bbox)
|
||||||
print("BBox: %s %s %s %s" % bbox)
|
|
||||||
|
|
||||||
# format
|
# format
|
||||||
version = i8(s[1])
|
version = i8(s[1])
|
||||||
bits = i8(s[3])
|
bits = i8(s[3])
|
||||||
planes = i8(s[65])
|
planes = i8(s[65])
|
||||||
stride = i16(s, 66)
|
stride = i16(s, 66)
|
||||||
if Image.DEBUG:
|
logger.debug("PCX version %s, bits %s, planes %s, stride %s",
|
||||||
print("PCX version %s, bits %s, planes %s, stride %s" %
|
version, bits, planes, stride)
|
||||||
(version, bits, planes, stride))
|
|
||||||
|
|
||||||
self.info["dpi"] = i16(s, 12), i16(s, 14)
|
self.info["dpi"] = i16(s, 12), i16(s, 14)
|
||||||
|
|
||||||
|
@ -107,8 +108,7 @@ class PcxImageFile(ImageFile.ImageFile):
|
||||||
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
|
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
|
||||||
|
|
||||||
bbox = (0, 0) + self.size
|
bbox = (0, 0) + self.size
|
||||||
if Image.DEBUG:
|
logger.debug("size: %sx%s", *self.size)
|
||||||
print("size: %sx%s" % self.size)
|
|
||||||
|
|
||||||
self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
|
self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
|
||||||
|
|
||||||
|
@ -144,9 +144,8 @@ def _save(im, fp, filename, check=0):
|
||||||
# Ideally it should be passed in in the state, but the bytes value
|
# Ideally it should be passed in in the state, but the bytes value
|
||||||
# gets overwritten.
|
# gets overwritten.
|
||||||
|
|
||||||
if Image.DEBUG:
|
logger.debug("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d",
|
||||||
print("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % (
|
im.size[0], bits, stride)
|
||||||
im.size[0], bits, stride))
|
|
||||||
|
|
||||||
# under windows, we could determine the current screen size with
|
# under windows, we could determine the current screen size with
|
||||||
# "Image.core.display_mode()[1]", but I think that's overkill...
|
# "Image.core.display_mode()[1]", but I think that's overkill...
|
||||||
|
|
|
@ -35,10 +35,13 @@ from __future__ import print_function
|
||||||
|
|
||||||
__version__ = "0.9"
|
__version__ = "0.9"
|
||||||
|
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import zlib
|
||||||
|
|
||||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||||
import zlib
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
i8 = _binary.i8
|
i8 = _binary.i8
|
||||||
i16 = _binary.i16be
|
i16 = _binary.i16be
|
||||||
|
@ -129,8 +132,7 @@ class ChunkStream(object):
|
||||||
def call(self, cid, pos, length):
|
def call(self, cid, pos, length):
|
||||||
"Call the appropriate chunk handler"
|
"Call the appropriate chunk handler"
|
||||||
|
|
||||||
if Image.DEBUG:
|
logger.debug("STREAM %s %s %s", cid, pos, length)
|
||||||
print("STREAM", cid, pos, length)
|
|
||||||
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, length)
|
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, length)
|
||||||
|
|
||||||
def crc(self, cid, data):
|
def crc(self, cid, data):
|
||||||
|
@ -293,9 +295,8 @@ class PngStream(ChunkStream):
|
||||||
# Compression method 1 byte (0)
|
# Compression method 1 byte (0)
|
||||||
# Compressed profile n bytes (zlib with deflate compression)
|
# Compressed profile n bytes (zlib with deflate compression)
|
||||||
i = s.find(b"\0")
|
i = s.find(b"\0")
|
||||||
if Image.DEBUG:
|
logger.debug("iCCP profile name %s", s[:i])
|
||||||
print("iCCP profile name", s[:i])
|
logger.debug("Compression method %s", i8(s[i]))
|
||||||
print("Compression method", i8(s[i]))
|
|
||||||
comp_method = i8(s[i])
|
comp_method = i8(s[i])
|
||||||
if comp_method != 0:
|
if comp_method != 0:
|
||||||
raise SyntaxError("Unknown compression method %s in iCCP chunk" %
|
raise SyntaxError("Unknown compression method %s in iCCP chunk" %
|
||||||
|
@ -507,8 +508,7 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
except EOFError:
|
except EOFError:
|
||||||
break
|
break
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if Image.DEBUG:
|
logger.debug("%s %s %s (unknown)", cid, pos, length)
|
||||||
print(cid, pos, length, "(unknown)")
|
|
||||||
s = ImageFile._safe_read(self.fp, length)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
|
|
||||||
self.png.crc(cid, s)
|
self.png.crc(cid, s)
|
||||||
|
|
|
@ -136,6 +136,10 @@ class PsdImageFile(ImageFile.ImageFile):
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
return len(self.layers)
|
return len(self.layers)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
return len(self.layers) > 1
|
||||||
|
|
||||||
def seek(self, layer):
|
def seek(self, layer):
|
||||||
# seek to given layer (1..max)
|
# seek to given layer (1..max)
|
||||||
if layer == self.frame:
|
if layer == self.frame:
|
||||||
|
|
|
@ -22,10 +22,14 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
from cffi import FFI
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
DEBUG = 0
|
from cffi import FFI
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
defs = """
|
defs = """
|
||||||
struct Pixel_RGBA {
|
struct Pixel_RGBA {
|
||||||
|
@ -50,8 +54,7 @@ class PyAccess(object):
|
||||||
self.xsize = vals['xsize']
|
self.xsize = vals['xsize']
|
||||||
self.ysize = vals['ysize']
|
self.ysize = vals['ysize']
|
||||||
|
|
||||||
if DEBUG:
|
logger.debug("%s", vals)
|
||||||
print(vals)
|
|
||||||
self._post_init()
|
self._post_init()
|
||||||
|
|
||||||
def _post_init(self):
|
def _post_init(self):
|
||||||
|
@ -305,11 +308,9 @@ else:
|
||||||
def new(img, readonly=False):
|
def new(img, readonly=False):
|
||||||
access_type = mode_map.get(img.mode, None)
|
access_type = mode_map.get(img.mode, None)
|
||||||
if not access_type:
|
if not access_type:
|
||||||
if DEBUG:
|
logger.debug("PyAccess Not Implemented: %s", img.mode)
|
||||||
print("PyAccess Not Implemented: %s" % img.mode)
|
|
||||||
return None
|
return None
|
||||||
if DEBUG:
|
logger.debug("New PyAccess: %s", img.mode)
|
||||||
print("New PyAccess: %s" % img.mode)
|
|
||||||
return access_type(img, readonly)
|
return access_type(img, readonly)
|
||||||
|
|
||||||
# End of file
|
# End of file
|
||||||
|
|
|
@ -158,6 +158,10 @@ class SpiderImageFile(ImageFile.ImageFile):
|
||||||
def n_frames(self):
|
def n_frames(self):
|
||||||
return self._nimages
|
return self._nimages
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
return self._nimages > 1
|
||||||
|
|
||||||
# 1st image index is zero (although SPIDER imgnumber starts at 1)
|
# 1st image index is zero (although SPIDER imgnumber starts at 1)
|
||||||
def tell(self):
|
def tell(self):
|
||||||
if self.imgnumber < 1:
|
if self.imgnumber < 1:
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
__version__ = "1.3.5"
|
__version__ = "1.3.5"
|
||||||
|
DEBUG = False # Needs to be merged with the new logging approach.
|
||||||
|
|
||||||
from PIL import Image, ImageFile
|
from PIL import Image, ImageFile
|
||||||
from PIL import ImagePalette
|
from PIL import ImagePalette
|
||||||
|
@ -434,7 +435,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
|
|
||||||
tag, typ = i16(ifd), i16(ifd, 2)
|
tag, typ = i16(ifd), i16(ifd, 2)
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
from PIL import TiffTags
|
from PIL import TiffTags
|
||||||
tagname = TiffTags.TAGS.get(tag, "unknown")
|
tagname = TiffTags.TAGS.get(tag, "unknown")
|
||||||
typname = TiffTags.TYPES.get(typ, "unknown")
|
typname = TiffTags.TYPES.get(typ, "unknown")
|
||||||
|
@ -444,7 +445,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
try:
|
try:
|
||||||
dispatch = self.load_dispatch[typ]
|
dispatch = self.load_dispatch[typ]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("- unsupported type", typ)
|
print("- unsupported type", typ)
|
||||||
continue # ignore unsupported type
|
continue # ignore unsupported type
|
||||||
|
|
||||||
|
@ -455,10 +456,10 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
# Get and expand tag value
|
# Get and expand tag value
|
||||||
if size > 4:
|
if size > 4:
|
||||||
here = fp.tell()
|
here = fp.tell()
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("Tag Location: %s" % here)
|
print("Tag Location: %s" % here)
|
||||||
fp.seek(i32(ifd, 8))
|
fp.seek(i32(ifd, 8))
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("Data Location: %s" % fp.tell())
|
print("Data Location: %s" % fp.tell())
|
||||||
data = ImageFile._safe_read(fp, size)
|
data = ImageFile._safe_read(fp, size)
|
||||||
fp.seek(here)
|
fp.seek(here)
|
||||||
|
@ -474,7 +475,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
self.tagdata[tag] = data
|
self.tagdata[tag] = data
|
||||||
self.tagtype[tag] = typ
|
self.tagtype[tag] = typ
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK,
|
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK,
|
||||||
ICCPROFILE, XMP):
|
ICCPROFILE, XMP):
|
||||||
print("- value: <table: %d bytes>" % size)
|
print("- value: <table: %d bytes>" % size)
|
||||||
|
@ -517,7 +518,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
if tag in self.tagtype:
|
if tag in self.tagtype:
|
||||||
typ = self.tagtype[tag]
|
typ = self.tagtype[tag]
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("Tag %s, Type: %s, Value: %s" % (tag, typ, value))
|
print ("Tag %s, Type: %s, Value: %s" % (tag, typ, value))
|
||||||
|
|
||||||
if typ == 1:
|
if typ == 1:
|
||||||
|
@ -573,7 +574,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
else:
|
else:
|
||||||
data = b"".join(map(o32, value))
|
data = b"".join(map(o32, value))
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
from PIL import TiffTags
|
from PIL import TiffTags
|
||||||
tagname = TiffTags.TAGS.get(tag, "unknown")
|
tagname = TiffTags.TAGS.get(tag, "unknown")
|
||||||
typname = TiffTags.TYPES.get(typ, "unknown")
|
typname = TiffTags.TYPES.get(typ, "unknown")
|
||||||
|
@ -610,7 +611,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
||||||
|
|
||||||
# pass 2: write directory to file
|
# pass 2: write directory to file
|
||||||
for tag, typ, count, value, data in directory:
|
for tag, typ, count, value, data in directory:
|
||||||
if Image.DEBUG > 1:
|
if DEBUG > 1:
|
||||||
print(tag, typ, count, repr(value), repr(data))
|
print(tag, typ, count, repr(value), repr(data))
|
||||||
fp.write(o16(tag) + o16(typ) + o32(count) + value)
|
fp.write(o16(tag) + o16(typ) + o32(count) + value)
|
||||||
|
|
||||||
|
@ -652,8 +653,9 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.__fp = self.fp
|
self.__fp = self.fp
|
||||||
self._frame_pos = []
|
self._frame_pos = []
|
||||||
self._n_frames = None
|
self._n_frames = None
|
||||||
|
self._is_animated = None
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("*** TiffImageFile._open ***")
|
print ("*** TiffImageFile._open ***")
|
||||||
print ("- __first:", self.__first)
|
print ("- __first:", self.__first)
|
||||||
print ("- ifh: ", ifh)
|
print ("- ifh: ", ifh)
|
||||||
|
@ -673,6 +675,20 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.seek(current)
|
self.seek(current)
|
||||||
return self._n_frames
|
return self._n_frames
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_animated(self):
|
||||||
|
if self._is_animated is None:
|
||||||
|
current = self.tell()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.seek(1)
|
||||||
|
self._is_animated = True
|
||||||
|
except EOFError:
|
||||||
|
self._is_animated = False
|
||||||
|
|
||||||
|
self.seek(current)
|
||||||
|
return self._is_animated
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
"Select a given frame as current image"
|
"Select a given frame as current image"
|
||||||
self._seek(max(frame, 0)) # Questionable backwards compatibility.
|
self._seek(max(frame, 0)) # Questionable backwards compatibility.
|
||||||
|
@ -687,7 +703,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
while len(self._frame_pos) <= frame:
|
while len(self._frame_pos) <= frame:
|
||||||
if not self.__next:
|
if not self.__next:
|
||||||
raise EOFError("no more images in TIFF file")
|
raise EOFError("no more images in TIFF file")
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("Seeking to frame %s, on frame %s, __next %s, location: %s" %
|
print("Seeking to frame %s, on frame %s, __next %s, location: %s" %
|
||||||
(frame, self.__frame, self.__next, self.fp.tell()))
|
(frame, self.__frame, self.__next, self.fp.tell()))
|
||||||
# reset python3 buffered io handle in case fp
|
# reset python3 buffered io handle in case fp
|
||||||
|
@ -695,7 +711,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.fp.tell()
|
self.fp.tell()
|
||||||
self.fp.seek(self.__next)
|
self.fp.seek(self.__next)
|
||||||
self._frame_pos.append(self.__next)
|
self._frame_pos.append(self.__next)
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("Loading tags, location: %s" % self.fp.tell())
|
print("Loading tags, location: %s" % self.fp.tell())
|
||||||
self.tag.load(self.fp)
|
self.tag.load(self.fp)
|
||||||
self.__next = self.tag.next
|
self.__next = self.tag.next
|
||||||
|
@ -773,19 +789,19 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
# Rearranging for supporting byteio items, since they have a fileno
|
# Rearranging for supporting byteio items, since they have a fileno
|
||||||
# that returns an IOError if there's no underlying fp. Easier to
|
# that returns an IOError if there's no underlying fp. Easier to
|
||||||
# deal with here by reordering.
|
# deal with here by reordering.
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("have getvalue. just sending in a string from getvalue")
|
print ("have getvalue. just sending in a string from getvalue")
|
||||||
n, err = decoder.decode(self.fp.getvalue())
|
n, err = decoder.decode(self.fp.getvalue())
|
||||||
elif hasattr(self.fp, "fileno"):
|
elif hasattr(self.fp, "fileno"):
|
||||||
# we've got a actual file on disk, pass in the fp.
|
# we've got a actual file on disk, pass in the fp.
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("have fileno, calling fileno version of the decoder.")
|
print ("have fileno, calling fileno version of the decoder.")
|
||||||
self.fp.seek(0)
|
self.fp.seek(0)
|
||||||
# 4 bytes, otherwise the trace might error out
|
# 4 bytes, otherwise the trace might error out
|
||||||
n, err = decoder.decode(b"fpfp")
|
n, err = decoder.decode(b"fpfp")
|
||||||
else:
|
else:
|
||||||
# we have something else.
|
# we have something else.
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("don't have fileno or getvalue. just reading")
|
print ("don't have fileno or getvalue. just reading")
|
||||||
# UNDONE -- so much for that buffer size thing.
|
# UNDONE -- so much for that buffer size thing.
|
||||||
n, err = decoder.decode(self.fp.read())
|
n, err = decoder.decode(self.fp.read())
|
||||||
|
@ -823,7 +839,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
fillorder = getscalar(FILLORDER, 1)
|
fillorder = getscalar(FILLORDER, 1)
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("*** Summary ***")
|
print("*** Summary ***")
|
||||||
print("- compression:", self._compression)
|
print("- compression:", self._compression)
|
||||||
print("- photometric_interpretation:", photo)
|
print("- photometric_interpretation:", photo)
|
||||||
|
@ -835,7 +851,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
ysize = getscalar(IMAGELENGTH)
|
ysize = getscalar(IMAGELENGTH)
|
||||||
self.size = xsize, ysize
|
self.size = xsize, ysize
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("- size:", self.size)
|
print("- size:", self.size)
|
||||||
|
|
||||||
format = getscalar(SAMPLEFORMAT, 1)
|
format = getscalar(SAMPLEFORMAT, 1)
|
||||||
|
@ -846,16 +862,16 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.tag.get(BITSPERSAMPLE, (1,)),
|
self.tag.get(BITSPERSAMPLE, (1,)),
|
||||||
self.tag.get(EXTRASAMPLES, ())
|
self.tag.get(EXTRASAMPLES, ())
|
||||||
)
|
)
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("format key:", key)
|
print("format key:", key)
|
||||||
try:
|
try:
|
||||||
self.mode, rawmode = OPEN_INFO[key]
|
self.mode, rawmode = OPEN_INFO[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("- unsupported format")
|
print("- unsupported format")
|
||||||
raise SyntaxError("unknown pixel mode")
|
raise SyntaxError("unknown pixel mode")
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("- raw mode:", rawmode)
|
print("- raw mode:", rawmode)
|
||||||
print("- pil mode:", self.mode)
|
print("- pil mode:", self.mode)
|
||||||
|
|
||||||
|
@ -895,7 +911,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
"tiff_sgilog",
|
"tiff_sgilog",
|
||||||
"tiff_sgilog24",
|
"tiff_sgilog24",
|
||||||
"tiff_raw_16"]:
|
"tiff_raw_16"]:
|
||||||
# if Image.DEBUG:
|
# if DEBUG:
|
||||||
# print "Activating g4 compression for whole file"
|
# print "Activating g4 compression for whole file"
|
||||||
|
|
||||||
# Decoder expects entire file as one tile.
|
# Decoder expects entire file as one tile.
|
||||||
|
@ -936,7 +952,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.tag.get(BITSPERSAMPLE, (1,)),
|
self.tag.get(BITSPERSAMPLE, (1,)),
|
||||||
self.tag.get(EXTRASAMPLES, ())
|
self.tag.get(EXTRASAMPLES, ())
|
||||||
)
|
)
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("format key:", key)
|
print("format key:", key)
|
||||||
# this should always work, since all the
|
# this should always work, since all the
|
||||||
# fillorder==2 modes have a corresponding
|
# fillorder==2 modes have a corresponding
|
||||||
|
@ -965,7 +981,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
(self._compression,
|
(self._compression,
|
||||||
(0, min(y, ysize), w, min(y+h, ysize)),
|
(0, min(y, ysize), w, min(y+h, ysize)),
|
||||||
offsets[i], a))
|
offsets[i], a))
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("tiles: ", self.tile)
|
print ("tiles: ", self.tile)
|
||||||
y = y + h
|
y = y + h
|
||||||
if y >= self.size[1]:
|
if y >= self.size[1]:
|
||||||
|
@ -994,7 +1010,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
l += 1
|
l += 1
|
||||||
a = None
|
a = None
|
||||||
else:
|
else:
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("- unsupported data organization")
|
print("- unsupported data organization")
|
||||||
raise SyntaxError("unknown data organization")
|
raise SyntaxError("unknown data organization")
|
||||||
|
|
||||||
|
@ -1075,7 +1091,7 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
# write any arbitrary tags passed in as an ImageFileDirectory
|
# write any arbitrary tags passed in as an ImageFileDirectory
|
||||||
info = im.encoderinfo.get("tiffinfo", {})
|
info = im.encoderinfo.get("tiffinfo", {})
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print("Tiffinfo Keys: %s" % info.keys)
|
print("Tiffinfo Keys: %s" % info.keys)
|
||||||
keys = list(info.keys())
|
keys = list(info.keys())
|
||||||
for key in keys:
|
for key in keys:
|
||||||
|
@ -1150,7 +1166,7 @@ def _save(im, fp, filename):
|
||||||
ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
|
ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
|
||||||
|
|
||||||
if libtiff:
|
if libtiff:
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print ("Saving using libtiff encoder")
|
print ("Saving using libtiff encoder")
|
||||||
print (ifd.items())
|
print (ifd.items())
|
||||||
_fp = 0
|
_fp = 0
|
||||||
|
@ -1208,7 +1224,7 @@ def _save(im, fp, filename):
|
||||||
# int or similar
|
# int or similar
|
||||||
atts[k] = v
|
atts[k] = v
|
||||||
|
|
||||||
if Image.DEBUG:
|
if DEBUG:
|
||||||
print (atts)
|
print (atts)
|
||||||
|
|
||||||
# libtiff always expects the bytes in native order.
|
# libtiff always expects the bytes in native order.
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# ;-)
|
# ;-)
|
||||||
|
|
||||||
VERSION = '1.1.7' # PIL version
|
VERSION = '1.1.7' # PIL version
|
||||||
PILLOW_VERSION = '2.9.0.dev0' # Pillow
|
PILLOW_VERSION = '3.0.0.dev0' # Pillow
|
||||||
|
|
||||||
_plugins = ['BmpImagePlugin',
|
_plugins = ['BmpImagePlugin',
|
||||||
'BufrStubImagePlugin',
|
'BufrStubImagePlugin',
|
||||||
|
|
|
@ -26,7 +26,7 @@ Pillow is the "friendly PIL fork" by `Alex Clark and Contributors <https://githu
|
||||||
:target: https://pypi.python.org/pypi/Pillow/
|
:target: https://pypi.python.org/pypi/Pillow/
|
||||||
:alt: Number of PyPI downloads
|
:alt: Number of PyPI downloads
|
||||||
|
|
||||||
.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.svg?branch=master
|
.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.svg?branch=master&service=github
|
||||||
:target: https://coveralls.io/r/python-pillow/Pillow?branch=master
|
:target: https://coveralls.io/r/python-pillow/Pillow?branch=master
|
||||||
:alt: Code coverage
|
:alt: Code coverage
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ Released quarterly on the first day of January, April, July, October.
|
||||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in ``master`` branch.
|
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in ``master`` branch.
|
||||||
* [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in:
|
* [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in:
|
||||||
```
|
```
|
||||||
PIL/__init__.py setup.py _imaging.c
|
PIL/__init__.py setup.py _imaging.c appveyor.yml
|
||||||
```
|
```
|
||||||
* [ ] Update `CHANGES.rst`.
|
* [ ] Update `CHANGES.rst`.
|
||||||
* [ ] Run pre-release check via `make pre`.
|
* [ ] Run pre-release check via `make pre`.
|
||||||
|
|
|
@ -14,104 +14,9 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
|
||||||
# For special purposes, you can import this module and call
|
|
||||||
# the makedelta or compress functions yourself. For example,
|
|
||||||
# if you have an application that generates a sequence of
|
|
||||||
# images, you can convert it to a GIF animation using some-
|
|
||||||
# thing like the following code:
|
|
||||||
#
|
|
||||||
# import Image
|
|
||||||
# import gifmaker
|
|
||||||
#
|
|
||||||
# sequence = []
|
|
||||||
#
|
|
||||||
# # generate sequence
|
|
||||||
# for i in range(100):
|
|
||||||
# im = <generate image i>
|
|
||||||
# sequence.append(im)
|
|
||||||
#
|
|
||||||
# # write GIF animation
|
|
||||||
# fp = open("out.gif", "wb")
|
|
||||||
# gifmaker.makedelta(fp, sequence)
|
|
||||||
# fp.close()
|
|
||||||
#
|
|
||||||
# Alternatively, use an iterator to generate the sequence, and
|
|
||||||
# write data directly to a socket. Or something...
|
|
||||||
#
|
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
from PIL import Image, ImageChops, ImageSequence
|
from PIL import Image
|
||||||
|
|
||||||
from PIL.GifImagePlugin import getheader, getdata
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# straightforward delta encoding
|
|
||||||
|
|
||||||
|
|
||||||
def makedelta(fp, sequence):
|
|
||||||
"""Convert list of image frames to a GIF animation file"""
|
|
||||||
|
|
||||||
frames = 0
|
|
||||||
|
|
||||||
previous = None
|
|
||||||
|
|
||||||
for im in sequence:
|
|
||||||
|
|
||||||
# To specify duration, add the time in milliseconds to getdata(),
|
|
||||||
# e.g. getdata(im, duration=1000)
|
|
||||||
|
|
||||||
if not previous:
|
|
||||||
|
|
||||||
# global header
|
|
||||||
for s in getheader(im)[0] + getdata(im):
|
|
||||||
fp.write(s)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
# delta frame
|
|
||||||
delta = ImageChops.subtract_modulo(im, previous)
|
|
||||||
|
|
||||||
bbox = delta.getbbox()
|
|
||||||
|
|
||||||
if bbox:
|
|
||||||
|
|
||||||
# compress difference
|
|
||||||
for s in getdata(im.crop(bbox), offset=bbox[:2]):
|
|
||||||
fp.write(s)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# FIXME: what should we do in this case?
|
|
||||||
pass
|
|
||||||
|
|
||||||
previous = im.copy()
|
|
||||||
|
|
||||||
frames += 1
|
|
||||||
|
|
||||||
fp.write(b";")
|
|
||||||
|
|
||||||
return frames
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# main hack
|
|
||||||
|
|
||||||
|
|
||||||
def compress(infile, outfile):
|
|
||||||
|
|
||||||
# open input image, and force loading of first frame
|
|
||||||
im = Image.open(infile)
|
|
||||||
im.load()
|
|
||||||
|
|
||||||
# open output file
|
|
||||||
fp = open(outfile, "wb")
|
|
||||||
|
|
||||||
seq = ImageSequence.Iterator(im)
|
|
||||||
|
|
||||||
makedelta(fp, seq)
|
|
||||||
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
@ -122,4 +27,5 @@ if __name__ == "__main__":
|
||||||
print("Usage: gifmaker infile outfile")
|
print("Usage: gifmaker infile outfile")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
compress(sys.argv[1], sys.argv[2])
|
im = Image.open(sys.argv[1])
|
||||||
|
im.save(sys.argv[2], save_all=True)
|
||||||
|
|
|
@ -21,6 +21,7 @@ from __future__ import print_function
|
||||||
|
|
||||||
import getopt
|
import getopt
|
||||||
import glob
|
import glob
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
@ -42,6 +43,7 @@ except getopt.error as v:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
verbose = quiet = verify = 0
|
verbose = quiet = verify = 0
|
||||||
|
logging_level = "WARNING"
|
||||||
|
|
||||||
for o, a in opt:
|
for o, a in opt:
|
||||||
if o == "-f":
|
if o == "-f":
|
||||||
|
@ -58,7 +60,9 @@ for o, a in opt:
|
||||||
elif o == "-v":
|
elif o == "-v":
|
||||||
verify = 1
|
verify = 1
|
||||||
elif o == "-D":
|
elif o == "-D":
|
||||||
Image.DEBUG += 1
|
logging_level = "DEBUG"
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging_level)
|
||||||
|
|
||||||
|
|
||||||
def globfix(files):
|
def globfix(files):
|
||||||
|
|
|
@ -15,9 +15,6 @@ from PIL import Image, ImageTk
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
Image.DEBUG = 0
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# an image animation player
|
# an image animation player
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
import sys
|
import sys
|
||||||
from PIL import Image, ImageFilter
|
from PIL import Image
|
||||||
|
|
||||||
min_iterations = 100
|
min_iterations = 100
|
||||||
max_iterations = 10000
|
max_iterations = 10000
|
||||||
|
@ -31,7 +31,8 @@ class TestImagingLeaks(PillowTestCase):
|
||||||
|
|
||||||
def test_leak_putdata(self):
|
def test_leak_putdata(self):
|
||||||
im = Image.new('RGB', (25, 25))
|
im = Image.new('RGB', (25, 25))
|
||||||
self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
|
self._test_leak(min_iterations, max_iterations,
|
||||||
|
im.putdata, im.getdata())
|
||||||
|
|
||||||
def test_leak_getlist(self):
|
def test_leak_getlist(self):
|
||||||
im = Image.new('P', (25, 25))
|
im = Image.new('P', (25, 25))
|
||||||
|
|
|
@ -42,7 +42,8 @@ class TestPngDos(PillowTestCase):
|
||||||
total_len = 0
|
total_len = 0
|
||||||
for txt in im2.text.values():
|
for txt in im2.text.values():
|
||||||
total_len += len(txt)
|
total_len += len(txt)
|
||||||
self.assertLess(total_len, 64*1024*1024, "Total text chunks greater than 64M")
|
self.assertLess(total_len, 64*1024*1024,
|
||||||
|
"Total text chunks greater than 64M")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
12
Tests/images/bad_palette_entry.gpl
Normal file
12
Tests/images/bad_palette_entry.gpl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: badpaletteentry
|
||||||
|
Columns: 4
|
||||||
|
#
|
||||||
|
0 0 0 Index 3
|
||||||
|
65 38
|
||||||
|
103 62 49 Index 6
|
||||||
|
79 73 72 Index 7
|
||||||
|
114 101 97 Index 8
|
||||||
|
208 127 100 Index 9
|
||||||
|
151 144 142 Index 10
|
||||||
|
221 207 199 Index 11
|
12
Tests/images/bad_palette_file.gpl
Normal file
12
Tests/images/bad_palette_file.gpl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: badpalettefile
|
||||||
|
Columns: 4
|
||||||
|
#
|
||||||
|
0 0 0 Index 3
|
||||||
|
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
103 62 49 Index 6
|
||||||
|
79 73 72 Index 7
|
||||||
|
114 101 97 Index 8
|
||||||
|
208 127 100 Index 9
|
||||||
|
151 144 142 Index 10
|
||||||
|
221 207 199 Index 11
|
12
Tests/images/custom_gimp_palette.gpl
Normal file
12
Tests/images/custom_gimp_palette.gpl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: custompalette
|
||||||
|
Columns: 4
|
||||||
|
#
|
||||||
|
0 0 0 Index 3
|
||||||
|
65 38 30 Index 4
|
||||||
|
103 62 49 Index 6
|
||||||
|
79 73 72 Index 7
|
||||||
|
114 101 97 Index 8
|
||||||
|
208 127 100 Index 9
|
||||||
|
151 144 142 Index 10
|
||||||
|
221 207 199 Index 11
|
BIN
Tests/images/hopper.bmp
Normal file
BIN
Tests/images/hopper.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
Tests/images/sugarshack_bad_mpo_header.jpg
Normal file
BIN
Tests/images/sugarshack_bad_mpo_header.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
4
Tests/images/test.gpl
Normal file
4
Tests/images/test.gpl
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: Test
|
||||||
|
Columns: 0
|
||||||
|
#
|
|
@ -61,6 +61,10 @@ class TestCffi(PillowTestCase):
|
||||||
for y in range(0, h, 10):
|
for y in range(0, h, 10):
|
||||||
self.assertEqual(access[(x, y)], caccess[(x, y)])
|
self.assertEqual(access[(x, y)], caccess[(x, y)])
|
||||||
|
|
||||||
|
# Access an out-of-range pixel
|
||||||
|
self.assertRaises(ValueError,
|
||||||
|
lambda: access[(access.xsize+1, access.ysize+1)])
|
||||||
|
|
||||||
def test_get_vs_c(self):
|
def test_get_vs_c(self):
|
||||||
rgb = hopper('RGB')
|
rgb = hopper('RGB')
|
||||||
rgb.load()
|
rgb.load()
|
||||||
|
@ -103,6 +107,14 @@ class TestCffi(PillowTestCase):
|
||||||
access[(x, y)] = color
|
access[(x, y)] = color
|
||||||
self.assertEqual(color, caccess[(x, y)])
|
self.assertEqual(color, caccess[(x, y)])
|
||||||
|
|
||||||
|
# Attempt to set the value on a read-only image
|
||||||
|
access = PyAccess.new(im, True)
|
||||||
|
try:
|
||||||
|
access[(0, 0)] = color
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
self.fail("Putpixel did not fail on a read-only image")
|
||||||
|
|
||||||
def test_set_vs_c(self):
|
def test_set_vs_c(self):
|
||||||
rgb = hopper('RGB')
|
rgb = hopper('RGB')
|
||||||
rgb.load()
|
rgb.load()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, BmpImagePlugin
|
||||||
import io
|
import io
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +25,11 @@ class TestFileBmp(PillowTestCase):
|
||||||
self.roundtrip(hopper("P"))
|
self.roundtrip(hopper("P"))
|
||||||
self.roundtrip(hopper("RGB"))
|
self.roundtrip(hopper("RGB"))
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: BmpImagePlugin.BmpImageFile(fp))
|
||||||
|
|
||||||
def test_save_to_bytes(self):
|
def test_save_to_bytes(self):
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
@ -49,6 +54,22 @@ class TestFileBmp(PillowTestCase):
|
||||||
|
|
||||||
self.assertEqual(reloaded.info["dpi"], dpi)
|
self.assertEqual(reloaded.info["dpi"], dpi)
|
||||||
|
|
||||||
|
def test_save_bmp_with_dpi(self):
|
||||||
|
# Test for #1301
|
||||||
|
# Arrange
|
||||||
|
outfile = self.tempfile("temp.jpg")
|
||||||
|
im = Image.open("Tests/images/hopper.bmp")
|
||||||
|
|
||||||
|
# Act
|
||||||
|
im.save(outfile, 'JPEG', dpi=im.info['dpi'])
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
reloaded = Image.open(outfile)
|
||||||
|
reloaded.load()
|
||||||
|
self.assertEqual(im.info['dpi'], reloaded.info['dpi'])
|
||||||
|
self.assertEqual(im.size, reloaded.size)
|
||||||
|
self.assertEqual(reloaded.format, "JPEG")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
19
Tests/test_file_bufrstub.py
Normal file
19
Tests/test_file_bufrstub.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import BufrStubImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileBufrStub(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda:
|
||||||
|
BufrStubImagePlugin.BufrStubImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
|
@ -20,6 +20,12 @@ class TestFileCur(PillowTestCase):
|
||||||
self.assertEqual(im.getpixel((11, 1)), (253, 254, 254, 1))
|
self.assertEqual(im.getpixel((11, 1)), (253, 254, 254, 1))
|
||||||
self.assertEqual(im.getpixel((16, 16)), (84, 87, 86, 255))
|
self.assertEqual(im.getpixel((16, 16)), (84, 87, 86, 255))
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: CurImagePlugin.CurImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -20,6 +20,11 @@ class TestFileDcx(PillowTestCase):
|
||||||
orig = hopper()
|
orig = hopper()
|
||||||
self.assert_image_equal(im, orig)
|
self.assert_image_equal(im, orig)
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: DcxImagePlugin.DcxImageFile(fp))
|
||||||
|
|
||||||
def test_tell(self):
|
def test_tell(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
@ -33,6 +38,19 @@ class TestFileDcx(PillowTestCase):
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
|
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):
|
def test_seek_too_far(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -51,6 +51,12 @@ class TestFileEps(PillowTestCase):
|
||||||
self.assertEqual(image2_scale2.size, (720, 504))
|
self.assertEqual(image2_scale2.size, (720, 504))
|
||||||
self.assertEqual(image2_scale2.format, "EPS")
|
self.assertEqual(image2_scale2.format, "EPS")
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: EpsImagePlugin.EpsImageFile(invalid_file))
|
||||||
|
|
||||||
def test_file_object(self):
|
def test_file_object(self):
|
||||||
# issue 479
|
# issue 479
|
||||||
image1 = Image.open(file1)
|
image1 = Image.open(file1)
|
||||||
|
@ -149,7 +155,9 @@ class TestFileEps(PillowTestCase):
|
||||||
Image.open(file3)
|
Image.open(file3)
|
||||||
|
|
||||||
def _test_readline(self, t, ending):
|
def _test_readline(self, t, ending):
|
||||||
ending = "Failure with line ending: %s" % ("".join("%s" % ord(s) for s in ending))
|
ending = "Failure with line ending: %s" % ("".join(
|
||||||
|
"%s" % ord(s)
|
||||||
|
for s in ending))
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'something', ending)
|
self.assertEqual(t.readline().strip('\r\n'), 'something', ending)
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'else', ending)
|
self.assertEqual(t.readline().strip('\r\n'), 'else', ending)
|
||||||
self.assertEqual(t.readline().strip('\r\n'), 'baz', ending)
|
self.assertEqual(t.readline().strip('\r\n'), 'baz', ending)
|
||||||
|
|
19
Tests/test_file_fitsstub.py
Normal file
19
Tests/test_file_fitsstub.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import FitsStubImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileFitsStub(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda:
|
||||||
|
FitsStubImagePlugin.FITSStubImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, FliImagePlugin
|
||||||
|
|
||||||
# sample ppm stream
|
# sample ppm stream
|
||||||
# created as an export of a palette image from Gimp2.6
|
# created as an export of a palette image from Gimp2.6
|
||||||
|
@ -18,9 +18,28 @@ class TestFileFli(PillowTestCase):
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "FLI")
|
self.assertEqual(im.format, "FLI")
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: FliImagePlugin.FliImageFile(invalid_file))
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
self.assertEqual(im.n_frames, 2)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
|
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__':
|
if __name__ == '__main__':
|
||||||
|
|
18
Tests/test_file_fpx.py
Normal file
18
Tests/test_file_fpx.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import FpxImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileFpx(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: FpxImagePlugin.FpxImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
18
Tests/test_file_gbr.py
Normal file
18
Tests/test_file_gbr.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import GbrImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileGbr(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: GbrImagePlugin.GbrImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
|
@ -25,6 +25,12 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "GIF")
|
self.assertEqual(im.format, "GIF")
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: GifImagePlugin.GifImageFile(invalid_file))
|
||||||
|
|
||||||
def test_optimize(self):
|
def test_optimize(self):
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
@ -71,6 +77,24 @@ class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
self.assert_image_similar(reread.convert('RGB'), hopper(), 50)
|
self.assert_image_similar(reread.convert('RGB'), hopper(), 50)
|
||||||
|
|
||||||
|
def test_roundtrip_save_all(self):
|
||||||
|
# Single frame image
|
||||||
|
out = self.tempfile('temp.gif')
|
||||||
|
im = hopper()
|
||||||
|
im.save(out, save_all=True)
|
||||||
|
reread = Image.open(out)
|
||||||
|
|
||||||
|
self.assert_image_similar(reread.convert('RGB'), im, 50)
|
||||||
|
|
||||||
|
# Multiframe image
|
||||||
|
im = Image.open("Tests/images/dispose_bgnd.gif")
|
||||||
|
|
||||||
|
out = self.tempfile('temp.gif')
|
||||||
|
im.save(out, save_all=True)
|
||||||
|
reread = Image.open(out)
|
||||||
|
|
||||||
|
self.assertEqual(reread.n_frames, 5)
|
||||||
|
|
||||||
def test_palette_handling(self):
|
def test_palette_handling(self):
|
||||||
# see https://github.com/python-pillow/Pillow/issues/513
|
# see https://github.com/python-pillow/Pillow/issues/513
|
||||||
|
|
||||||
|
@ -135,8 +159,25 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertEqual(framecount, 5)
|
self.assertEqual(framecount, 5)
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
|
im = Image.open(TEST_GIF)
|
||||||
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
im = Image.open("Tests/images/iss634.gif")
|
im = Image.open("Tests/images/iss634.gif")
|
||||||
self.assertEqual(im.n_frames, 43)
|
self.assertEqual(im.n_frames, 42)
|
||||||
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
|
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):
|
def test_dispose_none(self):
|
||||||
img = Image.open("Tests/images/dispose_none.gif")
|
img = Image.open("Tests/images/dispose_none.gif")
|
||||||
|
|
36
Tests/test_file_gimppalette.py
Normal file
36
Tests/test_file_gimppalette.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL.GimpPaletteFile import GimpPaletteFile
|
||||||
|
|
||||||
|
|
||||||
|
class TestImage(PillowTestCase):
|
||||||
|
|
||||||
|
def test_sanity(self):
|
||||||
|
with open('Tests/images/test.gpl', 'rb') as fp:
|
||||||
|
GimpPaletteFile(fp)
|
||||||
|
|
||||||
|
with open('Tests/images/hopper.jpg', 'rb') as fp:
|
||||||
|
self.assertRaises(SyntaxError, lambda: GimpPaletteFile(fp))
|
||||||
|
|
||||||
|
with open('Tests/images/bad_palette_file.gpl', 'rb') as fp:
|
||||||
|
self.assertRaises(SyntaxError, lambda: GimpPaletteFile(fp))
|
||||||
|
|
||||||
|
with open('Tests/images/bad_palette_entry.gpl', 'rb') as fp:
|
||||||
|
self.assertRaises(ValueError, lambda: GimpPaletteFile(fp))
|
||||||
|
|
||||||
|
def test_get_palette(self):
|
||||||
|
# Arrange
|
||||||
|
with open('Tests/images/custom_gimp_palette.gpl', 'rb') as fp:
|
||||||
|
palette_file = GimpPaletteFile(fp)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
palette, mode = palette_file.getpalette()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(mode, "RGB")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
19
Tests/test_file_gribstub.py
Normal file
19
Tests/test_file_gribstub.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import GribStubImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileGribStub(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda:
|
||||||
|
GribStubImagePlugin.GribStubImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
19
Tests/test_file_hdf5stub.py
Normal file
19
Tests/test_file_hdf5stub.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import Hdf5StubImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileHdf5Stub(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
test_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda:
|
||||||
|
Hdf5StubImagePlugin.HDF5StubImageFile(test_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
|
@ -1,7 +1,7 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
import io
|
import io
|
||||||
from PIL import Image
|
from PIL import Image, IcoImagePlugin
|
||||||
|
|
||||||
# sample ppm stream
|
# sample ppm stream
|
||||||
TEST_ICO_FILE = "Tests/images/hopper.ico"
|
TEST_ICO_FILE = "Tests/images/hopper.ico"
|
||||||
|
@ -17,6 +17,11 @@ class TestFileIco(PillowTestCase):
|
||||||
self.assertEqual(im.size, (16, 16))
|
self.assertEqual(im.size, (16, 16))
|
||||||
self.assertEqual(im.format, "ICO")
|
self.assertEqual(im.format, "ICO")
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: IcoImagePlugin.IcoImageFile(fp))
|
||||||
|
|
||||||
def test_save_to_bytes(self):
|
def test_save_to_bytes(self):
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
@ -30,7 +35,8 @@ class TestFileIco(PillowTestCase):
|
||||||
self.assertEqual(im.mode, reloaded.mode)
|
self.assertEqual(im.mode, reloaded.mode)
|
||||||
self.assertEqual((64, 64), reloaded.size)
|
self.assertEqual((64, 64), reloaded.size)
|
||||||
self.assertEqual(reloaded.format, "ICO")
|
self.assertEqual(reloaded.format, "ICO")
|
||||||
self.assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS))
|
self.assert_image_equal(reloaded,
|
||||||
|
hopper().resize((64, 64), Image.LANCZOS))
|
||||||
|
|
||||||
# the other one
|
# the other one
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
|
@ -40,7 +46,8 @@ class TestFileIco(PillowTestCase):
|
||||||
self.assertEqual(im.mode, reloaded.mode)
|
self.assertEqual(im.mode, reloaded.mode)
|
||||||
self.assertEqual((32, 32), reloaded.size)
|
self.assertEqual((32, 32), reloaded.size)
|
||||||
self.assertEqual(reloaded.format, "ICO")
|
self.assertEqual(reloaded.format, "ICO")
|
||||||
self.assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
|
self.assert_image_equal(reloaded,
|
||||||
|
hopper().resize((32, 32), Image.LANCZOS))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, ImImagePlugin
|
||||||
|
|
||||||
# sample im
|
# sample im
|
||||||
TEST_IM = "Tests/images/hopper.im"
|
TEST_IM = "Tests/images/hopper.im"
|
||||||
|
@ -18,6 +18,19 @@ class TestFileIm(PillowTestCase):
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(TEST_IM)
|
im = Image.open(TEST_IM)
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
|
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):
|
def test_roundtrip(self):
|
||||||
out = self.tempfile('temp.im')
|
out = self.tempfile('temp.im')
|
||||||
|
@ -27,6 +40,13 @@ class TestFileIm(PillowTestCase):
|
||||||
|
|
||||||
self.assert_image_equal(reread, im)
|
self.assert_image_equal(reread, im)
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: ImImagePlugin.ImImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
|
@ -291,22 +291,24 @@ class TestFileJpeg(PillowTestCase):
|
||||||
|
|
||||||
# dict of qtable lists
|
# dict of qtable lists
|
||||||
self.assert_image_similar(im,
|
self.assert_image_similar(im,
|
||||||
self.roundtrip(im,
|
self.roundtrip(im, qtables={
|
||||||
qtables={0: standard_l_qtable,
|
0: standard_l_qtable,
|
||||||
1: standard_chrominance_qtable}),
|
1: standard_chrominance_qtable
|
||||||
30)
|
}), 30)
|
||||||
|
|
||||||
# not a sequence
|
# not a sequence
|
||||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables='a'))
|
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables='a'))
|
||||||
# sequence wrong length
|
# sequence wrong length
|
||||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[]))
|
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[]))
|
||||||
# sequence wrong length
|
# sequence wrong length
|
||||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[1, 2, 3, 4, 5]))
|
self.assertRaises(Exception,
|
||||||
|
lambda: self.roundtrip(im, qtables=[1, 2, 3, 4, 5]))
|
||||||
|
|
||||||
# qtable entry not a sequence
|
# qtable entry not a sequence
|
||||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[1]))
|
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[1]))
|
||||||
# qtable entry has wrong number of items
|
# qtable entry has wrong number of items
|
||||||
self.assertRaises(Exception, lambda: self.roundtrip(im, qtables=[[1, 2, 3, 4]]))
|
self.assertRaises(Exception,
|
||||||
|
lambda: self.roundtrip(im, qtables=[[1, 2, 3, 4]]))
|
||||||
|
|
||||||
@unittest.skipUnless(djpeg_available(), "djpeg not available")
|
@unittest.skipUnless(djpeg_available(), "djpeg not available")
|
||||||
def test_load_djpeg(self):
|
def test_load_djpeg(self):
|
||||||
|
@ -337,7 +339,8 @@ class TestFileJpeg(PillowTestCase):
|
||||||
""" Generates a very hard to compress file
|
""" Generates a very hard to compress file
|
||||||
:param size: tuple
|
:param size: tuple
|
||||||
"""
|
"""
|
||||||
return Image.frombytes('RGB', size, os.urandom(size[0]*size[1] * 3))
|
return Image.frombytes('RGB',
|
||||||
|
size, os.urandom(size[0]*size[1] * 3))
|
||||||
|
|
||||||
im = gen_random_image((512, 512))
|
im = gen_random_image((512, 512))
|
||||||
f = self.tempfile("temp.jpeg")
|
f = self.tempfile("temp.jpeg")
|
||||||
|
@ -350,6 +353,17 @@ class TestFileJpeg(PillowTestCase):
|
||||||
reloaded.save(f, quality='keep', progressive=True)
|
reloaded.save(f, quality='keep', progressive=True)
|
||||||
reloaded.save(f, quality='keep', optimize=True)
|
reloaded.save(f, quality='keep', optimize=True)
|
||||||
|
|
||||||
|
def test_bad_mpo_header(self):
|
||||||
|
""" Treat unknown MPO as JPEG """
|
||||||
|
# Arrange
|
||||||
|
|
||||||
|
# Act
|
||||||
|
# Shouldn't raise error
|
||||||
|
im = Image.open("Tests/images/sugarshack_bad_mpo_header.jpg")
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(im.format, "JPEG")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, Jpeg2KImagePlugin
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
|
@ -39,6 +39,13 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
self.assertEqual(im.size, (640, 480))
|
self.assertEqual(im.size, (640, 480))
|
||||||
self.assertEqual(im.format, 'JPEG2000')
|
self.assertEqual(im.format, 'JPEG2000')
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda:
|
||||||
|
Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file))
|
||||||
|
|
||||||
def test_bytesio(self):
|
def test_bytesio(self):
|
||||||
with open('Tests/images/test-card-lossless.jp2', 'rb') as f:
|
with open('Tests/images/test-card-lossless.jp2', 'rb') as f:
|
||||||
data = BytesIO(f.read())
|
data = BytesIO(f.read())
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from helper import unittest, PillowTestCase, hopper, py3
|
from helper import unittest, PillowTestCase, hopper, py3
|
||||||
|
|
||||||
import os
|
|
||||||
import io
|
import io
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from PIL import Image, TiffImagePlugin
|
from PIL import Image, TiffImagePlugin
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LibTiffTestCase(PillowTestCase):
|
class LibTiffTestCase(PillowTestCase):
|
||||||
|
|
||||||
|
@ -231,7 +234,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
""" Are we generating the same interpretation
|
""" Are we generating the same interpretation
|
||||||
of the image as Imagemagick is? """
|
of the image as Imagemagick is? """
|
||||||
TiffImagePlugin.READ_LIBTIFF = True
|
TiffImagePlugin.READ_LIBTIFF = True
|
||||||
# Image.DEBUG = True
|
|
||||||
im = Image.open('Tests/images/12bit.cropped.tif')
|
im = Image.open('Tests/images/12bit.cropped.tif')
|
||||||
im.load()
|
im.load()
|
||||||
TiffImagePlugin.READ_LIBTIFF = False
|
TiffImagePlugin.READ_LIBTIFF = False
|
||||||
|
@ -243,14 +245,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
im2 = Image.open('Tests/images/12in16bit.tif')
|
im2 = Image.open('Tests/images/12in16bit.tif')
|
||||||
|
|
||||||
if Image.DEBUG:
|
logger.debug("%s", [img.getpixel((0, idx))
|
||||||
print(im.getpixel((0, 0)))
|
for img in [im, im2] for idx in range(3)])
|
||||||
print(im.getpixel((0, 1)))
|
|
||||||
print(im.getpixel((0, 2)))
|
|
||||||
|
|
||||||
print(im2.getpixel((0, 0)))
|
|
||||||
print(im2.getpixel((0, 1)))
|
|
||||||
print(im2.getpixel((0, 2)))
|
|
||||||
|
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
|
|
19
Tests/test_file_mcidas.py
Normal file
19
Tests/test_file_mcidas.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import McIdasImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileMcIdas(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda:
|
||||||
|
McIdasImagePlugin.McIdasImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
18
Tests/test_file_mic.py
Normal file
18
Tests/test_file_mic.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import MicImagePlugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileMic(PillowTestCase):
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: MicImagePlugin.MicImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
|
@ -98,6 +98,19 @@ class TestFileMpo(PillowTestCase):
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open("Tests/images/sugarshack.mpo")
|
im = Image.open("Tests/images/sugarshack.mpo")
|
||||||
self.assertEqual(im.n_frames, 2)
|
self.assertEqual(im.n_frames, 2)
|
||||||
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
|
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):
|
def test_image_grab(self):
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, MspImagePlugin
|
||||||
|
|
||||||
TEST_FILE = "Tests/images/hopper.msp"
|
TEST_FILE = "Tests/images/hopper.msp"
|
||||||
|
|
||||||
|
@ -18,6 +18,12 @@ class TestFileMsp(PillowTestCase):
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "MSP")
|
self.assertEqual(im.format, "MSP")
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: MspImagePlugin.MspImageFile(invalid_file))
|
||||||
|
|
||||||
def test_open(self):
|
def test_open(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
# Act
|
# Act
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, PcxImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFilePcx(PillowTestCase):
|
class TestFilePcx(PillowTestCase):
|
||||||
|
@ -19,6 +19,12 @@ class TestFilePcx(PillowTestCase):
|
||||||
for mode in ('1', 'L', 'P', 'RGB'):
|
for mode in ('1', 'L', 'P', 'RGB'):
|
||||||
self._roundtrip(hopper(mode))
|
self._roundtrip(hopper(mode))
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: PcxImagePlugin.PcxImageFile(invalid_file))
|
||||||
|
|
||||||
def test_odd(self):
|
def test_odd(self):
|
||||||
# see issue #523, odd sized images should have a stride that's even.
|
# see issue #523, odd sized images should have a stride that's even.
|
||||||
# not that imagemagick or gimp write pcx that way.
|
# not that imagemagick or gimp write pcx that way.
|
||||||
|
|
|
@ -52,6 +52,12 @@ class TestFilePdf(PillowTestCase):
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.helper_save_as_pdf(mode)
|
self.helper_save_as_pdf(mode)
|
||||||
|
|
||||||
|
def test_unsupported_mode(self):
|
||||||
|
im = hopper("LA")
|
||||||
|
outfile = self.tempfile("temp_LA.pdf")
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, lambda: im.save(outfile))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -81,6 +81,12 @@ class TestFilePng(PillowTestCase):
|
||||||
hopper("I").save(test_file)
|
hopper("I").save(test_file)
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: PngImagePlugin.PngImageFile(invalid_file))
|
||||||
|
|
||||||
def test_broken(self):
|
def test_broken(self):
|
||||||
# Check reading of totally broken files. In this case, the test
|
# Check reading of totally broken files. In this case, the test
|
||||||
# file was checked into Subversion as a text file.
|
# file was checked into Subversion as a text file.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, PsdImagePlugin
|
||||||
|
|
||||||
# sample ppm stream
|
# sample ppm stream
|
||||||
test_file = "Tests/images/hopper.psd"
|
test_file = "Tests/images/hopper.psd"
|
||||||
|
@ -16,12 +16,33 @@ class TestImagePsd(PillowTestCase):
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
self.assertEqual(im.format, "PSD")
|
self.assertEqual(im.format, "PSD")
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: PsdImagePlugin.PsdImageFile(invalid_file))
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open("Tests/images/hopper_merged.psd")
|
im = Image.open("Tests/images/hopper_merged.psd")
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
self.assertEqual(im.n_frames, 2)
|
self.assertEqual(im.n_frames, 2)
|
||||||
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
|
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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, SgiImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFileSgi(PillowTestCase):
|
class TestFileSgi(PillowTestCase):
|
||||||
|
@ -32,6 +32,13 @@ class TestFileSgi(PillowTestCase):
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
self.assertRaises(ValueError, lambda: Image.open(test_file))
|
self.assertRaises(ValueError, lambda: Image.open(test_file))
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(ValueError,
|
||||||
|
lambda:
|
||||||
|
SgiImagePlugin.SgiImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -45,6 +45,7 @@ class TestImageSpider(PillowTestCase):
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
def test_loadImageSeries(self):
|
def test_loadImageSeries(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, SunImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFileSun(PillowTestCase):
|
class TestFileSun(PillowTestCase):
|
||||||
|
@ -16,6 +16,10 @@ class TestFileSun(PillowTestCase):
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (128, 128))
|
self.assertEqual(im.size, (128, 128))
|
||||||
|
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: SunImagePlugin.SunImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -15,6 +15,25 @@ class TestFileTga(PillowTestCase):
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (100, 100))
|
self.assertEqual(im.size, (100, 100))
|
||||||
|
|
||||||
|
def test_save(self):
|
||||||
|
test_file = "Tests/images/tga_id_field.tga"
|
||||||
|
im = Image.open(test_file)
|
||||||
|
|
||||||
|
test_file = self.tempfile("temp.tga")
|
||||||
|
|
||||||
|
# Save
|
||||||
|
im.save(test_file)
|
||||||
|
test_im = Image.open(test_file)
|
||||||
|
self.assertEqual(test_im.size, (100, 100))
|
||||||
|
|
||||||
|
# RGBA save
|
||||||
|
im.convert("RGBA").save(test_file)
|
||||||
|
test_im = Image.open(test_file)
|
||||||
|
self.assertEqual(test_im.size, (100, 100))
|
||||||
|
|
||||||
|
# Unsupported mode save
|
||||||
|
self.assertRaises(IOError, lambda: im.convert("LA").save(test_file))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
import logging
|
||||||
|
import struct
|
||||||
|
|
||||||
from helper import unittest, PillowTestCase, hopper, py3
|
from helper import unittest, PillowTestCase, hopper, py3
|
||||||
|
|
||||||
from PIL import Image, TiffImagePlugin
|
from PIL import Image, TiffImagePlugin
|
||||||
|
|
||||||
import struct
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TestFileTiff(PillowTestCase):
|
class TestFileTiff(PillowTestCase):
|
||||||
|
@ -79,11 +82,25 @@ class TestFileTiff(PillowTestCase):
|
||||||
im._setup()
|
im._setup()
|
||||||
self.assertEqual(im.info['dpi'], (72., 72.))
|
self.assertEqual(im.info['dpi'], (72., 72.))
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: TiffImagePlugin.TiffImageFile(invalid_file))
|
||||||
|
|
||||||
|
|
||||||
def test_bad_exif(self):
|
def test_bad_exif(self):
|
||||||
try:
|
try:
|
||||||
Image.open('Tests/images/hopper_bad_exif.jpg')._getexif()
|
Image.open('Tests/images/hopper_bad_exif.jpg')._getexif()
|
||||||
except struct.error:
|
except struct.error:
|
||||||
self.fail("Bad EXIF data should not pass incorrect values to _binary unpack")
|
self.fail(
|
||||||
|
"Bad EXIF data passed incorrect values to _binary unpack")
|
||||||
|
|
||||||
|
def test_save_unsupported_mode(self):
|
||||||
|
im = hopper("HSV")
|
||||||
|
outfile = self.tempfile("temp.tif")
|
||||||
|
|
||||||
|
self.assertRaises(IOError, lambda: im.save(outfile))
|
||||||
|
|
||||||
def test_little_endian(self):
|
def test_little_endian(self):
|
||||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
im = Image.open('Tests/images/16bit.cropped.tif')
|
||||||
|
@ -118,7 +135,6 @@ class TestFileTiff(PillowTestCase):
|
||||||
""" Are we generating the same interpretation
|
""" Are we generating the same interpretation
|
||||||
of the image as Imagemagick is? """
|
of the image as Imagemagick is? """
|
||||||
|
|
||||||
# Image.DEBUG = True
|
|
||||||
im = Image.open('Tests/images/12bit.cropped.tif')
|
im = Image.open('Tests/images/12bit.cropped.tif')
|
||||||
|
|
||||||
# to make the target --
|
# to make the target --
|
||||||
|
@ -129,14 +145,8 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
im2 = Image.open('Tests/images/12in16bit.tif')
|
im2 = Image.open('Tests/images/12in16bit.tif')
|
||||||
|
|
||||||
if Image.DEBUG:
|
logger.debug("%s", [img.getpixel((0, idx))
|
||||||
print(im.getpixel((0, 0)))
|
for img in [im, im2] for idx in range(3)])
|
||||||
print(im.getpixel((0, 1)))
|
|
||||||
print(im.getpixel((0, 2)))
|
|
||||||
|
|
||||||
print(im2.getpixel((0, 0)))
|
|
||||||
print(im2.getpixel((0, 1)))
|
|
||||||
print(im2.getpixel((0, 2)))
|
|
||||||
|
|
||||||
self.assert_image_equal(im, im2)
|
self.assert_image_equal(im, im2)
|
||||||
|
|
||||||
|
@ -153,9 +163,23 @@ class TestFileTiff(PillowTestCase):
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open('Tests/images/multipage-lastframe.tif')
|
im = Image.open('Tests/images/multipage-lastframe.tif')
|
||||||
self.assertEqual(im.n_frames, 1)
|
self.assertEqual(im.n_frames, 1)
|
||||||
|
self.assertFalse(im.is_animated)
|
||||||
|
|
||||||
im = Image.open('Tests/images/multipage.tiff')
|
im = Image.open('Tests/images/multipage.tiff')
|
||||||
self.assertEqual(im.n_frames, 3)
|
self.assertEqual(im.n_frames, 3)
|
||||||
|
self.assertTrue(im.is_animated)
|
||||||
|
|
||||||
|
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):
|
def test_multipage(self):
|
||||||
# issue #862
|
# issue #862
|
||||||
|
|
|
@ -72,6 +72,11 @@ class TestFileWebp(PillowTestCase):
|
||||||
target = hopper("RGB")
|
target = hopper("RGB")
|
||||||
self.assert_image_similar(image, target, 12)
|
self.assert_image_similar(image, target, 12)
|
||||||
|
|
||||||
|
def test_write_unsupported_mode(self):
|
||||||
|
temp_file = self.tempfile("temp.webp")
|
||||||
|
|
||||||
|
self.assertRaises(IOError, lambda: hopper("L").save(temp_file))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -83,7 +83,8 @@ class TestFileWebpAlpha(PillowTestCase):
|
||||||
image.load()
|
image.load()
|
||||||
image.getdata()
|
image.getdata()
|
||||||
|
|
||||||
# early versions of webp are known to produce higher deviations: deal with it
|
# early versions of webp are known to produce higher deviations:
|
||||||
|
# deal with it
|
||||||
if _webp.WebPDecoderVersion(self) <= 0x201:
|
if _webp.WebPDecoderVersion(self) <= 0x201:
|
||||||
self.assert_image_similar(image, pil_image, 3.0)
|
self.assert_image_similar(image, pil_image, 3.0)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, XpmImagePlugin
|
||||||
|
|
||||||
# sample ppm stream
|
# sample ppm stream
|
||||||
TEST_FILE = "Tests/images/hopper.xpm"
|
TEST_FILE = "Tests/images/hopper.xpm"
|
||||||
|
@ -18,6 +18,12 @@ class TestFileXpm(PillowTestCase):
|
||||||
# large error due to quantization->44 colors.
|
# large error due to quantization->44 colors.
|
||||||
self.assert_image_similar(im.convert('RGB'), hopper('RGB'), 60)
|
self.assert_image_similar(im.convert('RGB'), hopper('RGB'), 60)
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
|
self.assertRaises(SyntaxError,
|
||||||
|
lambda: XpmImagePlugin.XpmImageFile(invalid_file))
|
||||||
|
|
||||||
def test_load_read(self):
|
def test_load_read(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.open(TEST_FILE)
|
im = Image.open(TEST_FILE)
|
||||||
|
|
|
@ -15,6 +15,10 @@ class TestFontBdf(PillowTestCase):
|
||||||
self.assertIsInstance(font, FontFile.FontFile)
|
self.assertIsInstance(font, FontFile.FontFile)
|
||||||
self.assertEqual(len([_f for _f in font.glyph if _f]), 190)
|
self.assertEqual(len([_f for _f in font.glyph if _f]), 190)
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
|
self.assertRaises(SyntaxError, lambda: BdfFontFile.BdfFontFile(fp))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -30,6 +30,10 @@ class TestFontPcf(PillowTestCase):
|
||||||
def test_sanity(self):
|
def test_sanity(self):
|
||||||
self.save_font()
|
self.save_font()
|
||||||
|
|
||||||
|
def test_invalid_file(self):
|
||||||
|
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||||
|
self.assertRaises(SyntaxError, lambda: PcfFontFile.PcfFontFile(fp))
|
||||||
|
|
||||||
def xtest_draw(self):
|
def xtest_draw(self):
|
||||||
|
|
||||||
tempname = self.save_font()
|
tempname = self.save_font()
|
||||||
|
|
|
@ -30,6 +30,15 @@ class TestImage(PillowTestCase):
|
||||||
# self.assertRaises(
|
# self.assertRaises(
|
||||||
# MemoryError, lambda: Image.new("L", (1000000, 1000000)))
|
# 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):
|
def test_invalid_image(self):
|
||||||
if str is bytes:
|
if str is bytes:
|
||||||
import StringIO
|
import StringIO
|
||||||
|
|
|
@ -88,6 +88,12 @@ class TestImageFilter(PillowTestCase):
|
||||||
self.assertEqual(rankfilter("I"), (0, 4, 8))
|
self.assertEqual(rankfilter("I"), (0, 4, 8))
|
||||||
self.assertEqual(rankfilter("F"), (0.0, 4.0, 8.0))
|
self.assertEqual(rankfilter("F"), (0.0, 4.0, 8.0))
|
||||||
|
|
||||||
|
def test_rankfilter_properties(self):
|
||||||
|
rankfilter = ImageFilter.RankFilter(1, 2)
|
||||||
|
|
||||||
|
self.assertEqual(rankfilter.size, 1)
|
||||||
|
self.assertEqual(rankfilter.rank, 2)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -21,12 +21,14 @@ class TestImageMode(PillowTestCase):
|
||||||
|
|
||||||
m = ImageMode.getmode("1")
|
m = ImageMode.getmode("1")
|
||||||
self.assertEqual(m.mode, "1")
|
self.assertEqual(m.mode, "1")
|
||||||
|
self.assertEqual(str(m), "1")
|
||||||
self.assertEqual(m.bands, ("1",))
|
self.assertEqual(m.bands, ("1",))
|
||||||
self.assertEqual(m.basemode, "L")
|
self.assertEqual(m.basemode, "L")
|
||||||
self.assertEqual(m.basetype, "L")
|
self.assertEqual(m.basetype, "L")
|
||||||
|
|
||||||
m = ImageMode.getmode("RGB")
|
m = ImageMode.getmode("RGB")
|
||||||
self.assertEqual(m.mode, "RGB")
|
self.assertEqual(m.mode, "RGB")
|
||||||
|
self.assertEqual(str(m), "RGB")
|
||||||
self.assertEqual(m.bands, ("R", "G", "B"))
|
self.assertEqual(m.bands, ("R", "G", "B"))
|
||||||
self.assertEqual(m.basemode, "RGB")
|
self.assertEqual(m.basemode, "RGB")
|
||||||
self.assertEqual(m.basetype, "L")
|
self.assertEqual(m.basetype, "L")
|
||||||
|
|
|
@ -19,7 +19,7 @@ class TestToQImage(PillowQtTestCase, PillowTestCase):
|
||||||
self.assertFalse(data.isNull())
|
self.assertFalse(data.isNull())
|
||||||
|
|
||||||
# Test saving the file
|
# Test saving the file
|
||||||
tempfile = self.tempfile('temp_{}.png'.format(mode))
|
tempfile = self.tempfile('temp_{0}.png'.format(mode))
|
||||||
data.save(tempfile)
|
data.save(tempfile)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ class TestToQPixmap(PillowQPixmapTestCase, PillowTestCase):
|
||||||
self.assertFalse(data.isNull())
|
self.assertFalse(data.isNull())
|
||||||
|
|
||||||
# Test saving the file
|
# Test saving the file
|
||||||
tempfile = self.tempfile('temp_{}.png'.format(mode))
|
tempfile = self.tempfile('temp_{0}.png'.format(mode))
|
||||||
data.save(tempfile)
|
data.save(tempfile)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@ class TestImageColor(PillowTestCase):
|
||||||
(255, 0, 0, 0), ImageColor.getrgb("rgba(255, 0, 0, 0)"))
|
(255, 0, 0, 0), ImageColor.getrgb("rgba(255, 0, 0, 0)"))
|
||||||
self.assertEqual((255, 0, 0), ImageColor.getrgb("red"))
|
self.assertEqual((255, 0, 0), ImageColor.getrgb("red"))
|
||||||
|
|
||||||
|
self.assertRaises(ValueError,
|
||||||
|
lambda: ImageColor.getrgb("invalid color"))
|
||||||
|
|
||||||
# look for rounding errors (based on code by Tim Hatch)
|
# look for rounding errors (based on code by Tim Hatch)
|
||||||
def test_rounding_errors(self):
|
def test_rounding_errors(self):
|
||||||
|
|
||||||
|
@ -43,8 +46,8 @@ class TestImageColor(PillowTestCase):
|
||||||
|
|
||||||
self.assertEqual(0, ImageColor.getcolor("black", "L"))
|
self.assertEqual(0, ImageColor.getcolor("black", "L"))
|
||||||
self.assertEqual(255, ImageColor.getcolor("white", "L"))
|
self.assertEqual(255, ImageColor.getcolor("white", "L"))
|
||||||
self.assertEqual(
|
self.assertEqual(162,
|
||||||
162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "L"))
|
ImageColor.getcolor("rgba(0, 255, 115, 33)", "L"))
|
||||||
Image.new("L", (1, 1), "white")
|
Image.new("L", (1, 1), "white")
|
||||||
|
|
||||||
self.assertEqual(0, ImageColor.getcolor("black", "1"))
|
self.assertEqual(0, ImageColor.getcolor("black", "1"))
|
||||||
|
|
|
@ -52,6 +52,12 @@ class TestImageDraw(PillowTestCase):
|
||||||
self.assert_warning(DeprecationWarning, lambda: draw.setink(0))
|
self.assert_warning(DeprecationWarning, lambda: draw.setink(0))
|
||||||
self.assert_warning(DeprecationWarning, lambda: draw.setfill(0))
|
self.assert_warning(DeprecationWarning, lambda: draw.setfill(0))
|
||||||
|
|
||||||
|
def test_mode_mismatch(self):
|
||||||
|
im = hopper("RGB").copy()
|
||||||
|
|
||||||
|
self.assertRaises(ValueError,
|
||||||
|
lambda: ImageDraw.ImageDraw(im, mode="L"))
|
||||||
|
|
||||||
def helper_arc(self, bbox):
|
def helper_arc(self, bbox):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.new("RGB", (W, H))
|
im = Image.new("RGB", (W, H))
|
||||||
|
|
|
@ -93,6 +93,9 @@ class TestImageFile(PillowTestCase):
|
||||||
|
|
||||||
self.assert_image_equal(im1, im2)
|
self.assert_image_equal(im1, im2)
|
||||||
|
|
||||||
|
def test_raise_ioerror(self):
|
||||||
|
self.assertRaises(IOError, lambda: ImageFile.raise_ioerror(1))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -182,7 +182,10 @@ try:
|
||||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
# Act/Assert
|
# Act/Assert
|
||||||
self.assertRaises(AssertionError, lambda: draw.multiline_text((0, 0), TEST_TEXT, font=ttf, align="unknown"))
|
self.assertRaises(AssertionError,
|
||||||
|
lambda: draw.multiline_text((0, 0), TEST_TEXT,
|
||||||
|
font=ttf,
|
||||||
|
align="unknown"))
|
||||||
|
|
||||||
def test_multiline_size(self):
|
def test_multiline_size(self):
|
||||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
@ -199,7 +202,8 @@ try:
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
|
|
||||||
self.assertEqual(draw.textsize("longest line", font=ttf)[0],
|
self.assertEqual(draw.textsize("longest line", font=ttf)[0],
|
||||||
draw.multiline_textsize("longest line\nline", font=ttf)[0])
|
draw.multiline_textsize("longest line\nline",
|
||||||
|
font=ttf)[0])
|
||||||
|
|
||||||
def test_multiline_spacing(self):
|
def test_multiline_spacing(self):
|
||||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
@ -256,6 +260,34 @@ try:
|
||||||
# Check boxes a and b are same size
|
# Check boxes a and b are same size
|
||||||
self.assertEqual(box_size_a, box_size_b)
|
self.assertEqual(box_size_a, box_size_b)
|
||||||
|
|
||||||
|
def test_rotated_transposed_font_get_mask(self):
|
||||||
|
# Arrange
|
||||||
|
text = "mask this"
|
||||||
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
orientation = Image.ROTATE_90
|
||||||
|
transposed_font = ImageFont.TransposedFont(
|
||||||
|
font, orientation=orientation)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
mask = transposed_font.getmask(text)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(mask.size, (13, 108))
|
||||||
|
|
||||||
|
def test_unrotated_transposed_font_get_mask(self):
|
||||||
|
# Arrange
|
||||||
|
text = "mask this"
|
||||||
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
orientation = None
|
||||||
|
transposed_font = ImageFont.TransposedFont(
|
||||||
|
font, orientation=orientation)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
mask = transposed_font.getmask(text)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(mask.size, (108, 13))
|
||||||
|
|
||||||
def test_free_type_font_get_name(self):
|
def test_free_type_font_get_name(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
@ -278,6 +310,28 @@ try:
|
||||||
self.assertIsInstance(descent, int)
|
self.assertIsInstance(descent, int)
|
||||||
self.assertEqual((ascent, descent), (16, 4)) # too exact check?
|
self.assertEqual((ascent, descent), (16, 4)) # too exact check?
|
||||||
|
|
||||||
|
def test_free_type_font_get_offset(self):
|
||||||
|
# Arrange
|
||||||
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
text = "offset this"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
offset = font.getoffset(text)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(offset, (0, 3))
|
||||||
|
|
||||||
|
def test_free_type_font_get_mask(self):
|
||||||
|
# Arrange
|
||||||
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
text = "mask this"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
mask = font.getmask(text)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(mask.size, (108, 13))
|
||||||
|
|
||||||
def test_load_path_not_found(self):
|
def test_load_path_not_found(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
filename = "somefilenamethatdoesntexist.ttf"
|
filename = "somefilenamethatdoesntexist.ttf"
|
||||||
|
|
|
@ -5,16 +5,19 @@ from PIL import Image, ImageFont, ImageDraw
|
||||||
class TestImageFontBitmap(PillowTestCase):
|
class TestImageFontBitmap(PillowTestCase):
|
||||||
def test_similar(self):
|
def test_similar(self):
|
||||||
text = 'EmbeddedBitmap'
|
text = 'EmbeddedBitmap'
|
||||||
font_outline = ImageFont.truetype(font='Tests/fonts/DejaVuSans.ttf', size=24)
|
font_outline = ImageFont.truetype(
|
||||||
font_bitmap = ImageFont.truetype(font='Tests/fonts/DejaVuSans-bitmap.ttf', size=24)
|
font='Tests/fonts/DejaVuSans.ttf', size=24)
|
||||||
|
font_bitmap = ImageFont.truetype(
|
||||||
|
font='Tests/fonts/DejaVuSans-bitmap.ttf', size=24)
|
||||||
size_outline, size_bitmap = font_outline.getsize(text), font_bitmap.getsize(text)
|
size_outline, size_bitmap = font_outline.getsize(text), font_bitmap.getsize(text)
|
||||||
size_final = max(size_outline[0], size_bitmap[0]), max(size_outline[1], size_bitmap[1])
|
size_final = max(size_outline[0], size_bitmap[0]), max(size_outline[1], size_bitmap[1])
|
||||||
im_bitmap = Image.new('RGB', size_final, (255, 255, 255))
|
im_bitmap = Image.new('RGB', size_final, (255, 255, 255))
|
||||||
im_outline = im_bitmap.copy()
|
im_outline = im_bitmap.copy()
|
||||||
draw_bitmap, draw_outline = ImageDraw.Draw(im_bitmap), ImageDraw.Draw(im_outline)
|
draw_bitmap, draw_outline = ImageDraw.Draw(im_bitmap), ImageDraw.Draw(im_outline)
|
||||||
|
|
||||||
# Metrics are different on the bitmap and ttf fonts, more so on some platforms
|
# Metrics are different on the bitmap and ttf fonts,
|
||||||
# and versions of freetype than others. Mac has a 1px difference, linux doesn't.
|
# more so on some platforms and versions of freetype than others.
|
||||||
|
# Mac has a 1px difference, linux doesn't.
|
||||||
draw_bitmap.text((0, size_final[1] - size_bitmap[1]),
|
draw_bitmap.text((0, size_final[1] - size_bitmap[1]),
|
||||||
text, fill=(0, 0, 0), font=font_bitmap)
|
text, fill=(0, 0, 0), font=font_bitmap)
|
||||||
draw_outline.text((0, size_final[1] - size_outline[1]),
|
draw_outline.text((0, size_final[1] - size_outline[1]),
|
||||||
|
|
|
@ -75,7 +75,9 @@ class TestImageOpsUsm(PillowTestCase):
|
||||||
(4, 3, 2), (4, 2, 2)]:
|
(4, 3, 2), (4, 2, 2)]:
|
||||||
self.assertGreaterEqual(i.im.getpixel((x, y))[c], 250)
|
self.assertGreaterEqual(i.im.getpixel((x, y))[c], 250)
|
||||||
# Fuzzy match.
|
# Fuzzy match.
|
||||||
gp = lambda x, y: i.im.getpixel((x, y))
|
|
||||||
|
def gp(x, y):
|
||||||
|
return i.im.getpixel((x, y))
|
||||||
self.assertTrue(236 <= gp(7, 4)[0] <= 239)
|
self.assertTrue(236 <= gp(7, 4)[0] <= 239)
|
||||||
self.assertTrue(236 <= gp(7, 5)[2] <= 239)
|
self.assertTrue(236 <= gp(7, 5)[2] <= 239)
|
||||||
self.assertTrue(236 <= gp(7, 6)[2] <= 239)
|
self.assertTrue(236 <= gp(7, 6)[2] <= 239)
|
||||||
|
|
|
@ -22,15 +22,14 @@ class TestImageSequence(PillowTestCase):
|
||||||
|
|
||||||
self.assertEqual(index, 1)
|
self.assertEqual(index, 1)
|
||||||
|
|
||||||
|
self.assertRaises(AttributeError, lambda: ImageSequence.Iterator(0))
|
||||||
|
|
||||||
def _test_multipage_tiff(self, dbg=False):
|
def _test_multipage_tiff(self, dbg=False):
|
||||||
# debug had side effect of calling fp.tell.
|
|
||||||
Image.DEBUG = dbg
|
|
||||||
im = Image.open('Tests/images/multipage.tiff')
|
im = Image.open('Tests/images/multipage.tiff')
|
||||||
for index, frame in enumerate(ImageSequence.Iterator(im)):
|
for index, frame in enumerate(ImageSequence.Iterator(im)):
|
||||||
frame.load()
|
frame.load()
|
||||||
self.assertEqual(index, im.tell())
|
self.assertEqual(index, im.tell())
|
||||||
frame.convert('RGB')
|
frame.convert('RGB')
|
||||||
Image.DEBUG = False
|
|
||||||
|
|
||||||
def test_tiff(self):
|
def test_tiff(self):
|
||||||
# self._test_multipage_tiff(True)
|
# self._test_multipage_tiff(True)
|
||||||
|
|
|
@ -115,7 +115,8 @@ class TestImageWinDib(PillowTestCase):
|
||||||
|
|
||||||
# Act/Assert
|
# Act/Assert
|
||||||
self.assert_warning(DeprecationWarning, dib.tostring)
|
self.assert_warning(DeprecationWarning, dib.tostring)
|
||||||
self.assert_warning(DeprecationWarning, lambda: dib.fromstring(test_buffer))
|
self.assert_warning(DeprecationWarning,
|
||||||
|
lambda: dib.fromstring(test_buffer))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -7,25 +7,20 @@ import PIL.OleFileIO as OleFileIO
|
||||||
|
|
||||||
class TestOleFileIo(PillowTestCase):
|
class TestOleFileIo(PillowTestCase):
|
||||||
|
|
||||||
def test_isOleFile_false(self):
|
def test_isOleFile(self):
|
||||||
# Arrange
|
|
||||||
non_ole_file = "Tests/images/flower.jpg"
|
|
||||||
|
|
||||||
# Act
|
|
||||||
is_ole = OleFileIO.isOleFile(non_ole_file)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertFalse(is_ole)
|
|
||||||
|
|
||||||
def test_isOleFile_true(self):
|
|
||||||
# Arrange
|
|
||||||
ole_file = "Tests/images/test-ole-file.doc"
|
ole_file = "Tests/images/test-ole-file.doc"
|
||||||
|
|
||||||
# Act
|
self.assertTrue(OleFileIO.isOleFile(ole_file))
|
||||||
is_ole = OleFileIO.isOleFile(ole_file)
|
with open(ole_file, 'rb') as fp:
|
||||||
|
self.assertTrue(OleFileIO.isOleFile(fp))
|
||||||
|
self.assertTrue(OleFileIO.isOleFile(fp.read()))
|
||||||
|
|
||||||
# Assert
|
non_ole_file = "Tests/images/flower.jpg"
|
||||||
self.assertTrue(is_ole)
|
|
||||||
|
self.assertFalse(OleFileIO.isOleFile(non_ole_file))
|
||||||
|
with open(non_ole_file, 'rb') as fp:
|
||||||
|
self.assertFalse(OleFileIO.isOleFile(fp))
|
||||||
|
self.assertFalse(OleFileIO.isOleFile(fp.read()))
|
||||||
|
|
||||||
def test_exists_worddocument(self):
|
def test_exists_worddocument(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PILLOW_VERSION "2.9.0.dev0"
|
#define PILLOW_VERSION "3.0.0.dev0"
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
version: 2.9.pre.{build}
|
version: 3.0.pre.{build}
|
||||||
shallow_clone: true
|
|
||||||
clone_folder: c:\pillow
|
clone_folder: c:\pillow
|
||||||
init:
|
init:
|
||||||
- ECHO %PYTHON%
|
- ECHO %PYTHON%
|
||||||
|
@ -25,3 +24,5 @@ test_script:
|
||||||
- cd c:\pillow
|
- cd c:\pillow
|
||||||
- '%PYTHON%\Scripts\pip.exe install nose'
|
- '%PYTHON%\Scripts\pip.exe install nose'
|
||||||
- '%PYTHON%\python.exe test-installed.py'
|
- '%PYTHON%\python.exe test-installed.py'
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
|
@ -77,8 +77,8 @@ Reading sequences
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The GIF loader supports the :py:meth:`~file.seek` and :py:meth:`~file.tell`
|
The GIF loader supports the :py:meth:`~file.seek` and :py:meth:`~file.tell`
|
||||||
methods. You can seek to the next frame (``im.seek(im.tell() + 1``), or rewind
|
methods. You can seek to the next frame (``im.seek(im.tell() + 1)``), or rewind
|
||||||
the file by seeking to the first frame. Random access is not supported.
|
the file by seeking to the first frame. Random access is not supported. ``im.seek()`` raises an ``EOFError`` if you try to seek after the last frame.
|
||||||
|
|
||||||
Reading local images
|
Reading local images
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -181,6 +181,18 @@ Instances of the :py:class:`Image` class have the following attributes:
|
||||||
|
|
||||||
:type: ``(width, height)``
|
: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
|
.. py:attribute:: palette
|
||||||
|
|
||||||
Colour palette table, if any. If mode is “P”, this should be an instance of
|
Colour palette table, if any. If mode is “P”, this should be an instance of
|
||||||
|
|
|
@ -234,16 +234,17 @@ Methods
|
||||||
:param xy: Top left corner of the text.
|
:param xy: Top left corner of the text.
|
||||||
:param text: Text to be drawn. If it contains any newline characters,
|
:param text: Text to be drawn. If it contains any newline characters,
|
||||||
the text is passed on to mulitiline_text()
|
the text is passed on to mulitiline_text()
|
||||||
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
|
||||||
:param fill: Color to use for the text.
|
:param fill: Color to use for the text.
|
||||||
|
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
||||||
|
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.Draw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left")
|
.. py:method:: PIL.ImageDraw.Draw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left")
|
||||||
|
|
||||||
Draws the string at the given position.
|
Draws the string at the given position.
|
||||||
|
|
||||||
:param xy: Top left corner of the text.
|
:param xy: Top left corner of the text.
|
||||||
:param text: Text to be drawn. If it contains any newline characters,
|
:param text: Text to be drawn.
|
||||||
the text is split and passed on to mulitiline_text()
|
:param fill: Color to use for the text.
|
||||||
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
||||||
:param spacing: The number of pixels between lines.
|
:param spacing: The number of pixels between lines.
|
||||||
:param align: "left", "center" or "right".
|
:param align: "left", "center" or "right".
|
||||||
|
@ -260,8 +261,7 @@ Methods
|
||||||
|
|
||||||
Return the size of the given string, in pixels.
|
Return the size of the given string, in pixels.
|
||||||
|
|
||||||
:param text: Text to be measured. If it contains any newline characters,
|
:param text: Text to be measured.
|
||||||
the text is split and passed on to mulitiline_textsize()
|
|
||||||
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
||||||
:param spacing: The number of pixels between lines.
|
:param spacing: The number of pixels between lines.
|
||||||
|
|
||||||
|
|
21
setup.py
21
setup.py
|
@ -90,7 +90,7 @@ except (ImportError, OSError):
|
||||||
|
|
||||||
|
|
||||||
NAME = 'Pillow'
|
NAME = 'Pillow'
|
||||||
PILLOW_VERSION = '2.9.0.dev0'
|
PILLOW_VERSION = '3.0.0.dev0'
|
||||||
TCL_ROOT = None
|
TCL_ROOT = None
|
||||||
JPEG_ROOT = None
|
JPEG_ROOT = None
|
||||||
JPEG2K_ROOT = None
|
JPEG2K_ROOT = None
|
||||||
|
@ -468,7 +468,7 @@ class pil_build_ext(build_ext):
|
||||||
feature.lcms = "lcms2_static"
|
feature.lcms = "lcms2_static"
|
||||||
|
|
||||||
if _tkinter and _find_include_file(self, "tk.h"):
|
if _tkinter and _find_include_file(self, "tk.h"):
|
||||||
# the library names may vary somewhat (e.g. tcl84 or tcl8.4)
|
# the library names may vary somewhat (e.g. tcl85 or tcl8.5)
|
||||||
version = TCL_VERSION[0] + TCL_VERSION[2]
|
version = TCL_VERSION[0] + TCL_VERSION[2]
|
||||||
if feature.want('tcl'):
|
if feature.want('tcl'):
|
||||||
if _find_library_file(self, "tcl" + version):
|
if _find_library_file(self, "tcl" + version):
|
||||||
|
@ -571,6 +571,7 @@ class pil_build_ext(build_ext):
|
||||||
exts.append(Extension(
|
exts.append(Extension(
|
||||||
"PIL._webp", ["_webp.c"], libraries=libs, define_macros=defs))
|
"PIL._webp", ["_webp.c"], libraries=libs, define_macros=defs))
|
||||||
|
|
||||||
|
if feature.tcl and feature.tk:
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
# locate Tcl/Tk frameworks
|
# locate Tcl/Tk frameworks
|
||||||
frameworks = []
|
frameworks = []
|
||||||
|
@ -578,22 +579,22 @@ class pil_build_ext(build_ext):
|
||||||
"/Library/Frameworks",
|
"/Library/Frameworks",
|
||||||
"/System/Library/Frameworks"]
|
"/System/Library/Frameworks"]
|
||||||
for root in framework_roots:
|
for root in framework_roots:
|
||||||
if (
|
root_tcl = os.path.join(root, "Tcl.framework")
|
||||||
os.path.exists(os.path.join(root, "Tcl.framework")) and
|
root_tk = os.path.join(root, "Tk.framework")
|
||||||
os.path.exists(os.path.join(root, "Tk.framework"))):
|
if (os.path.exists(root_tcl) and os.path.exists(root_tk)):
|
||||||
print("--- using frameworks at %s" % root)
|
print("--- using frameworks at %s" % root)
|
||||||
frameworks = ["-framework", "Tcl", "-framework", "Tk"]
|
frameworks = ["-framework", "Tcl", "-framework", "Tk"]
|
||||||
dir = os.path.join(root, "Tcl.framework", "Headers")
|
dir = os.path.join(root_tcl, "Headers")
|
||||||
_add_directory(self.compiler.include_dirs, dir, 0)
|
_add_directory(self.compiler.include_dirs, dir, 0)
|
||||||
dir = os.path.join(root, "Tk.framework", "Headers")
|
dir = os.path.join(root_tk, "Headers")
|
||||||
_add_directory(self.compiler.include_dirs, dir, 1)
|
_add_directory(self.compiler.include_dirs, dir, 1)
|
||||||
break
|
break
|
||||||
if frameworks:
|
if frameworks:
|
||||||
exts.append(Extension(
|
exts.append(Extension(
|
||||||
"PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
|
"PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
|
||||||
extra_compile_args=frameworks, extra_link_args=frameworks))
|
extra_compile_args=frameworks,
|
||||||
feature.tcl = feature.tk = 1 # mark as present
|
extra_link_args=frameworks))
|
||||||
elif feature.tcl and feature.tk:
|
else:
|
||||||
exts.append(Extension(
|
exts.append(Extension(
|
||||||
"PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
|
"PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"],
|
||||||
libraries=[feature.tcl, feature.tk]))
|
libraries=[feature.tcl, feature.tk]))
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -11,4 +11,4 @@ commands =
|
||||||
{envpython} setup.py clean
|
{envpython} setup.py clean
|
||||||
{envpython} setup.py build_ext --inplace
|
{envpython} setup.py build_ext --inplace
|
||||||
{envpython} selftest.py
|
{envpython} selftest.py
|
||||||
{envpython} Tests/run.py --installed
|
{envpython} test-installed.py --installed
|
||||||
|
|
|
@ -13,8 +13,8 @@ def setup_vms():
|
||||||
ret = []
|
ret = []
|
||||||
for py in pythons.keys():
|
for py in pythons.keys():
|
||||||
for arch in ('', X64_EXT):
|
for arch in ('', X64_EXT):
|
||||||
ret.append("virtualenv -p c:/Python%s%s/python.exe --clear %s%s%s" %
|
ret.append("virtualenv -p c:/Python%s%s/python.exe --clear %s%s%s"
|
||||||
(py, arch, VIRT_BASE, py, arch))
|
% (py, arch, VIRT_BASE, py, arch))
|
||||||
ret.append("%s%s%s\Scripts\pip.exe install nose" %
|
ret.append("%s%s%s\Scripts\pip.exe install nose" %
|
||||||
(VIRT_BASE, py, arch))
|
(VIRT_BASE, py, arch))
|
||||||
if py == '26':
|
if py == '26':
|
||||||
|
@ -109,13 +109,15 @@ def main(op):
|
||||||
scripts.append((py_version,
|
scripts.append((py_version,
|
||||||
"\n".join([header(op),
|
"\n".join([header(op),
|
||||||
build_one(py_version,
|
build_one(py_version,
|
||||||
compilers[(compiler_version, 32)]),
|
compilers[(compiler_version,
|
||||||
|
32)]),
|
||||||
footer()])))
|
footer()])))
|
||||||
|
|
||||||
scripts.append(("%s%s" % (py_version, X64_EXT),
|
scripts.append(("%s%s" % (py_version, X64_EXT),
|
||||||
"\n".join([header(op),
|
"\n".join([header(op),
|
||||||
build_one("%sx64" % py_version,
|
build_one("%sx64" % py_version,
|
||||||
compilers[(compiler_version, 64)]),
|
compilers[(compiler_version,
|
||||||
|
64)]),
|
||||||
footer()])))
|
footer()])))
|
||||||
|
|
||||||
results = map(run_script, scripts)
|
results = map(run_script, scripts)
|
||||||
|
|
|
@ -4,7 +4,7 @@ from untar import untar
|
||||||
import os
|
import os
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from config import *
|
from config import bin_libs, compilers, compiler_fromEnv, libs
|
||||||
|
|
||||||
|
|
||||||
def _relpath(*args):
|
def _relpath(*args):
|
||||||
|
@ -64,10 +64,12 @@ def fetch_libs():
|
||||||
if name == 'openjpeg':
|
if name == 'openjpeg':
|
||||||
filename = check_hash(fetch(lib['url']), lib['hash'])
|
filename = check_hash(fetch(lib['url']), lib['hash'])
|
||||||
for compiler in compilers.values():
|
for compiler in compilers.values():
|
||||||
if not os.path.exists(os.path.join(build_dir, lib['dir']+compiler['inc_dir'])):
|
if not os.path.exists(os.path.join(
|
||||||
|
build_dir, lib['dir']+compiler['inc_dir'])):
|
||||||
extract(filename, build_dir)
|
extract(filename, build_dir)
|
||||||
os.rename(os.path.join(build_dir, lib['dir']),
|
os.rename(os.path.join(build_dir, lib['dir']),
|
||||||
os.path.join(build_dir, lib['dir']+compiler['inc_dir']))
|
os.path.join(
|
||||||
|
build_dir, lib['dir']+compiler['inc_dir']))
|
||||||
else:
|
else:
|
||||||
extract(check_hash(fetch(lib['url']), lib['hash']), build_dir)
|
extract(check_hash(fetch(lib['url']), lib['hash']), build_dir)
|
||||||
|
|
||||||
|
@ -91,18 +93,19 @@ endlocal
|
||||||
""" % compiler
|
""" % compiler
|
||||||
|
|
||||||
|
|
||||||
def cp_tk():
|
def cp_tk(ver_85, ver_86):
|
||||||
|
versions = {'ver_85':ver_85, 'ver_86':ver_86}
|
||||||
return r"""
|
return r"""
|
||||||
mkdir %INCLIB%\tcl85\include\X11
|
mkdir %%INCLIB%%\tcl85\include\X11
|
||||||
copy /Y /B %BUILD%\tcl8.5.13\generic\*.h %INCLIB%\tcl85\include\
|
copy /Y /B %%BUILD%%\tcl%(ver_85)s\generic\*.h %%INCLIB%%\tcl85\include\
|
||||||
copy /Y /B %BUILD%\tk8.5.13\generic\*.h %INCLIB%\tcl85\include\
|
copy /Y /B %%BUILD%%\tk%(ver_85)s\generic\*.h %%INCLIB%%\tcl85\include\
|
||||||
copy /Y /B %BUILD%\tk8.5.13\xlib\X11\* %INCLIB%\tcl85\include\X11\
|
copy /Y /B %%BUILD%%\tk%(ver_85)s\xlib\X11\* %%INCLIB%%\tcl85\include\X11\
|
||||||
|
|
||||||
mkdir %INCLIB%\tcl86\include\X11
|
mkdir %%INCLIB%%\tcl86\include\X11
|
||||||
copy /Y /B %BUILD%\tcl8.6.4\generic\*.h %INCLIB%\tcl86\include\
|
copy /Y /B %%BUILD%%\tcl%(ver_86)s\generic\*.h %%INCLIB%%\tcl86\include\
|
||||||
copy /Y /B %BUILD%\tk8.6.4\generic\*.h %INCLIB%\tcl86\include\
|
copy /Y /B %%BUILD%%\tk%(ver_86)s\generic\*.h %%INCLIB%%\tcl86\include\
|
||||||
copy /Y /B %BUILD%\tk8.6.4\xlib\X11\* %INCLIB%\tcl86\include\X11\
|
copy /Y /B %%BUILD%%\tk%(ver_86)s\xlib\X11\* %%INCLIB%%\tcl86\include\X11\
|
||||||
"""
|
""" % versions
|
||||||
|
|
||||||
|
|
||||||
def header():
|
def header():
|
||||||
|
@ -305,7 +308,7 @@ def add_compiler(compiler):
|
||||||
mkdirs()
|
mkdirs()
|
||||||
fetch_libs()
|
fetch_libs()
|
||||||
# extract_binlib()
|
# 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:
|
if 'PYTHON' in os.environ:
|
||||||
|
|
|
@ -11,7 +11,8 @@ pythons = {#'26': 7,
|
||||||
VIRT_BASE = "c:/vp/"
|
VIRT_BASE = "c:/vp/"
|
||||||
X64_EXT = os.environ.get('X64_EXT', "x64")
|
X64_EXT = os.environ.get('X64_EXT', "x64")
|
||||||
|
|
||||||
libs = {'zlib': {
|
libs = {
|
||||||
|
'zlib': {
|
||||||
'url': 'http://zlib.net/zlib128.zip',
|
'url': 'http://zlib.net/zlib128.zip',
|
||||||
'hash': 'md5:126f8676442ffbd97884eb4d6f32afb4',
|
'hash': 'md5:126f8676442ffbd97884eb4d6f32afb4',
|
||||||
'dir': 'zlib-1.2.8',
|
'dir': 'zlib-1.2.8',
|
||||||
|
@ -22,9 +23,9 @@ libs = {'zlib': {
|
||||||
'dir': 'jpeg-9a',
|
'dir': 'jpeg-9a',
|
||||||
},
|
},
|
||||||
'tiff': {
|
'tiff': {
|
||||||
'url': 'ftp://ftp.remotesensing.org/pub/libtiff/tiff-4.0.3.zip',
|
'url': 'ftp://ftp.remotesensing.org/pub/libtiff/tiff-4.0.4.zip',
|
||||||
'hash': 'md5:dd70349cedb3981371686e1c9b89a7f9', # not found - generated by wiredfool
|
'hash': 'md5:8f538a34156188f9a8dcddb679c65d1e',
|
||||||
'dir': 'tiff-4.0.3',
|
'dir': 'tiff-4.0.4',
|
||||||
},
|
},
|
||||||
'freetype': {
|
'freetype': {
|
||||||
'url': 'http://download.savannah.gnu.org/releases/freetype/freetype-2.6.tar.gz',
|
'url': 'http://download.savannah.gnu.org/releases/freetype/freetype-2.6.tar.gz',
|
||||||
|
@ -37,14 +38,15 @@ libs = {'zlib': {
|
||||||
'dir': 'lcms2-2.7',
|
'dir': 'lcms2-2.7',
|
||||||
},
|
},
|
||||||
'tcl-8.5': {
|
'tcl-8.5': {
|
||||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.5.13/tcl8513-src.zip',
|
'url': SF_MIRROR+'/project/tcl/Tcl/8.5.18/tcl8518-src.zip',
|
||||||
'hash': 'sha1:3e01585c91293c532a3cd594ec59deca92153a5e',
|
'hash': 'sha1:4c2aed9043088c630a4c795265e2738ef1b4db3b',
|
||||||
'dir': '',
|
'dir': '',
|
||||||
},
|
},
|
||||||
'tk-8.5': {
|
'tk-8.5': {
|
||||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.5.13/tk8513-src.zip',
|
'url': SF_MIRROR+'/project/tcl/Tcl/8.5.18/tk8518-src.zip',
|
||||||
'hash': 'sha1:23a1d7ddd416e11e06dfdb9f86111d4bab9420b4',
|
'hash': 'sha1:273f55148777413774aa722ecad25cabda1e31ae',
|
||||||
'dir': '',
|
'dir': '',
|
||||||
|
'version':'8.5.18',
|
||||||
},
|
},
|
||||||
'tcl-8.6': {
|
'tcl-8.6': {
|
||||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.4/tcl864-src.zip',
|
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.4/tcl864-src.zip',
|
||||||
|
@ -55,19 +57,18 @@ libs = {'zlib': {
|
||||||
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.4/tk864-src.zip',
|
'url': SF_MIRROR+'/project/tcl/Tcl/8.6.4/tk864-src.zip',
|
||||||
'hash': 'md5:111d45061a69e7f5250b6ec8ca7c4f35',
|
'hash': 'md5:111d45061a69e7f5250b6ec8ca7c4f35',
|
||||||
'dir': '',
|
'dir': '',
|
||||||
|
'version':'8.6.4',
|
||||||
},
|
},
|
||||||
'webp': {
|
'webp': {
|
||||||
'url': 'http://downloads.webmproject.org/releases/webp/libwebp-0.4.3.tar.gz',
|
'url': 'http://downloads.webmproject.org/releases/webp/libwebp-0.4.3.tar.gz',
|
||||||
'hash': 'sha1:1c307a61c4d0018620b4ba9a58e8f48a8d6640ef',
|
'hash': 'sha1:1c307a61c4d0018620b4ba9a58e8f48a8d6640ef',
|
||||||
'dir': 'libwebp-0.4.3',
|
'dir': 'libwebp-0.4.3',
|
||||||
|
|
||||||
},
|
},
|
||||||
'openjpeg': {
|
'openjpeg': {
|
||||||
'url': SF_MIRROR+'/project/openjpeg/openjpeg/2.1.0/openjpeg-2.1.0.tar.gz',
|
'url': SF_MIRROR+'/project/openjpeg/openjpeg/2.1.0/openjpeg-2.1.0.tar.gz',
|
||||||
'hash': 'md5:f6419fcc233df84f9a81eb36633c6db6',
|
'hash': 'md5:f6419fcc233df84f9a81eb36633c6db6',
|
||||||
'dir': 'openjpeg-2.1.0',
|
'dir': 'openjpeg-2.1.0',
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bin_libs = {
|
bin_libs = {
|
||||||
|
@ -78,7 +79,8 @@ bin_libs = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
compilers = {(7, 64): {
|
compilers = {
|
||||||
|
(7, 64): {
|
||||||
'env_version': 'v7.0',
|
'env_version': 'v7.0',
|
||||||
'vc_version': '2008',
|
'vc_version': '2008',
|
||||||
'env_flags': '/x64 /xp',
|
'env_flags': '/x64 /xp',
|
||||||
|
@ -94,7 +96,6 @@ compilers = {(7, 64): {
|
||||||
'platform': 'Win32',
|
'platform': 'Win32',
|
||||||
'webp_platform': 'x86',
|
'webp_platform': 'x86',
|
||||||
},
|
},
|
||||||
|
|
||||||
(7.1, 64): {
|
(7.1, 64): {
|
||||||
'env_version': 'v7.1',
|
'env_version': 'v7.1',
|
||||||
'vc_version': '2010',
|
'vc_version': '2010',
|
||||||
|
@ -111,7 +112,6 @@ compilers = {(7, 64): {
|
||||||
'platform': 'Win32',
|
'platform': 'Win32',
|
||||||
'webp_platform': 'x86',
|
'webp_platform': 'x86',
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ if __name__ == '__main__':
|
||||||
for version in ['2.6.5', '2.7.6', '3.2.5', '3.3.5', '3.4.3']:
|
for version in ['2.6.5', '2.7.6', '3.2.5', '3.3.5', '3.4.3']:
|
||||||
for platform in ['', '.amd64']:
|
for platform in ['', '.amd64']:
|
||||||
for extension in ['', '.asc']:
|
for extension in ['', '.asc']:
|
||||||
fetch('https://www.python.org/ftp/python/%s/python-%s%s.msi%s' % (
|
fetch('https://www.python.org/ftp/python/%s/python-%s%s.msi%s'
|
||||||
version, version, platform, extension))
|
% (version, version, platform, extension))
|
||||||
|
|
||||||
# find pip, if it's not in the path!
|
# find pip, if it's not in the path!
|
||||||
os.system('pip install virtualenv')
|
os.system('pip install virtualenv')
|
||||||
|
|
|
@ -5,14 +5,15 @@ import os
|
||||||
import glob
|
import glob
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from config import *
|
from config import pythons, VIRT_BASE, X64_EXT
|
||||||
|
|
||||||
|
|
||||||
def test_one(params):
|
def test_one(params):
|
||||||
python, architecture = params
|
python, architecture = params
|
||||||
try:
|
try:
|
||||||
print("Running: %s, %s" % params)
|
print("Running: %s, %s" % params)
|
||||||
command = [r'%s\%s%s\Scripts\python.exe' % (VIRT_BASE, python, architecture),
|
command = [r'%s\%s%s\Scripts\python.exe' %
|
||||||
|
(VIRT_BASE, python, architecture),
|
||||||
'test-installed.py',
|
'test-installed.py',
|
||||||
'--processes=-0',
|
'--processes=-0',
|
||||||
'--process-timeout=30',
|
'--process-timeout=30',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user