Merge branch 'master' into winbuild

This commit is contained in:
wiredfool 2014-06-05 00:15:58 +00:00
commit 64efea9ed8
34 changed files with 845 additions and 425 deletions

11
.coveragerc Normal file
View File

@ -0,0 +1,11 @@
# .coveragerc to control coverage.py
[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma:
pragma: no cover
# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:

View File

@ -26,8 +26,14 @@ script:
- coverage erase
- python setup.py clean
- python setup.py build_ext --inplace
- coverage run --append --include=PIL/* selftest.py
- python Tests/run.py --coverage
# Don't cover PyPy: it fails intermittently and is x5.8 slower (#640)
- if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then python selftest.py; fi
- if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then python Tests/run.py; fi
# Cover the others
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then coverage run --append --include=PIL/* selftest.py; fi
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then python Tests/run.py --coverage; fi
after_success:
- coverage report
@ -35,8 +41,5 @@ after_success:
- pip install pep8 pyflakes
- pep8 PIL/*.py
- pyflakes PIL/*.py
matrix:
allow_failures:
- python: "pypy"
- python: 3.4
- pep8 Tests/*.py
- pyflakes Tests/*.py

View File

@ -3,6 +3,41 @@ Changelog (Pillow)
2.5.0 (unreleased)
------------------
- Added tests for Spider files
[hugovk]
- Use libtiff to write any compressed tiff files
[wiredfool]
- Support for pickling Image objects
[hugovk]
- Fixed resolution handling for EPS thumbnails
[eliempje]
- Fixed rendering of some binary EPS files (Issue #302)
[eliempje]
- Rename variables not to use built-in function names
[hugovk]
- Ignore junk JPEG markers
[hugovk]
- Change default interpolation for Image.thumbnail to Image.ANTIALIAS
[hugovk]
- Add tests and fixes for saving PDFs
[hugovk]
- Remove transparency resource after P->RGBA conversion
[hugovk]
- Clean up preprocessor cruft for Windows
[CounterPillow]
- Adjust Homebrew freetype detection logic
[jacknagel]
- Added Image.close, context manager support.
[wiredfool]

View File

@ -11,6 +11,7 @@
# 1996-08-23 fl Handle files from Macintosh (0.3)
# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4)
# 2003-09-07 fl Check gs.close status (from Federico Di Gregorio) (0.5)
# 2014-05-07 e Handling of EPS with binary preview and fixed resolution resizing
#
# Copyright (c) 1997-2003 by Secret Labs AB.
# Copyright (c) 1995-2003 by Fredrik Lundh
@ -77,8 +78,9 @@ def Ghostscript(tile, size, fp, scale=1):
orig_size = size
orig_bbox = bbox
size = (size[0] * scale, size[1] * scale)
bbox = [bbox[0], bbox[1], bbox[2] * scale, bbox[3] * scale]
#print("Ghostscript", scale, size, orig_size, bbox, orig_bbox)
# resolution is dependend on bbox and size
res = ( float((72.0 * size[0]) / (bbox[2]-bbox[0])), float((72.0 * size[1]) / (bbox[3]-bbox[1])) )
#print("Ghostscript", scale, size, orig_size, bbox, orig_bbox, res)
import tempfile, os, subprocess
@ -87,20 +89,29 @@ def Ghostscript(tile, size, fp, scale=1):
in_fd, infile = tempfile.mkstemp()
os.close(in_fd)
# ignore length and offset!
# ghostscript can read it
# copy whole file to read in ghostscript
with open(infile, 'wb') as f:
fp.seek(offset)
while length >0:
s = fp.read(100*1024)
# fetch length of fp
fp.seek(0, 2)
fsize = fp.tell()
# ensure start position
# go back
fp.seek(0)
lengthfile = fsize
while lengthfile > 0:
s = fp.read(min(lengthfile, 100*1024))
if not s:
break
length = length - len(s)
lengthfile = lengthfile - len(s)
f.write(s)
# Build ghostscript command
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%d" % (72*scale), # set input DPI (dots per inch)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dNOPAUSE -dSAFER", # don't pause between pages, safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
@ -145,6 +156,8 @@ class PSFile:
self.fp.seek(offset, whence)
def read(self, count):
return self.fp.read(count).decode('latin-1')
def readbinary(self, count):
return self.fp.read(count)
def tell(self):
pos = self.fp.tell()
if self.char:
@ -182,24 +195,32 @@ class EpsImageFile(ImageFile.ImageFile):
def _open(self):
# FIXME: should check the first 512 bytes to see if this
# really is necessary (platform-dependent, though...)
fp = PSFile(self.fp)
# HEAD
s = fp.read(512)
# FIX for: Some EPS file not handled correctly / issue #302
# EPS can contain binary data
# or start directly with latin coding
# read header in both ways to handle both
# file types
# more info see http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
# for HEAD without binary preview
s = fp.read(4)
# for HEAD with binary preview
fp.seek(0)
sb = fp.readbinary(160)
if s[:4] == "%!PS":
offset = 0
fp.seek(0, 2)
length = fp.tell()
elif i32(s) == 0xC6D3D0C5:
offset = i32(s[4:])
length = i32(s[8:])
fp.seek(offset)
offset = 0
elif i32(sb[0:4]) == 0xC6D3D0C5:
offset = i32(sb[4:8])
length = i32(sb[8:12])
else:
raise SyntaxError("not an EPS file")
# go to offset - start of "%!PS"
fp.seek(offset)
box = None

View File

@ -30,6 +30,7 @@ from PIL import VERSION, PILLOW_VERSION, _plugins
import warnings
class _imaging_not_installed:
# module placeholder
def __getattr__(self, id):
@ -52,8 +53,8 @@ try:
# directly; import Image and use the Image.core variable instead.
from PIL import _imaging as core
if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None):
raise ImportError("The _imaging extension was built for another "
" version of Pillow or PIL")
raise ImportError("The _imaging extension was built for another "
" version of Pillow or PIL")
except ImportError as v:
core = _imaging_not_installed()
@ -91,10 +92,13 @@ except ImportError:
builtins = __builtin__
from PIL import ImageMode
from PIL._binary import i8, o8
from PIL._util import isPath, isStringType, deferred_error
from PIL._binary import i8
from PIL._util import isPath
from PIL._util import isStringType
from PIL._util import deferred_error
import os, sys
import os
import sys
# type stuff
import collections
@ -104,9 +108,10 @@ import numbers
USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info')
try:
import cffi
HAS_CFFI=True
HAS_CFFI = True
except:
HAS_CFFI=False
HAS_CFFI = False
def isImageType(t):
"""
@ -148,16 +153,16 @@ MESH = 4
# resampling filters
NONE = 0
NEAREST = 0
ANTIALIAS = 1 # 3-lobed lanczos
ANTIALIAS = 1 # 3-lobed lanczos
LINEAR = BILINEAR = 2
CUBIC = BICUBIC = 3
# dithers
NONE = 0
NEAREST = 0
ORDERED = 1 # Not yet implemented
RASTERIZE = 2 # Not yet implemented
FLOYDSTEINBERG = 3 # default
ORDERED = 1 # Not yet implemented
RASTERIZE = 2 # Not yet implemented
FLOYDSTEINBERG = 3 # default
# palettes/quantizers
WEB = 0
@ -222,7 +227,7 @@ else:
_MODE_CONV = {
# official modes
"1": ('|b1', None), # broken
"1": ('|b1', None), # broken
"L": ('|u1', None),
"I": (_ENDIAN + 'i4', None),
"F": (_ENDIAN + 'f4', None),
@ -232,8 +237,8 @@ _MODE_CONV = {
"RGBA": ('|u1', 4),
"CMYK": ('|u1', 4),
"YCbCr": ('|u1', 3),
"LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1
# I;16 == I;16L, and I;32 == I;32L
"LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1
# I;16 == I;16L, and I;32 == I;32L
"I;16": ('<u2', None),
"I;16B": ('>u2', None),
"I;16L": ('<u2', None),
@ -248,6 +253,7 @@ _MODE_CONV = {
"I;32LS": ('<i4', None),
}
def _conv_type_shape(im):
shape = im.size[1], im.size[0]
typ, extra = _MODE_CONV[im.mode]
@ -368,8 +374,8 @@ def init():
for plugin in _plugins:
try:
if DEBUG:
print ("Importing %s"%plugin)
__import__("PIL.%s"%plugin, globals(), locals(), [])
print ("Importing %s" % plugin)
__import__("PIL.%s" % plugin, globals(), locals(), [])
except ImportError:
if DEBUG:
print("Image: failed to import", end=' ')
@ -379,6 +385,7 @@ def init():
_initialized = 2
return 1
# --------------------------------------------------------------------
# Codec factories (used by tobytes/frombytes and ImageFile.load)
@ -398,6 +405,7 @@ def _getdecoder(mode, decoder_name, args, extra=()):
except AttributeError:
raise IOError("decoder %s not available" % decoder_name)
def _getencoder(mode, encoder_name, args, extra=()):
# tweak arguments
@ -421,30 +429,36 @@ def _getencoder(mode, encoder_name, args, extra=()):
def coerce_e(value):
return value if isinstance(value, _E) else _E(value)
class _E:
def __init__(self, data):
self.data = data
def __add__(self, other):
return _E((self.data, "__add__", coerce_e(other).data))
def __mul__(self, other):
return _E((self.data, "__mul__", coerce_e(other).data))
def _getscaleoffset(expr):
stub = ["stub"]
data = expr(_E(stub)).data
try:
(a, b, c) = data # simplified syntax
(a, b, c) = data # simplified syntax
if (a is stub and b == "__mul__" and isinstance(c, numbers.Number)):
return c, 0.0
if (a is stub and b == "__add__" and isinstance(c, numbers.Number)):
return 1.0, c
except TypeError: pass
except TypeError:
pass
try:
((a, b, c), d, e) = data # full syntax
((a, b, c), d, e) = data # full syntax
if (a is stub and b == "__mul__" and isinstance(c, numbers.Number) and
d == "__add__" and isinstance(e, numbers.Number)):
d == "__add__" and isinstance(e, numbers.Number)):
return c, e
except TypeError: pass
except TypeError:
pass
raise ValueError("illegal expression")
@ -495,11 +509,12 @@ class Image:
new.info[k] = v
return new
_makeself = _new # compatibility
_makeself = _new # compatibility
# Context Manager Support
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
@ -518,14 +533,13 @@ class Image:
self.fp.close()
except Exception as msg:
if Image.DEBUG:
print ("Error closing: %s" %msg)
print ("Error closing: %s" % msg)
# Instead of simply setting to None, we're setting up a
# deferred error that will better explain that the core image
# object is gone.
self.im = deferred_error(ValueError("Operation on closed image"))
def _copy(self):
self.load()
self.im = self.im.copy()
@ -533,7 +547,8 @@ class Image:
self.readonly = 0
def _dump(self, file=None, format=None):
import tempfile, os
import os
import tempfile
suffix = ''
if format:
suffix = '.'+format
@ -550,6 +565,20 @@ class Image:
self.save(file, format)
return file
def __eq__(self, other):
a = (self.mode == other.mode)
b = (self.size == other.size)
c = (self.getpalette() == other.getpalette())
d = (self.info == other.info)
e = (self.category == other.category)
f = (self.readonly == other.readonly)
g = (self.tobytes() == other.tobytes())
return a and b and c and d and e and f and g
def __ne__(self, other):
eq = (self == other)
return not eq
def __repr__(self):
return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
self.__class__.__module__, self.__class__.__name__,
@ -568,6 +597,26 @@ class Image:
return new
raise AttributeError(name)
def __getstate__(self):
return [
self.info,
self.mode,
self.size,
self.getpalette(),
self.tobytes()]
def __setstate__(self, state):
Image.__init__(self)
self.tile = []
info, mode, size, palette, data = state
self.info = info
self.mode = mode
self.size = size
self.im = core.new(mode, size)
if mode in ("L", "P"):
self.putpalette(palette)
self.frombytes(data)
def tobytes(self, encoder_name="raw", *args):
"""
Return image as a bytes object
@ -591,7 +640,7 @@ class Image:
e = _getencoder(self.mode, encoder_name, args)
e.setimage(self.im)
bufsize = max(65536, self.size[0] * 4) # see RawEncode.c
bufsize = max(65536, self.size[0] * 4) # see RawEncode.c
data = []
while True:
@ -628,9 +677,11 @@ class Image:
if self.mode != "1":
raise ValueError("not a bitmap")
data = self.tobytes("xbm")
return b"".join([("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
("#define %s_height %d\n"% (name, self.size[1])).encode('ascii'),
("static char %s_bits[] = {\n" % name).encode('ascii'), data, b"};"])
return b"".join([
("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
("#define %s_height %d\n" % (name, self.size[1])).encode('ascii'),
("static char %s_bits[] = {\n" % name).encode('ascii'), data, b"};"
])
def frombytes(self, data, decoder_name="raw", *args):
"""
@ -663,7 +714,9 @@ class Image:
.. deprecated:: 2.0
"""
warnings.warn('fromstring() is deprecated. Please call frombytes() instead.', DeprecationWarning)
warnings.warn(
'fromstring() is deprecated. Please call frombytes() instead.',
DeprecationWarning)
return self.frombytes(*args, **kw)
def load(self):
@ -774,28 +827,29 @@ class Image:
trns = None
delete_trns = False
# transparency handling
if "transparency" in self.info and self.info['transparency'] is not None:
if "transparency" in self.info and \
self.info['transparency'] is not None:
if self.mode in ('L', 'RGB') and mode == 'RGBA':
# Use transparent conversion to promote from transparent
# color to an alpha channel.
return self._new(self.im.convert_transparent(
mode, self.info['transparency']))
mode, self.info['transparency']))
elif self.mode in ('L', 'RGB', 'P') and mode in ('L', 'RGB', 'P'):
t = self.info['transparency']
if isinstance(t, bytes):
# Dragons. This can't be represented by a single color
warnings.warn('Palette images with Transparency expressed '+
warnings.warn('Palette images with Transparency expressed ' +
' in bytes should be converted to RGBA images')
delete_trns = True
else:
# get the new transparency color.
# use existing conversions
trns_im = Image()._new(core.new(self.mode, (1,1)))
trns_im = Image()._new(core.new(self.mode, (1, 1)))
if self.mode == 'P':
trns_im.putpalette(self.palette)
trns_im.putpixel((0,0), t)
trns_im.putpixel((0, 0), t)
if mode in ('L','RGB'):
if mode in ('L', 'RGB'):
trns_im = trns_im.convert(mode)
else:
# can't just retrieve the palette number, got to do it
@ -803,6 +857,8 @@ class Image:
trns_im = trns_im.convert('RGB')
trns = trns_im.getpixel((0,0))
elif self.mode == 'P' and mode == 'RGBA':
delete_trns = True
if mode == "P" and palette == ADAPTIVE:
im = self.im.quantize(colors)
@ -820,7 +876,8 @@ class Image:
# if we can't make a transparent color, don't leave the old
# transparency hanging around to mess us up.
del(new.info['transparency'])
warnings.warn("Couldn't allocate palette entry for transparency")
warnings.warn("Couldn't allocate palette entry " +
"for transparency")
return new
# colorspace conversion
@ -839,7 +896,7 @@ class Image:
new_im = self._new(im)
if delete_trns:
#crash fail if we leave a bytes transparency in an rgb/l mode.
# crash fail if we leave a bytes transparency in an rgb/l mode.
del(new_im.info['transparency'])
if trns is not None:
if new_im.mode == 'P':
@ -847,7 +904,8 @@ class Image:
new_im.info['transparency'] = new_im.palette.getcolor(trns)
except:
del(new_im.info['transparency'])
warnings.warn("Couldn't allocate palette entry for transparency")
warnings.warn("Couldn't allocate palette entry " +
"for transparency")
else:
new_im.info['transparency'] = trns
return new_im
@ -963,7 +1021,8 @@ class Image:
if isinstance(filter, collections.Callable):
filter = filter()
if not hasattr(filter, "filter"):
raise TypeError("filter argument should be ImageFilter.Filter instance or class")
raise TypeError("filter argument should be ImageFilter.Filter " +
"instance or class")
if self.im.bands == 1:
return self._new(filter.filter(self.im))
@ -1019,7 +1078,7 @@ class Image:
return out
return self.im.getcolors(maxcolors)
def getdata(self, band = None):
def getdata(self, band=None):
"""
Returns the contents of this image as a sequence object
containing pixel values. The sequence object is flattened, so
@ -1040,7 +1099,7 @@ class Image:
self.load()
if band is not None:
return self.im.getband(band)
return self.im # could be abused
return self.im # could be abused
def getextrema(self):
"""
@ -1070,7 +1129,6 @@ class Image:
self.load()
return self.im.ptr
def getpalette(self):
"""
Returns the image palette as a list.
@ -1086,8 +1144,7 @@ class Image:
else:
return list(self.im.getpalette())
except ValueError:
return None # no palette
return None # no palette
def getpixel(self, xy):
"""
@ -1209,7 +1266,8 @@ class Image:
if isImageType(box) and mask is None:
# abbreviated paste(im, mask) syntax
mask = box; box = None
mask = box
box = None
if box is None:
# cover all of self
@ -1315,7 +1373,7 @@ class Image:
# do things the hard way
im = self.im.convert(mode)
if im.mode not in ("LA", "RGBA"):
raise ValueError # sanity check
raise ValueError # sanity check
self.im = im
self.pyaccess = None
self.mode = self.im.mode
@ -1393,7 +1451,7 @@ class Image:
self.mode = "P"
self.palette = palette
self.palette.mode = "RGB"
self.load() # install new palette
self.load() # install new palette
def putpixel(self, xy, value):
"""
@ -1422,7 +1480,7 @@ class Image:
self.load()
if self.pyaccess:
return self.pyaccess.putpixel(xy,value)
return self.pyaccess.putpixel(xy, value)
return self.im.putpixel(xy, value)
def resize(self, size, resample=NEAREST):
@ -1489,9 +1547,11 @@ class Image:
import math
angle = -angle * math.pi / 180
matrix = [
math.cos(angle), math.sin(angle), 0.0,
math.cos(angle), math.sin(angle), 0.0,
-math.sin(angle), math.cos(angle), 0.0
]
]
def transform(x, y, matrix=matrix):
(a, b, c, d, e, f) = matrix
return a*x + b*y + c, d*x + e*y + f
@ -1579,13 +1639,13 @@ class Image:
try:
format = EXTENSION[ext]
except KeyError:
raise KeyError(ext) # unknown extension
raise KeyError(ext) # unknown extension
try:
save_handler = SAVE[format.upper()]
except KeyError:
init()
save_handler = SAVE[format.upper()] # unknown format
save_handler = SAVE[format.upper()] # unknown format
if isPath(fp):
fp = builtins.open(fp, "wb")
@ -1667,7 +1727,7 @@ class Image:
"""
return 0
def thumbnail(self, size, resample=NEAREST):
def thumbnail(self, size, resample=ANTIALIAS):
"""
Make this image into a thumbnail. This method modifies the
image to contain a thumbnail version of itself, no larger than
@ -1682,26 +1742,28 @@ class Image:
important than quality.
Also note that this function modifies the :py:class:`~PIL.Image.Image`
object in place. If you need to use the full resolution image as well, apply
this method to a :py:meth:`~PIL.Image.Image.copy` of the original image.
object in place. If you need to use the full resolution image as well,
apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
image.
:param size: Requested size.
:param resample: Optional resampling filter. This can be one
of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
:py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.ANTIALIAS`
(best quality). If omitted, it defaults to
:py:attr:`PIL.Image.NEAREST` (this will be changed to ANTIALIAS in a
future version).
:py:attr:`PIL.Image.ANTIALIAS`. (was :py:attr:`PIL.Image.NEAREST`
prior to version 2.5.0)
:returns: None
"""
# FIXME: the default resampling filter will be changed
# to ANTIALIAS in future versions
# preserve aspect ratio
x, y = self.size
if x > size[0]: y = int(max(y * size[0] / x, 1)); x = int(size[0])
if y > size[1]: x = int(max(x * size[1] / y, 1)); y = int(size[1])
if x > size[0]:
y = int(max(y * size[0] / x, 1))
x = int(size[0])
if y > size[1]:
x = int(max(x * size[1] / y, 1))
y = int(size[1])
size = x, y
if size == self.size:
@ -1716,7 +1778,7 @@ class Image:
except ValueError:
if resample != ANTIALIAS:
raise
im = self.resize(size, NEAREST) # fallback
im = self.resize(size, NEAREST) # fallback
self.im = im.im
self.mode = im.mode
@ -1752,7 +1814,8 @@ class Image:
"""
if self.mode == 'RGBA':
return self.convert('RGBa').transform(size, method, data, resample, fill).convert('RGBA')
return self.convert('RGBa').transform(
size, method, data, resample, fill).convert('RGBA')
if isinstance(method, ImageTransformHandler):
return method.transform(size, self, resample=resample, fill=fill)
@ -1799,8 +1862,13 @@ class Image:
elif method == QUAD:
# quadrilateral warp. data specifies the four corners
# given as NW, SW, SE, and NE.
nw = data[0:2]; sw = data[2:4]; se = data[4:6]; ne = data[6:8]
x0, y0 = nw; As = 1.0 / w; At = 1.0 / h
nw = data[0:2]
sw = data[2:4]
se = data[4:6]
ne = data[6:8]
x0, y0 = nw
As = 1.0 / w
At = 1.0 / h
data = (x0, (ne[0]-x0)*As, (sw[0]-x0)*At,
(se[0]-sw[0]-ne[0]+x0)*As*At,
y0, (ne[1]-y0)*As, (sw[1]-y0)*At,
@ -1834,6 +1902,7 @@ class Image:
im = self.im.transpose(method)
return self._new(im)
# --------------------------------------------------------------------
# Lazy operations
@ -1869,6 +1938,7 @@ class _ImageCrop(Image):
# FIXME: future versions should optimize crop/paste
# sequences!
# --------------------------------------------------------------------
# Abstract handlers.
@ -1876,10 +1946,12 @@ class ImagePointHandler:
# used as a mixin by point transforms (for use with im.point)
pass
class ImageTransformHandler:
# used as a mixin by geometry transforms (for use with im.transform)
pass
# --------------------------------------------------------------------
# Factories
@ -1955,6 +2027,7 @@ def frombytes(mode, size, data, decoder_name="raw", *args):
im.frombytes(data, decoder_name, args)
return im
def fromstring(*args, **kw):
"""Deprecated alias to frombytes.
@ -2017,9 +2090,9 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
" frombuffer(mode, size, data, 'raw', mode, 0, 1)",
RuntimeWarning, stacklevel=2
)
args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6
args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6
if args[0] in _MAPMODES:
im = new(mode, (1,1))
im = new(mode, (1, 1))
im = im._new(
core.map_buffer(data, size, decoder_name, None, 0, args)
)
@ -2139,8 +2212,8 @@ def open(fp, mode="r"):
fp.seek(0)
return factory(fp, filename)
except (SyntaxError, IndexError, TypeError):
#import traceback
#traceback.print_exc()
# import traceback
# traceback.print_exc()
pass
if init():
@ -2152,13 +2225,14 @@ def open(fp, mode="r"):
fp.seek(0)
return factory(fp, filename)
except (SyntaxError, IndexError, TypeError):
#import traceback
#traceback.print_exc()
# import traceback
# traceback.print_exc()
pass
raise IOError("cannot identify image file %r"
% (filename if filename else fp))
#
# Image processing.
@ -2257,6 +2331,7 @@ def merge(mode, bands):
im.putband(bands[i].im, i)
return bands[0]._new(im)
# --------------------------------------------------------------------
# Plugin registry
@ -2315,6 +2390,7 @@ def _show(image, **options):
# override me, as necessary
_showxv(image, **options)
def _showxv(image, title=None, **options):
from PIL import ImageShow
ImageShow.show(image, title, **options)

View File

@ -34,7 +34,8 @@
__version__ = "0.6"
import array, struct
import array
import struct
from PIL import Image, ImageFile, _binary
from PIL.JpegPresets import presets
from PIL._util import isStringType
@ -44,6 +45,7 @@ o8 = _binary.o8
i16 = _binary.i16be
i32 = _binary.i32be
#
# Parser
@ -51,6 +53,7 @@ def Skip(self, marker):
n = i16(self.fp.read(2))-2
ImageFile._safe_read(self.fp, n)
def APP(self, marker):
#
# Application marker. Store these in the APP dictionary.
@ -59,14 +62,14 @@ def APP(self, marker):
n = i16(self.fp.read(2))-2
s = ImageFile._safe_read(self.fp, n)
app = "APP%d" % (marker&15)
app = "APP%d" % (marker & 15)
self.app[app] = s # compatibility
self.app[app] = s # compatibility
self.applist.append((app, s))
if marker == 0xFFE0 and s[:4] == b"JFIF":
# extract JFIF information
self.info["jfif"] = version = i16(s, 5) # version
self.info["jfif"] = version = i16(s, 5) # version
self.info["jfif_version"] = divmod(version, 256)
# extract JFIF properties
try:
@ -81,10 +84,10 @@ def APP(self, marker):
self.info["jfif_density"] = jfif_density
elif marker == 0xFFE1 and s[:5] == b"Exif\0":
# extract Exif information (incomplete)
self.info["exif"] = s # FIXME: value will change
self.info["exif"] = s # FIXME: value will change
elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
# extract FlashPix information (incomplete)
self.info["flashpix"] = s # FIXME: value will change
self.info["flashpix"] = s # FIXME: value will change
elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
# Since an ICC profile can be larger than the maximum size of
# a JPEG marker (64K), we need provisions to split it into
@ -108,16 +111,17 @@ def APP(self, marker):
else:
self.info["adobe_transform"] = adobe_transform
def COM(self, marker):
#
# Comment marker. Store these in the APP dictionary.
n = i16(self.fp.read(2))-2
s = ImageFile._safe_read(self.fp, n)
self.app["COM"] = s # compatibility
self.app["COM"] = s # compatibility
self.applist.append(("COM", s))
def SOF(self, marker):
#
# Start of frame marker. Defines the size and mode of the
@ -149,21 +153,22 @@ def SOF(self, marker):
if self.icclist:
# fixup icc profile
self.icclist.sort() # sort by sequence number
self.icclist.sort() # sort by sequence number
if i8(self.icclist[0][13]) == len(self.icclist):
profile = []
for p in self.icclist:
profile.append(p[14:])
icc_profile = b"".join(profile)
else:
icc_profile = None # wrong number of fragments
icc_profile = None # wrong number of fragments
self.info["icc_profile"] = icc_profile
self.icclist = None
for i in range(6, len(s), 3):
t = s[i:i+3]
# 4-tuples: id, vsamp, hsamp, qtable
self.layer.append((t[0], i8(t[1])//16, i8(t[1])&15, i8(t[2])))
self.layer.append((t[0], i8(t[1])//16, i8(t[1]) & 15, i8(t[2])))
def DQT(self, marker):
#
@ -181,10 +186,10 @@ def DQT(self, marker):
raise SyntaxError("bad quantization table marker")
v = i8(s[0])
if v//16 == 0:
self.quantization[v&15] = array.array("b", s[1:65])
self.quantization[v & 15] = array.array("b", s[1:65])
s = s[65:]
else:
return # FIXME: add code to read 16-bit tables!
return # FIXME: add code to read 16-bit tables!
# raise SyntaxError, "bad quantization table element size"
@ -261,6 +266,7 @@ MARKER = {
def _accept(prefix):
return prefix[0:1] == b"\377"
##
# Image plugin for JPEG and JFIF images.
@ -284,32 +290,37 @@ class JpegImageFile(ImageFile.ImageFile):
self.huffman_dc = {}
self.huffman_ac = {}
self.quantization = {}
self.app = {} # compatibility
self.app = {} # compatibility
self.applist = []
self.icclist = []
while True:
s = s + self.fp.read(1)
i = i16(s)
i = i8(s)
if i == 0xFF:
s = s + self.fp.read(1)
i = i16(s)
else:
# Skip non-0xFF junk
s = b"\xff"
continue
if i in MARKER:
name, description, handler = MARKER[i]
# print hex(i), name, description
if handler is not None:
handler(self, i)
if i == 0xFFDA: # start of scan
if i == 0xFFDA: # start of scan
rawmode = self.mode
if self.mode == "CMYK":
rawmode = "CMYK;I" # assume adobe conventions
self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
rawmode = "CMYK;I" # assume adobe conventions
self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))]
# self.__offset = self.fp.tell()
break
s = self.fp.read(1)
elif i == 0 or i == 65535:
elif i == 0 or i == 0xFFFF:
# padded marker or junk; move on
s = "\xff"
s = b"\xff"
else:
raise SyntaxError("no marker found")
@ -343,7 +354,8 @@ class JpegImageFile(ImageFile.ImageFile):
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
import tempfile, os
import tempfile
import os
f, path = tempfile.mkstemp()
os.close(f)
if os.path.exists(self.filename):
@ -354,8 +366,10 @@ class JpegImageFile(ImageFile.ImageFile):
try:
self.im = Image.core.open_ppm(path)
finally:
try: os.unlink(path)
except: pass
try:
os.unlink(path)
except:
pass
self.mode = self.im.mode
self.size = self.im.size
@ -372,6 +386,7 @@ def _getexif(self):
# version.
from PIL import TiffImagePlugin
import io
def fixup(value):
if len(value) == 1:
return value[0]
@ -422,7 +437,7 @@ RAWMODE = {
"RGB": "RGB",
"RGBA": "RGB",
"RGBX": "RGB",
"CMYK": "CMYK;I", # assume adobe conventions
"CMYK": "CMYK;I", # assume adobe conventions
"YCbCr": "YCbCr",
}
@ -441,16 +456,19 @@ samplings = {
(2, 2, 1, 1, 1, 1): 2,
}
def convert_dict_qtables(qtables):
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
for idx, table in enumerate(qtables):
qtables[idx] = [table[i] for i in zigzag_index]
return qtables
def get_sampling(im):
sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
return samplings.get(sampling, -1)
def _save(im, fp, filename):
try:
@ -563,12 +581,11 @@ def _save(im, fp, filename):
info.get("exif", b"")
)
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
# is a value that's been used in a django patch.
# if we optimize, libjpeg needs a buffer big enough to hold the whole image
# in a shot. Guessing on the size, at im.size bytes. (raw pizel size is
# channels*size, this is a value that's been used in a django patch.
# https://github.com/jdriscoll/django-imagekit/issues/50
bufsize=0
bufsize = 0
if "optimize" in info or "progressive" in info or "progression" in info:
if quality >= 95:
bufsize = 2 * im.size[0] * im.size[1]
@ -577,17 +594,20 @@ def _save(im, fp, filename):
# The exif info needs to be written as one block, + APP1, + one spare byte.
# Ensure that our buffer is big enough
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif",b"")) + 5 )
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5)
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize)
def _save_cjpeg(im, fp, filename):
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
import os
file = im._dump()
os.system("cjpeg %s >%s" % (file, filename))
try: os.unlink(file)
except: pass
try:
os.unlink(file)
except:
pass
# -------------------------------------------------------------------q-
# Registry stuff

View File

@ -46,9 +46,11 @@ def _obj(fp, obj, **dict):
fp.write("/%s %s\n" % (k, v))
fp.write(">>\n")
def _endobj(fp):
fp.write("endobj\n")
##
# (Internal) Image save plugin for the PDF format.
@ -59,13 +61,15 @@ def _save(im, fp, filename):
# make sure image data is available
im.load()
xref = [0]*(5+1) # placeholders
xref = [0]*(5+1) # placeholders
class TextWriter:
def __init__(self, fp):
self.fp = fp
def __getattr__(self, name):
return getattr(self.fp, name)
def write(self, value):
self.fp.write(value.encode('latin-1'))
@ -89,13 +93,13 @@ def _save(im, fp, filename):
if im.mode == "1":
filter = "/ASCIIHexDecode"
colorspace = "/DeviceGray"
procset = "/ImageB" # grayscale
procset = "/ImageB" # grayscale
bits = 1
elif im.mode == "L":
filter = "/DCTDecode"
# params = "<< /Predictor 15 /Columns %d >>" % (width-2)
colorspace = "/DeviceGray"
procset = "/ImageB" # grayscale
procset = "/ImageB" # grayscale
elif im.mode == "P":
filter = "/ASCIIHexDecode"
colorspace = "[ /Indexed /DeviceRGB 255 <"
@ -105,16 +109,16 @@ def _save(im, fp, filename):
g = i8(palette[i*3+1])
b = i8(palette[i*3+2])
colorspace = colorspace + "%02x%02x%02x " % (r, g, b)
colorspace = colorspace + b"> ]"
procset = "/ImageI" # indexed color
colorspace = colorspace + "> ]"
procset = "/ImageI" # indexed color
elif im.mode == "RGB":
filter = "/DCTDecode"
colorspace = "/DeviceRGB"
procset = "/ImageC" # color images
procset = "/ImageC" # color images
elif im.mode == "CMYK":
filter = "/DCTDecode"
colorspace = "/DeviceCMYK"
procset = "/ImageC" # color images
procset = "/ImageC" # color images
else:
raise ValueError("cannot save mode %s" % im.mode)
@ -122,17 +126,21 @@ def _save(im, fp, filename):
# catalogue
xref[1] = fp.tell()
_obj(fp, 1, Type = "/Catalog",
Pages = "2 0 R")
_obj(
fp, 1,
Type="/Catalog",
Pages="2 0 R")
_endobj(fp)
#
# pages
xref[2] = fp.tell()
_obj(fp, 2, Type = "/Pages",
Count = 1,
Kids = "[4 0 R]")
_obj(
fp, 2,
Type="/Pages",
Count=1,
Kids="[4 0 R]")
_endobj(fp)
#
@ -144,29 +152,31 @@ def _save(im, fp, filename):
if bits == 1:
# FIXME: the hex encoder doesn't support packed 1-bit
# images; do things the hard way...
data = im.tostring("raw", "1")
data = im.tobytes("raw", "1")
im = Image.new("L", (len(data), 1), None)
im.putdata(data)
ImageFile._save(im, op, [("hex", (0,0)+im.size, 0, im.mode)])
ImageFile._save(im, op, [("hex", (0, 0)+im.size, 0, im.mode)])
elif filter == "/DCTDecode":
Image.SAVE["JPEG"](im, op, filename)
elif filter == "/FlateDecode":
ImageFile._save(im, op, [("zip", (0,0)+im.size, 0, im.mode)])
ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)])
elif filter == "/RunLengthDecode":
ImageFile._save(im, op, [("packbits", (0,0)+im.size, 0, im.mode)])
ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)])
else:
raise ValueError("unsupported PDF filter (%s)" % filter)
xref[3] = fp.tell()
_obj(fp, 3, Type = "/XObject",
Subtype = "/Image",
Width = width, # * 72.0 / resolution,
Height = height, # * 72.0 / resolution,
Length = len(op.getvalue()),
Filter = filter,
BitsPerComponent = bits,
DecodeParams = params,
ColorSpace = colorspace)
_obj(
fp, 3,
Type="/XObject",
Subtype="/Image",
Width=width, # * 72.0 / resolution,
Height=height, # * 72.0 / resolution,
Length=len(op.getvalue()),
Filter=filter,
BitsPerComponent=bits,
DecodeParams=params,
ColorSpace=colorspace)
fp.write("stream\n")
fp.fp.write(op.getvalue())
@ -179,11 +189,14 @@ def _save(im, fp, filename):
xref[4] = fp.tell()
_obj(fp, 4)
fp.write("<<\n/Type /Page\n/Parent 2 0 R\n"\
"/Resources <<\n/ProcSet [ /PDF %s ]\n"\
"/XObject << /image 3 0 R >>\n>>\n"\
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" %\
(procset, int(width * 72.0 /resolution) , int(height * 72.0 / resolution)))
fp.write(
"<<\n/Type /Page\n/Parent 2 0 R\n"
"/Resources <<\n/ProcSet [ /PDF %s ]\n"
"/XObject << /image 3 0 R >>\n>>\n"
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (
procset,
int(width * 72.0 / resolution),
int(height * 72.0 / resolution)))
_endobj(fp)
#
@ -191,10 +204,13 @@ def _save(im, fp, filename):
op = TextWriter(io.BytesIO())
op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" % (int(width * 72.0 / resolution), int(height * 72.0 / resolution)))
op.write(
"q %d 0 0 %d 0 0 cm /image Do Q\n" % (
int(width * 72.0 / resolution),
int(height * 72.0 / resolution)))
xref[5] = fp.tell()
_obj(fp, 5, Length = len(op.fp.getvalue()))
_obj(fp, 5, Length=len(op.fp.getvalue()))
fp.write("stream\n")
fp.fp.write(op.fp.getvalue())

View File

@ -89,33 +89,33 @@ class ChunkStream:
"Fetch a new chunk. Returns header information."
if self.queue:
cid, pos, len = self.queue[-1]
cid, pos, length = self.queue[-1]
del self.queue[-1]
self.fp.seek(pos)
else:
s = self.fp.read(8)
cid = s[4:]
pos = self.fp.tell()
len = i32(s)
length = i32(s)
if not is_cid(cid):
raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
return cid, pos, len
return cid, pos, length
def close(self):
self.queue = self.crc = self.fp = None
def push(self, cid, pos, len):
def push(self, cid, pos, length):
self.queue.append((cid, pos, len))
self.queue.append((cid, pos, length))
def call(self, cid, pos, len):
def call(self, cid, pos, length):
"Call the appropriate chunk handler"
if Image.DEBUG:
print("STREAM", cid, pos, len)
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, len)
print("STREAM", cid, pos, length)
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, length)
def crc(self, cid, data):
"Read and verify checksum"
@ -139,10 +139,10 @@ class ChunkStream:
cids = []
while True:
cid, pos, len = self.read()
cid, pos, length = self.read()
if cid == endchunk:
break
self.crc(cid, ImageFile._safe_read(self.fp, len))
self.crc(cid, ImageFile._safe_read(self.fp, length))
cids.append(cid)
return cids
@ -190,10 +190,10 @@ class PngStream(ChunkStream):
self.im_tile = None
self.im_palette = None
def chunk_iCCP(self, pos, len):
def chunk_iCCP(self, pos, length):
# ICC profile
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
# according to PNG spec, the iCCP chunk contains:
# Profile name 1-79 bytes (character string)
# Null separator 1 byte (null character)
@ -213,10 +213,10 @@ class PngStream(ChunkStream):
self.im_info["icc_profile"] = icc_profile
return s
def chunk_IHDR(self, pos, len):
def chunk_IHDR(self, pos, length):
# image header
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
self.im_size = i32(s), i32(s[4:])
try:
self.im_mode, self.im_rawmode = _MODES[(i8(s[8]), i8(s[9]))]
@ -228,30 +228,30 @@ class PngStream(ChunkStream):
raise SyntaxError("unknown filter category")
return s
def chunk_IDAT(self, pos, len):
def chunk_IDAT(self, pos, length):
# image data
self.im_tile = [("zip", (0,0)+self.im_size, pos, self.im_rawmode)]
self.im_idat = len
self.im_idat = length
raise EOFError
def chunk_IEND(self, pos, len):
def chunk_IEND(self, pos, length):
# end of PNG image
raise EOFError
def chunk_PLTE(self, pos, len):
def chunk_PLTE(self, pos, length):
# palette
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
if self.im_mode == "P":
self.im_palette = "RGB", s
return s
def chunk_tRNS(self, pos, len):
def chunk_tRNS(self, pos, length):
# transparency
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
if self.im_mode == "P":
if _simple_palette.match(s):
i = s.find(b"\0")
@ -265,17 +265,17 @@ class PngStream(ChunkStream):
self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
return s
def chunk_gAMA(self, pos, len):
def chunk_gAMA(self, pos, length):
# gamma setting
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
self.im_info["gamma"] = i32(s) / 100000.0
return s
def chunk_pHYs(self, pos, len):
def chunk_pHYs(self, pos, length):
# pixels per unit
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
px, py = i32(s), i32(s[4:])
unit = i8(s[8])
if unit == 1: # meter
@ -285,10 +285,10 @@ class PngStream(ChunkStream):
self.im_info["aspect"] = px, py
return s
def chunk_tEXt(self, pos, len):
def chunk_tEXt(self, pos, length):
# text
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
try:
k, v = s.split(b"\0", 1)
except ValueError:
@ -301,10 +301,10 @@ class PngStream(ChunkStream):
self.im_info[k] = self.im_text[k] = v
return s
def chunk_zTXt(self, pos, len):
def chunk_zTXt(self, pos, length):
# compressed text
s = ImageFile._safe_read(self.fp, len)
s = ImageFile._safe_read(self.fp, length)
try:
k, v = s.split(b"\0", 1)
except ValueError:
@ -358,16 +358,16 @@ class PngImageFile(ImageFile.ImageFile):
#
# get next chunk
cid, pos, len = self.png.read()
cid, pos, length = self.png.read()
try:
s = self.png.call(cid, pos, len)
s = self.png.call(cid, pos, length)
except EOFError:
break
except AttributeError:
if Image.DEBUG:
print(cid, pos, len, "(unknown)")
s = ImageFile._safe_read(self.fp, len)
print(cid, pos, length, "(unknown)")
s = ImageFile._safe_read(self.fp, length)
self.png.crc(cid, s)
@ -388,7 +388,7 @@ class PngImageFile(ImageFile.ImageFile):
rawmode, data = self.png.im_palette
self.palette = ImagePalette.raw(rawmode, data)
self.__idat = len # used by load_read()
self.__idat = length # used by load_read()
def verify(self):
@ -413,7 +413,7 @@ class PngImageFile(ImageFile.ImageFile):
ImageFile.ImageFile.load_prepare(self)
def load_read(self, bytes):
def load_read(self, read_bytes):
"internal: read more image data"
while self.__idat == 0:
@ -421,23 +421,23 @@ class PngImageFile(ImageFile.ImageFile):
self.fp.read(4) # CRC
cid, pos, len = self.png.read()
cid, pos, length = self.png.read()
if cid not in [b"IDAT", b"DDAT"]:
self.png.push(cid, pos, len)
self.png.push(cid, pos, length)
return b""
self.__idat = len # empty chunks are allowed
self.__idat = length # empty chunks are allowed
# read more data from this chunk
if bytes <= 0:
bytes = self.__idat
if read_bytes <= 0:
read_bytes = self.__idat
else:
bytes = min(bytes, self.__idat)
read_bytes = min(read_bytes, self.__idat)
self.__idat = self.__idat - bytes
self.__idat = self.__idat - read_bytes
return self.fp.read(bytes)
return self.fp.read(read_bytes)
def load_end(self):

View File

@ -36,17 +36,23 @@
from __future__ import print_function
from PIL import Image, ImageFile
import os, struct, sys
import os
import struct
import sys
def isInt(f):
try:
i = int(f)
if f-i == 0: return 1
else: return 0
if f-i == 0:
return 1
else:
return 0
except:
return 0
iforms = [1,3,-11,-12,-21,-22]
iforms = [1, 3, -11, -12, -21, -22]
# There is no magic number to identify Spider files, so just check a
# series of header locations to see if they have reasonable values.
@ -56,30 +62,32 @@ iforms = [1,3,-11,-12,-21,-22]
def isSpiderHeader(t):
h = (99,) + t # add 1 value so can use spider header index start=1
# header values 1,2,5,12,13,22,23 should be integers
for i in [1,2,5,12,13,22,23]:
if not isInt(h[i]): return 0
for i in [1, 2, 5, 12, 13, 22, 23]:
if not isInt(h[i]):
return 0
# check iform
iform = int(h[5])
if not iform in iforms: return 0
if iform not in iforms:
return 0
# check other header values
labrec = int(h[13]) # no. records in file header
labbyt = int(h[22]) # total no. of bytes in header
lenbyt = int(h[23]) # record length in bytes
#print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
if labbyt != (labrec * lenbyt): return 0
# print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
if labbyt != (labrec * lenbyt):
return 0
# looks like a valid header
return labbyt
def isSpiderImage(filename):
fp = open(filename,'rb')
fp = open(filename, 'rb')
f = fp.read(92) # read 23 * 4 bytes
fp.close()
bigendian = 1
t = struct.unpack('>23f',f) # try big-endian first
t = struct.unpack('>23f', f) # try big-endian first
hdrlen = isSpiderHeader(t)
if hdrlen == 0:
bigendian = 0
t = struct.unpack('<23f',f) # little-endian
t = struct.unpack('<23f', f) # little-endian
hdrlen = isSpiderHeader(t)
return hdrlen
@ -96,11 +104,11 @@ class SpiderImageFile(ImageFile.ImageFile):
try:
self.bigendian = 1
t = struct.unpack('>27f',f) # try big-endian first
t = struct.unpack('>27f', f) # try big-endian first
hdrlen = isSpiderHeader(t)
if hdrlen == 0:
self.bigendian = 0
t = struct.unpack('<27f',f) # little-endian
t = struct.unpack('<27f', f) # little-endian
hdrlen = isSpiderHeader(t)
if hdrlen == 0:
raise SyntaxError("not a valid Spider file")
@ -112,7 +120,7 @@ class SpiderImageFile(ImageFile.ImageFile):
if iform != 1:
raise SyntaxError("not a Spider 2D image")
self.size = int(h[12]), int(h[2]) # size in pixels (width, height)
self.size = int(h[12]), int(h[2]) # size in pixels (width, height)
self.istack = int(h[24])
self.imgnumber = int(h[27])
@ -141,9 +149,10 @@ class SpiderImageFile(ImageFile.ImageFile):
self.rawmode = "F;32F"
self.mode = "F"
self.tile = [("raw", (0, 0) + self.size, offset,
(self.rawmode, 0, 1))]
self.__fp = self.fp # FIXME: hack
self.tile = [
("raw", (0, 0) + self.size, offset,
(self.rawmode, 0, 1))]
self.__fp = self.fp # FIXME: hack
# 1st image index is zero (although SPIDER imgnumber starts at 1)
def tell(self):
@ -176,6 +185,7 @@ class SpiderImageFile(ImageFile.ImageFile):
from PIL import ImageTk
return ImageTk.PhotoImage(self.convert2byte(), palette=256)
# --------------------------------------------------------------------
# Image series
@ -200,17 +210,19 @@ def loadImageSeries(filelist=None):
imglist.append(im)
return imglist
# --------------------------------------------------------------------
# For saving images in Spider format
def makeSpiderHeader(im):
nsam,nrow = im.size
nsam, nrow = im.size
lenbyt = nsam * 4 # There are labrec records in the header
labrec = 1024 / lenbyt
if 1024%lenbyt != 0: labrec += 1
if 1024 % lenbyt != 0:
labrec += 1
labbyt = labrec * lenbyt
hdr = []
nvalues = labbyt / 4
nvalues = int(labbyt / 4)
for i in range(nvalues):
hdr.append(0.0)
@ -218,13 +230,13 @@ def makeSpiderHeader(im):
return []
# NB these are Fortran indices
hdr[1] = 1.0 # nslice (=1 for an image)
hdr[2] = float(nrow) # number of rows per slice
hdr[5] = 1.0 # iform for 2D image
hdr[12] = float(nsam) # number of pixels per line
hdr[13] = float(labrec) # number of records in file header
hdr[22] = float(labbyt) # total number of bytes in header
hdr[23] = float(lenbyt) # record length in bytes
hdr[1] = 1.0 # nslice (=1 for an image)
hdr[2] = float(nrow) # number of rows per slice
hdr[5] = 1.0 # iform for 2D image
hdr[12] = float(nsam) # number of pixels per line
hdr[13] = float(labrec) # number of records in file header
hdr[22] = float(labbyt) # total number of bytes in header
hdr[23] = float(lenbyt) # record length in bytes
# adjust for Fortran indexing
hdr = hdr[1:]
@ -232,9 +244,10 @@ def makeSpiderHeader(im):
# pack binary data into a string
hdrstr = []
for v in hdr:
hdrstr.append(struct.pack('f',v))
hdrstr.append(struct.pack('f', v))
return hdrstr
def _save(im, fp, filename):
if im.mode[0] != "F":
im = im.convert('F')
@ -250,11 +263,12 @@ def _save(im, fp, filename):
raise IOError("Unable to open %s for writing" % filename)
fp.writelines(hdr)
rawmode = "F;32NF" #32-bit native floating point
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode,0,1))])
rawmode = "F;32NF" # 32-bit native floating point
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])
fp.close()
def _save_spider(im, fp, filename):
# get the filename extension and register it with Image
fn, ext = os.path.splitext(filename)
@ -292,5 +306,7 @@ if __name__ == "__main__":
if outfile != "":
# perform some image operation
im = im.transpose(Image.FLIP_LEFT_RIGHT)
print("saving a flipped version of %s as %s " % (os.path.basename(filename), outfile))
print(
"saving a flipped version of %s as %s " %
(os.path.basename(filename), outfile))
im.save(outfile, "SPIDER")

View File

@ -984,11 +984,7 @@ def _save(im, fp, filename):
compression = im.encoderinfo.get('compression',im.info.get('compression','raw'))
libtiff = WRITE_LIBTIFF or compression in ["tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]
libtiff = WRITE_LIBTIFF or compression != 'raw'
# required for color libtiff images
ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
Tests/images/lena.spider Normal file

Binary file not shown.

View File

@ -1,25 +1,27 @@
from tester import *
from PIL import Image, EpsImagePlugin
import sys
import io
if not EpsImagePlugin.has_ghostscript():
skip()
#Our two EPS test files (they are identical except for their bounding boxes)
# Our two EPS test files (they are identical except for their bounding boxes)
file1 = "Tests/images/zero_bb.eps"
file2 = "Tests/images/non_zero_bb.eps"
#Due to palletization, we'll need to convert these to RGB after load
# Due to palletization, we'll need to convert these to RGB after load
file1_compare = "Tests/images/zero_bb.png"
file1_compare_scale2 = "Tests/images/zero_bb_scale2.png"
file2_compare = "Tests/images/non_zero_bb.png"
file2_compare_scale2 = "Tests/images/non_zero_bb_scale2.png"
# EPS test files with binary preview
file3 = "Tests/images/binary_preview_map.eps"
def test_sanity():
#Regular scale
# Regular scale
image1 = Image.open(file1)
image1.load()
assert_equal(image1.mode, "RGB")
@ -32,7 +34,7 @@ def test_sanity():
assert_equal(image2.size, (360, 252))
assert_equal(image2.format, "EPS")
#Double scale
# Double scale
image1_scale2 = Image.open(file1)
image1_scale2.load(scale=2)
assert_equal(image1_scale2.mode, "RGB")
@ -45,54 +47,96 @@ def test_sanity():
assert_equal(image2_scale2.size, (720, 504))
assert_equal(image2_scale2.format, "EPS")
def test_file_object():
#issue 479
# issue 479
image1 = Image.open(file1)
with open(tempfile('temp_file.eps'), 'wb') as fh:
image1.save(fh, 'EPS')
def test_iobase_object():
#issue 479
# issue 479
image1 = Image.open(file1)
with io.open(tempfile('temp_iobase.eps'), 'wb') as fh:
image1.save(fh, 'EPS')
def test_render_scale1():
#We need png support for these render test
# We need png support for these render test
codecs = dir(Image.core)
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
skip("zip/deflate support not available")
#Zero bounding box
# Zero bounding box
image1_scale1 = Image.open(file1)
image1_scale1.load()
image1_scale1_compare = Image.open(file1_compare).convert("RGB")
image1_scale1_compare.load()
assert_image_similar(image1_scale1, image1_scale1_compare, 5)
#Non-Zero bounding box
# Non-Zero bounding box
image2_scale1 = Image.open(file2)
image2_scale1.load()
image2_scale1_compare = Image.open(file2_compare).convert("RGB")
image2_scale1_compare.load()
assert_image_similar(image2_scale1, image2_scale1_compare, 10)
def test_render_scale2():
#We need png support for these render test
# We need png support for these render test
codecs = dir(Image.core)
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
skip("zip/deflate support not available")
#Zero bounding box
# Zero bounding box
image1_scale2 = Image.open(file1)
image1_scale2.load(scale=2)
image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB")
image1_scale2_compare.load()
assert_image_similar(image1_scale2, image1_scale2_compare, 5)
#Non-Zero bounding box
# Non-Zero bounding box
image2_scale2 = Image.open(file2)
image2_scale2.load(scale=2)
image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB")
image2_scale2_compare.load()
assert_image_similar(image2_scale2, image2_scale2_compare, 10)
def test_resize():
# Arrange
image1 = Image.open(file1)
image2 = Image.open(file2)
new_size = (100, 100)
# Act
image1 = image1.resize(new_size)
image2 = image2.resize(new_size)
# Assert
assert_equal(image1.size, new_size)
assert_equal(image2.size, new_size)
def test_thumbnail():
# Issue #619
# Arrange
image1 = Image.open(file1)
image2 = Image.open(file2)
new_size = (100, 100)
# Act
image1.thumbnail(new_size)
image2.thumbnail(new_size)
# Assert
assert_equal(max(image1.size), max(new_size))
assert_equal(max(image2.size), max(new_size))
def test_read_binary_preview():
# Issue 302
# open image with binary preview
image1 = Image.open(file3)
# End of file

View File

@ -12,17 +12,19 @@ if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
test_file = "Images/lena.jpg"
def roundtrip(im, **options):
out = BytesIO()
im.save(out, "JPEG", **options)
bytes = out.tell()
out.seek(0)
im = Image.open(out)
im.bytes = bytes # for testing only
im.bytes = bytes # for testing only
return im
# --------------------------------------------------------------------
def test_sanity():
# internal version number
@ -34,6 +36,7 @@ def test_sanity():
assert_equal(im.size, (128, 128))
assert_equal(im.format, "JPEG")
# --------------------------------------------------------------------
def test_app():
@ -44,6 +47,7 @@ def test_app():
assert_equal(im.applist[1], ("COM", b"Python Imaging Library"))
assert_equal(len(im.applist), 2)
def test_cmyk():
# Test CMYK handling. Thanks to Tim and Charlie for test data,
# Michael for getting me to look one more time.
@ -62,6 +66,7 @@ def test_cmyk():
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))]
assert_true(k > 0.9)
def test_dpi():
def test(xdpi, ydpi=None):
im = Image.open(test_file)
@ -70,7 +75,8 @@ def test_dpi():
assert_equal(test(72), (72, 72))
assert_equal(test(300), (300, 300))
assert_equal(test(100, 200), (100, 200))
assert_equal(test(0), None) # square pixels
assert_equal(test(0), None) # square pixels
def test_icc():
# Test ICC support
@ -89,6 +95,7 @@ def test_icc():
assert_false(im1.info.get("icc_profile"))
assert_true(im2.info.get("icc_profile"))
def test_icc_big():
# Make sure that the "extra" support handles large blocks
def test(n):
@ -96,16 +103,20 @@ def test_icc_big():
# using a 4-byte test code should allow us to detect out of
# order issues.
icc_profile = (b"Test"*int(n/4+1))[:n]
assert len(icc_profile) == n # sanity
assert len(icc_profile) == n # sanity
im1 = roundtrip(lena(), icc_profile=icc_profile)
assert_equal(im1.info.get("icc_profile"), icc_profile or None)
test(0); test(1)
test(3); test(4); test(5)
test(65533-14) # full JPEG marker block
test(65533-14+1) # full block plus one byte
test(ImageFile.MAXBLOCK) # full buffer block
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
test(ImageFile.MAXBLOCK*4+3) # large block
test(0)
test(1)
test(3)
test(4)
test(5)
test(65533-14) # full JPEG marker block
test(65533-14+1) # full block plus one byte
test(ImageFile.MAXBLOCK) # full buffer block
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
test(ImageFile.MAXBLOCK*4+3) # large block
def test_optimize():
im1 = roundtrip(lena())
@ -113,25 +124,29 @@ def test_optimize():
assert_image_equal(im1, im2)
assert_true(im1.bytes >= im2.bytes)
def test_optimize_large_buffer():
#https://github.com/python-imaging/Pillow/issues/148
# https://github.com/python-imaging/Pillow/issues/148
f = tempfile('temp.jpg')
# this requires ~ 1.5x Image.MAXBLOCK
im = Image.new("RGB", (4096,4096), 0xff3333)
im = Image.new("RGB", (4096, 4096), 0xff3333)
im.save(f, format="JPEG", optimize=True)
def test_progressive():
im1 = roundtrip(lena())
im2 = roundtrip(lena(), progressive=True)
assert_image_equal(im1, im2)
assert_true(im1.bytes >= im2.bytes)
def test_progressive_large_buffer():
f = tempfile('temp.jpg')
# this requires ~ 1.5x Image.MAXBLOCK
im = Image.new("RGB", (4096,4096), 0xff3333)
im = Image.new("RGB", (4096, 4096), 0xff3333)
im.save(f, format="JPEG", progressive=True)
def test_progressive_large_buffer_highest_quality():
f = tempfile('temp.jpg')
if py3:
@ -142,16 +157,18 @@ def test_progressive_large_buffer_highest_quality():
# this requires more bytes than pixels in the image
im.save(f, format="JPEG", progressive=True, quality=100)
def test_large_exif():
#https://github.com/python-imaging/Pillow/issues/148
# https://github.com/python-imaging/Pillow/issues/148
f = tempfile('temp.jpg')
im = lena()
im.save(f,'JPEG', quality=90, exif=b"1"*65532)
im.save(f, 'JPEG', quality=90, exif=b"1"*65532)
def test_progressive_compat():
im1 = roundtrip(lena())
im2 = roundtrip(lena(), progressive=1)
im3 = roundtrip(lena(), progression=1) # compatibility
im3 = roundtrip(lena(), progression=1) # compatibility
assert_image_equal(im1, im2)
assert_image_equal(im1, im3)
assert_false(im1.info.get("progressive"))
@ -161,31 +178,34 @@ def test_progressive_compat():
assert_true(im3.info.get("progressive"))
assert_true(im3.info.get("progression"))
def test_quality():
im1 = roundtrip(lena())
im2 = roundtrip(lena(), quality=50)
assert_image(im1, im2.mode, im2.size)
assert_true(im1.bytes >= im2.bytes)
def test_smooth():
im1 = roundtrip(lena())
im2 = roundtrip(lena(), smooth=100)
assert_image(im1, im2.mode, im2.size)
def test_subsampling():
def getsampling(im):
layer = im.layer
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
# experimental API
im = roundtrip(lena(), subsampling=-1) # default
im = roundtrip(lena(), subsampling=-1) # default
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
im = roundtrip(lena(), subsampling=0) # 4:4:4
im = roundtrip(lena(), subsampling=0) # 4:4:4
assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1))
im = roundtrip(lena(), subsampling=1) # 4:2:2
im = roundtrip(lena(), subsampling=1) # 4:2:2
assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1))
im = roundtrip(lena(), subsampling=2) # 4:1:1
im = roundtrip(lena(), subsampling=2) # 4:1:1
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
im = roundtrip(lena(), subsampling=3) # default (undefined)
im = roundtrip(lena(), subsampling=3) # default (undefined)
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
im = roundtrip(lena(), subsampling="4:4:4")
@ -197,6 +217,7 @@ def test_subsampling():
assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1"))
def test_exif():
im = Image.open("Tests/images/pil_sample_rgb.jpg")
info = im._getexif()
@ -207,3 +228,11 @@ def test_quality_keep():
im = Image.open("Images/lena.jpg")
f = tempfile('temp.jpg')
assert_no_exception(lambda: im.save(f, quality='keep'))
def test_junk_jpeg_header():
# https://github.com/python-imaging/Pillow/issues/630
filename = "Tests/images/junk_jpeg_header.jpg"
assert_no_exception(lambda: Image.open(filename))
# End of file

View File

@ -258,9 +258,6 @@ def test_compressions():
im = lena('RGB')
out = tempfile('temp.tif')
TiffImagePlugin.READ_LIBTIFF = True
TiffImagePlugin.WRITE_LIBTIFF = True
for compression in ('packbits', 'tiff_lzw'):
im.save(out, compression=compression)
im2 = Image.open(out)
@ -270,11 +267,6 @@ def test_compressions():
im2 = Image.open(out)
assert_image_similar(im, im2, 30)
TiffImagePlugin.READ_LIBTIFF = False
TiffImagePlugin.WRITE_LIBTIFF = False
def test_cmyk_save():
im = lena('CMYK')

58
Tests/test_file_pdf.py Normal file
View File

@ -0,0 +1,58 @@
from tester import *
import os.path
def helper_save_as_pdf(mode):
# Arrange
im = lena(mode)
outfile = tempfile("temp_" + mode + ".pdf")
# Act
im.save(outfile)
# Assert
assert_true(os.path.isfile(outfile))
assert_greater(os.path.getsize(outfile), 0)
def test_monochrome():
# Arrange
mode = "1"
# Act / Assert
helper_save_as_pdf(mode)
def test_greyscale():
# Arrange
mode = "L"
# Act / Assert
helper_save_as_pdf(mode)
def test_rgb():
# Arrange
mode = "RGB"
# Act / Assert
helper_save_as_pdf(mode)
def test_p_mode():
# Arrange
mode = "P"
# Act / Assert
helper_save_as_pdf(mode)
def test_cmyk_mode():
# Arrange
mode = "CMYK"
# Act / Assert
helper_save_as_pdf(mode)
# End of file

36
Tests/test_file_spider.py Normal file
View File

@ -0,0 +1,36 @@
from tester import *
from PIL import Image
from PIL import SpiderImagePlugin
test_file = "Tests/images/lena.spider"
def test_sanity():
im = Image.open(test_file)
im.load()
assert_equal(im.mode, "F")
assert_equal(im.size, (128, 128))
assert_equal(im.format, "SPIDER")
def test_save():
# Arrange
temp = tempfile('temp.spider')
im = lena()
# Act
im.save(temp, "SPIDER")
# Assert
im2 = Image.open(temp)
assert_equal(im2.mode, "F")
assert_equal(im2.size, (128, 128))
assert_equal(im2.format, "SPIDER")
def test_isSpiderImage():
assert_true(SpiderImagePlugin.isSpiderImage(test_file))
# End of file

View File

@ -2,6 +2,7 @@ from tester import *
from PIL import Image
def test_sanity():
def convert(im, mode):
@ -16,6 +17,7 @@ def test_sanity():
for mode in modes:
yield_test(convert, im, mode)
def test_default():
im = lena("P")
@ -26,26 +28,29 @@ def test_default():
assert_image(im, "RGB", im.size)
# ref https://github.com/python-imaging/Pillow/issues/274
def _test_float_conversion(im):
orig = im.getpixel((5,5))
converted = im.convert('F').getpixel((5,5))
orig = im.getpixel((5, 5))
converted = im.convert('F').getpixel((5, 5))
assert_equal(orig, converted)
def test_8bit():
im = Image.open('Images/lena.jpg')
_test_float_conversion(im.convert('L'))
def test_16bit():
im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im)
def test_16bit_workaround():
im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im.convert('I'))
def test_rgba_p():
im = lena('RGBA')
im.putalpha(lena('L'))
@ -55,21 +60,36 @@ def test_rgba_p():
assert_image_similar(im, comparable, 20)
def test_trns_p():
im = lena('P')
im.info['transparency']=0
im.info['transparency'] = 0
f = tempfile('temp.png')
l = im.convert('L')
assert_equal(l.info['transparency'], 0) # undone
assert_equal(l.info['transparency'], 0) # undone
assert_no_exception(lambda: l.save(f))
rgb = im.convert('RGB')
assert_equal(rgb.info['transparency'], (0,0,0)) # undone
assert_equal(rgb.info['transparency'], (0, 0, 0)) # undone
assert_no_exception(lambda: rgb.save(f))
# ref https://github.com/python-imaging/Pillow/issues/664
def test_trns_p_rgba():
# Arrange
im = lena('P')
im.info['transparency'] = 128
# Act
rgba = im.convert('RGBA')
# Assert
assert_false('transparency' in rgba.info)
def test_trns_l():
im = lena('L')
im.info['transparency'] = 128
@ -77,7 +97,7 @@ def test_trns_l():
f = tempfile('temp.png')
rgb = im.convert('RGB')
assert_equal(rgb.info['transparency'], (128,128,128)) # undone
assert_equal(rgb.info['transparency'], (128, 128, 128)) # undone
assert_no_exception(lambda: rgb.save(f))
p = im.convert('P')
@ -85,19 +105,19 @@ def test_trns_l():
assert_no_exception(lambda: p.save(f))
p = assert_warning(UserWarning,
lambda: im.convert('P', palette = Image.ADAPTIVE))
lambda: im.convert('P', palette=Image.ADAPTIVE))
assert_false('transparency' in p.info)
assert_no_exception(lambda: p.save(f))
def test_trns_RGB():
im = lena('RGB')
im.info['transparency'] = im.getpixel((0,0))
im.info['transparency'] = im.getpixel((0, 0))
f = tempfile('temp.png')
l = im.convert('L')
assert_equal(l.info['transparency'], l.getpixel((0,0))) # undone
assert_equal(l.info['transparency'], l.getpixel((0, 0))) # undone
assert_no_exception(lambda: l.save(f))
p = im.convert('P')
@ -105,8 +125,6 @@ def test_trns_RGB():
assert_no_exception(lambda: p.save(f))
p = assert_warning(UserWarning,
lambda: im.convert('P', palette = Image.ADAPTIVE))
lambda: im.convert('P', palette=Image.ADAPTIVE))
assert_false('transparency' in p.info)
assert_no_exception(lambda: p.save(f))

70
Tests/test_pickle.py Normal file
View File

@ -0,0 +1,70 @@
from tester import *
from PIL import Image
def helper_test_pickle_file(pickle, protocol=0):
im = Image.open('Images/lena.jpg')
filename = tempfile('temp.pkl')
# Act
with open(filename, 'wb') as f:
pickle.dump(im, f, protocol)
with open(filename, 'rb') as f:
loaded_im = pickle.load(f)
# Assert
assert_image_completely_equal(im, loaded_im)
def helper_test_pickle_string(pickle, protocol=0, file='Images/lena.jpg'):
im = Image.open(file)
# Act
dumped_string = pickle.dumps(im, protocol)
loaded_im = pickle.loads(dumped_string)
# Assert
assert_image_completely_equal(im, loaded_im)
def test_pickle_image():
# Arrange
import pickle
# Act / Assert
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
helper_test_pickle_string(pickle, protocol)
helper_test_pickle_file(pickle, protocol)
def test_cpickle_image():
# Arrange
try:
import cPickle
except ImportError:
return
# Act / Assert
for protocol in range(0, cPickle.HIGHEST_PROTOCOL + 1):
helper_test_pickle_string(cPickle, protocol)
helper_test_pickle_file(cPickle, protocol)
def test_pickle_p_mode():
# Arrange
import pickle
# Act / Assert
for file in [
"Tests/images/test-card.png",
"Tests/images/zero_bb.png",
"Tests/images/zero_bb_scale2.png",
"Tests/images/non_zero_bb.png",
"Tests/images/non_zero_bb_scale2.png",
"Tests/images/p_trns_single.png",
"Tests/images/pil123p.png"
]:
helper_test_pickle_string(pickle, file=file)
# End of file

View File

@ -242,7 +242,13 @@ def assert_image_equal(a, b, msg=None):
failure(msg or "got size %r, expected %r" % (a.size, b.size))
elif a.tobytes() != b.tobytes():
failure(msg or "got different content")
# generate better diff?
else:
success()
def assert_image_completely_equal(a, b, msg=None):
if a != b:
failure(msg or "images different")
else:
success()
@ -345,7 +351,10 @@ def _setup():
import sys
if "--coverage" in sys.argv:
import coverage
# Temporary: ignore PendingDeprecationWarning from Coverage (Py3.4)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
import coverage
cov = coverage.coverage(auto_data=True, include="PIL/*")
cov.start()

View File

@ -3350,7 +3350,7 @@ extern PyObject* PyImaging_ZipEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args);
/* Display support etc (in display.c) */
#ifdef WIN32
#ifdef _WIN32
extern PyObject* PyImaging_CreateWindowWin32(PyObject* self, PyObject* args);
extern PyObject* PyImaging_DisplayWin32(PyObject* self, PyObject* args);
extern PyObject* PyImaging_DisplayModeWin32(PyObject* self, PyObject* args);
@ -3423,14 +3423,14 @@ static PyMethodDef functions[] = {
/* Memory mapping */
#ifdef WITH_MAPPING
#ifdef WIN32
#ifdef _WIN32
{"map", (PyCFunction)PyImaging_Mapper, 1},
#endif
{"map_buffer", (PyCFunction)PyImaging_MapBuffer, 1},
#endif
/* Display support */
#ifdef WIN32
#ifdef _WIN32
{"display", (PyCFunction)PyImaging_DisplayWin32, 1},
{"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, 1},
{"grabscreen", (PyCFunction)PyImaging_GrabScreenWin32, 1},

View File

@ -28,12 +28,6 @@ http://www.cazabon.com\n\
#include "Imaging.h"
#include "py3.h"
#ifdef WIN32
#include <windows.h>
#include <windef.h>
#include <wingdi.h>
#endif
#define PYCMSVERSION "1.0.0 pil"
/* version history */
@ -450,7 +444,7 @@ cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args)
return PyInt_FromLong(result != 0);
}
#ifdef WIN32
#ifdef _WIN32
static PyObject *
cms_get_display_profile_win32(PyObject* self, PyObject* args)
{
@ -496,7 +490,7 @@ static PyMethodDef pyCMSdll_methods[] = {
{"createProfile", createProfile, 1},
/* platform specific tools */
#ifdef WIN32
#ifdef _WIN32
{"get_display_profile_win32", cms_get_display_profile_win32, 1},
#endif

View File

@ -433,9 +433,6 @@ PyImaging_TiffLzwDecoderNew(PyObject* self, PyObject* args)
#include "TiffDecode.h"
#include <string.h>
#ifdef __WIN32__
#define strcasecmp(s1, s2) stricmp(s1, s2)
#endif
PyObject*
PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)

View File

@ -31,7 +31,7 @@
/* -------------------------------------------------------------------- */
/* Windows DIB support */
#ifdef WIN32
#ifdef _WIN32
#include "ImDib.h"
@ -864,4 +864,4 @@ error:
return buffer;
}
#endif /* WIN32 */
#endif /* _WIN32 */

View File

@ -670,9 +670,6 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
#include "TiffDecode.h"
#include <string.h>
#ifdef __WIN32__
#define strcasecmp(s1, s2) stricmp(s1, s2)
#endif
PyObject*
PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)

View File

@ -22,7 +22,7 @@
#include "Imaging.h"
#ifdef WIN32
#ifdef _WIN32
#include "ImDib.h"
@ -308,4 +308,4 @@ ImagingDeleteDIB(ImagingDIB dib)
free(dib->info);
}
#endif /* WIN32 */
#endif /* _WIN32 */

View File

@ -59,7 +59,7 @@ typedef struct {
unsigned char buffer[GIFTABLE];
/* Symbol table */
unsigned INT16 link[GIFTABLE];
UINT16 link[GIFTABLE];
unsigned char data[GIFTABLE];
int next;

View File

@ -10,20 +10,9 @@
* See the README file for information on usage and redistribution.
*/
#ifdef WIN32
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER >= 1200) || (defined __GNUC__)
/* already defined in basetsd.h */
#undef INT8
#undef UINT8
#undef INT16
#undef UINT16
#undef INT32
#undef INT64
#undef UINT32
#endif
#include <windows.h>
#include "ImPlatform.h"
#if defined(__cplusplus)
extern "C" {

View File

@ -17,26 +17,22 @@
#error Sorry, this library requires ANSI header files.
#endif
#if defined(_MSC_VER)
#ifndef WIN32
#define WIN32
#endif
/* VC++ 4.0 is a bit annoying when it comes to precision issues (like
claiming that "float a = 0.0;" would lead to loss of precision). I
don't like to see warnings from my code, but since I still want to
keep it readable, I simply switch off a few warnings instead of adding
the tons of casts that VC++ seem to require. This code is compiled
with numerous other compilers as well, so any real errors are likely
to be catched anyway. */
#pragma warning(disable: 4244) /* conversion from 'float' to 'int' */
#if defined(_MSC_VER) && !defined(__GNUC__)
#define inline __inline
#endif
#if defined(_MSC_VER)
#define inline __inline
#elif !defined(USE_INLINE)
#if !defined(PIL_USE_INLINE)
#define inline
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
/* For System that are not Windows, we'll need to define these. */
#if SIZEOF_SHORT == 2
#define INT16 short
#elif SIZEOF_INT == 2
@ -61,12 +57,16 @@
#define INT64 long
#endif
/* assume IEEE; tweak if necessary (patches are welcome) */
#define FLOAT32 float
#define FLOAT64 double
#define INT8 signed char
#define UINT8 unsigned char
#define UINT16 unsigned INT16
#define UINT32 unsigned INT32
#endif
/* assume IEEE; tweak if necessary (patches are welcome) */
#define FLOAT32 float
#define FLOAT64 double

View File

@ -41,7 +41,6 @@
two cases. */
#ifdef _WIN32
#include <windows.h>
#include <process.h>
#else
#include <pthread.h>

View File

@ -45,7 +45,7 @@ typedef struct {
unsigned char buffer[LZWTABLE];
/* Symbol table */
unsigned INT16 link[LZWTABLE];
UINT16 link[LZWTABLE];
unsigned char data[LZWTABLE];
int next;

18
map.c
View File

@ -22,18 +22,6 @@
#include "Imaging.h"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#undef INT8
#undef UINT8
#undef INT16
#undef UINT16
#undef INT32
#undef INT64
#undef UINT32
#include "windows.h"
#endif
#include "py3.h"
/* compatibility wrappers (defined in _imaging.c) */
@ -48,7 +36,7 @@ typedef struct {
char* base;
int size;
int offset;
#ifdef WIN32
#ifdef _WIN32
HANDLE hFile;
HANDLE hMap;
#endif
@ -71,7 +59,7 @@ PyImaging_MapperNew(const char* filename, int readonly)
mapper->base = NULL;
mapper->size = mapper->offset = 0;
#ifdef WIN32
#ifdef _WIN32
mapper->hFile = (HANDLE)-1;
mapper->hMap = (HANDLE)-1;
@ -114,7 +102,7 @@ PyImaging_MapperNew(const char* filename, int readonly)
static void
mapping_dealloc(ImagingMapperObject* mapper)
{
#ifdef WIN32
#ifdef _WIN32
if (mapper->base != 0)
UnmapViewOfFile(mapper->base);
if (mapper->hMap != (HANDLE)-1)

View File

@ -206,24 +206,30 @@ class pil_build_ext(build_ext):
_add_directory(library_dirs, "/opt/local/lib")
_add_directory(include_dirs, "/opt/local/include")
# if homebrew is installed, use its lib and include directories
# if Homebrew is installed, use its lib and include directories
import subprocess
try:
prefix = subprocess.check_output(['brew', '--prefix'])
if prefix:
prefix = prefix.strip()
_add_directory(library_dirs, os.path.join(prefix, 'lib'))
_add_directory(include_dirs, os.path.join(prefix, 'include'))
# freetype2 is a key-only brew under opt/
_add_directory(library_dirs, os.path.join(prefix, 'opt', 'freetype', 'lib'))
_add_directory(include_dirs, os.path.join(prefix, 'opt', 'freetype', 'include'))
prefix = subprocess.check_output(['brew', '--prefix']).strip()
except:
pass # homebrew not installed
# Homebrew not installed
prefix = None
# freetype2 ships with X11 (after homebrew, so that homebrew freetype is preferred)
_add_directory(library_dirs, "/usr/X11/lib")
_add_directory(include_dirs, "/usr/X11/include")
ft_prefix = None
if prefix:
# add Homebrew's include and lib directories
_add_directory(library_dirs, os.path.join(prefix, 'lib'))
_add_directory(include_dirs, os.path.join(prefix, 'include'))
ft_prefix = os.path.join(prefix, 'opt', 'freetype')
if ft_prefix and os.path.isdir(ft_prefix):
# freetype might not be linked into Homebrew's prefix
_add_directory(library_dirs, os.path.join(ft_prefix, 'lib'))
_add_directory(include_dirs, os.path.join(ft_prefix, 'include'))
else:
# fall back to freetype from XQuartz if Homebrew's freetype is missing
_add_directory(library_dirs, "/usr/X11/lib")
_add_directory(include_dirs, "/usr/X11/include")
elif sys.platform.startswith("linux"):
arch_tp = (plat.processor(), plat.architecture()[0])