mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 02:36:17 +03:00
Merge from current master
This commit is contained in:
commit
3b227d1a05
23
.travis.yml
23
.travis.yml
|
@ -1,18 +1,15 @@
|
||||||
language: python
|
language: python
|
||||||
|
|
||||||
# for python-qt4
|
|
||||||
virtualenv:
|
|
||||||
system_site_packages: true
|
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
irc: "chat.freenode.net#pil"
|
irc: "chat.freenode.net#pil"
|
||||||
|
|
||||||
python:
|
python:
|
||||||
|
- "pypy"
|
||||||
- 2.6
|
- 2.6
|
||||||
- 2.7
|
- 2.7
|
||||||
- 3.2
|
- 3.2
|
||||||
- 3.3
|
- 3.3
|
||||||
- "pypy"
|
- 3.4
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake"
|
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake"
|
||||||
|
@ -29,8 +26,14 @@ script:
|
||||||
- coverage erase
|
- coverage erase
|
||||||
- python setup.py clean
|
- python setup.py clean
|
||||||
- python setup.py build_ext --inplace
|
- 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:
|
after_success:
|
||||||
- coverage report
|
- coverage report
|
||||||
|
@ -38,7 +41,5 @@ after_success:
|
||||||
- pip install pep8 pyflakes
|
- pip install pep8 pyflakes
|
||||||
- pep8 PIL/*.py
|
- pep8 PIL/*.py
|
||||||
- pyflakes PIL/*.py
|
- pyflakes PIL/*.py
|
||||||
|
- pep8 Tests/*.py
|
||||||
matrix:
|
- pyflakes Tests/*.py
|
||||||
allow_failures:
|
|
||||||
- python: "pypy"
|
|
||||||
|
|
21
CHANGES.rst
21
CHANGES.rst
|
@ -4,6 +4,27 @@ Changelog (Pillow)
|
||||||
2.5.0 (unreleased)
|
2.5.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- 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.
|
- Added Image.close, context manager support.
|
||||||
[wiredfool]
|
[wiredfool]
|
||||||
|
|
||||||
|
|
28
PIL/Image.py
28
PIL/Image.py
|
@ -92,8 +92,10 @@ except ImportError:
|
||||||
builtins = __builtin__
|
builtins = __builtin__
|
||||||
|
|
||||||
from PIL import ImageMode
|
from PIL import ImageMode
|
||||||
from PIL._binary import i8, o8
|
from PIL._binary import i8
|
||||||
from PIL._util import isPath, isStringType, deferred_error
|
from PIL._util import isPath
|
||||||
|
from PIL._util import isStringType
|
||||||
|
from PIL._util import deferred_error
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -545,8 +547,8 @@ class Image:
|
||||||
self.readonly = 0
|
self.readonly = 0
|
||||||
|
|
||||||
def _dump(self, file=None, format=None):
|
def _dump(self, file=None, format=None):
|
||||||
import tempfile
|
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
suffix = ''
|
suffix = ''
|
||||||
if format:
|
if format:
|
||||||
suffix = '.'+format
|
suffix = '.'+format
|
||||||
|
@ -836,8 +838,7 @@ class Image:
|
||||||
t = self.info['transparency']
|
t = self.info['transparency']
|
||||||
if isinstance(t, bytes):
|
if isinstance(t, bytes):
|
||||||
# Dragons. This can't be represented by a single color
|
# Dragons. This can't be represented by a single color
|
||||||
warnings.warn(
|
warnings.warn('Palette images with Transparency expressed ' +
|
||||||
'Palette images with Transparency expressed ' +
|
|
||||||
' in bytes should be converted to RGBA images')
|
' in bytes should be converted to RGBA images')
|
||||||
delete_trns = True
|
delete_trns = True
|
||||||
else:
|
else:
|
||||||
|
@ -856,6 +857,9 @@ class Image:
|
||||||
trns_im = trns_im.convert('RGB')
|
trns_im = trns_im.convert('RGB')
|
||||||
trns = trns_im.getpixel((0,0))
|
trns = trns_im.getpixel((0,0))
|
||||||
|
|
||||||
|
elif self.mode == 'P' and mode == 'RGBA':
|
||||||
|
delete_trns = True
|
||||||
|
|
||||||
if mode == "P" and palette == ADAPTIVE:
|
if mode == "P" and palette == ADAPTIVE:
|
||||||
im = self.im.quantize(colors)
|
im = self.im.quantize(colors)
|
||||||
new = self._new(im)
|
new = self._new(im)
|
||||||
|
@ -1547,6 +1551,7 @@ class Image:
|
||||||
-math.sin(angle), math.cos(angle), 0.0
|
-math.sin(angle), math.cos(angle), 0.0
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def transform(x, y, matrix=matrix):
|
def transform(x, y, matrix=matrix):
|
||||||
(a, b, c, d, e, f) = matrix
|
(a, b, c, d, e, f) = matrix
|
||||||
return a*x + b*y + c, d*x + e*y + f
|
return a*x + b*y + c, d*x + e*y + f
|
||||||
|
@ -1722,7 +1727,7 @@ class Image:
|
||||||
"""
|
"""
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def thumbnail(self, size, resample=NEAREST):
|
def thumbnail(self, size, resample=ANTIALIAS):
|
||||||
"""
|
"""
|
||||||
Make this image into a thumbnail. This method modifies the
|
Make this image into a thumbnail. This method modifies the
|
||||||
image to contain a thumbnail version of itself, no larger than
|
image to contain a thumbnail version of itself, no larger than
|
||||||
|
@ -1738,22 +1743,19 @@ class Image:
|
||||||
|
|
||||||
Also note that this function modifies the :py:class:`~PIL.Image.Image`
|
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,
|
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
|
apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
|
||||||
original image.
|
image.
|
||||||
|
|
||||||
:param size: Requested size.
|
:param size: Requested size.
|
||||||
:param resample: Optional resampling filter. This can be one
|
:param resample: Optional resampling filter. This can be one
|
||||||
of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
|
of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
|
||||||
:py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.ANTIALIAS`
|
:py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.ANTIALIAS`
|
||||||
(best quality). If omitted, it defaults to
|
(best quality). If omitted, it defaults to
|
||||||
:py:attr:`PIL.Image.NEAREST` (this will be changed to ANTIALIAS in a
|
:py:attr:`PIL.Image.ANTIALIAS`. (was :py:attr:`PIL.Image.NEAREST`
|
||||||
future version).
|
prior to version 2.5.0)
|
||||||
:returns: None
|
:returns: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# FIXME: the default resampling filter will be changed
|
|
||||||
# to ANTIALIAS in future versions
|
|
||||||
|
|
||||||
# preserve aspect ratio
|
# preserve aspect ratio
|
||||||
x, y = self.size
|
x, y = self.size
|
||||||
if x > size[0]:
|
if x > size[0]:
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
|
|
||||||
__version__ = "0.6"
|
__version__ = "0.6"
|
||||||
|
|
||||||
import array, struct
|
import array
|
||||||
|
import struct
|
||||||
from PIL import Image, ImageFile, _binary
|
from PIL import Image, ImageFile, _binary
|
||||||
from PIL.JpegPresets import presets
|
from PIL.JpegPresets import presets
|
||||||
from PIL._util import isStringType
|
from PIL._util import isStringType
|
||||||
|
@ -44,6 +45,7 @@ o8 = _binary.o8
|
||||||
i16 = _binary.i16be
|
i16 = _binary.i16be
|
||||||
i32 = _binary.i32be
|
i32 = _binary.i32be
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Parser
|
# Parser
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ def Skip(self, marker):
|
||||||
n = i16(self.fp.read(2))-2
|
n = i16(self.fp.read(2))-2
|
||||||
ImageFile._safe_read(self.fp, n)
|
ImageFile._safe_read(self.fp, n)
|
||||||
|
|
||||||
|
|
||||||
def APP(self, marker):
|
def APP(self, marker):
|
||||||
#
|
#
|
||||||
# Application marker. Store these in the APP dictionary.
|
# Application marker. Store these in the APP dictionary.
|
||||||
|
@ -108,16 +111,17 @@ def APP(self, marker):
|
||||||
else:
|
else:
|
||||||
self.info["adobe_transform"] = adobe_transform
|
self.info["adobe_transform"] = adobe_transform
|
||||||
|
|
||||||
|
|
||||||
def COM(self, marker):
|
def COM(self, marker):
|
||||||
#
|
#
|
||||||
# Comment marker. Store these in the APP dictionary.
|
# Comment marker. Store these in the APP dictionary.
|
||||||
|
|
||||||
n = i16(self.fp.read(2))-2
|
n = i16(self.fp.read(2))-2
|
||||||
s = ImageFile._safe_read(self.fp, n)
|
s = ImageFile._safe_read(self.fp, n)
|
||||||
|
|
||||||
self.app["COM"] = s # compatibility
|
self.app["COM"] = s # compatibility
|
||||||
self.applist.append(("COM", s))
|
self.applist.append(("COM", s))
|
||||||
|
|
||||||
|
|
||||||
def SOF(self, marker):
|
def SOF(self, marker):
|
||||||
#
|
#
|
||||||
# Start of frame marker. Defines the size and mode of the
|
# Start of frame marker. Defines the size and mode of the
|
||||||
|
@ -165,6 +169,7 @@ def SOF(self, marker):
|
||||||
# 4-tuples: id, vsamp, hsamp, qtable
|
# 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):
|
def DQT(self, marker):
|
||||||
#
|
#
|
||||||
# Define quantization table. Support baseline 8-bit tables
|
# Define quantization table. Support baseline 8-bit tables
|
||||||
|
@ -261,6 +266,7 @@ MARKER = {
|
||||||
def _accept(prefix):
|
def _accept(prefix):
|
||||||
return prefix[0:1] == b"\377"
|
return prefix[0:1] == b"\377"
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Image plugin for JPEG and JFIF images.
|
# Image plugin for JPEG and JFIF images.
|
||||||
|
|
||||||
|
@ -290,9 +296,14 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
|
i = i8(s)
|
||||||
|
if i == 0xFF:
|
||||||
s = s + self.fp.read(1)
|
s = s + self.fp.read(1)
|
||||||
|
|
||||||
i = i16(s)
|
i = i16(s)
|
||||||
|
else:
|
||||||
|
# Skip non-0xFF junk
|
||||||
|
s = b"\xff"
|
||||||
|
continue
|
||||||
|
|
||||||
if i in MARKER:
|
if i in MARKER:
|
||||||
name, description, handler = MARKER[i]
|
name, description, handler = MARKER[i]
|
||||||
|
@ -307,9 +318,9 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
# self.__offset = self.fp.tell()
|
# self.__offset = self.fp.tell()
|
||||||
break
|
break
|
||||||
s = self.fp.read(1)
|
s = self.fp.read(1)
|
||||||
elif i == 0 or i == 65535:
|
elif i == 0 or i == 0xFFFF:
|
||||||
# padded marker or junk; move on
|
# padded marker or junk; move on
|
||||||
s = "\xff"
|
s = b"\xff"
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("no marker found")
|
raise SyntaxError("no marker found")
|
||||||
|
|
||||||
|
@ -343,7 +354,8 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
|
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
|
||||||
|
|
||||||
import tempfile, os
|
import tempfile
|
||||||
|
import os
|
||||||
f, path = tempfile.mkstemp()
|
f, path = tempfile.mkstemp()
|
||||||
os.close(f)
|
os.close(f)
|
||||||
if os.path.exists(self.filename):
|
if os.path.exists(self.filename):
|
||||||
|
@ -354,8 +366,10 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
try:
|
try:
|
||||||
self.im = Image.core.open_ppm(path)
|
self.im = Image.core.open_ppm(path)
|
||||||
finally:
|
finally:
|
||||||
try: os.unlink(path)
|
try:
|
||||||
except: pass
|
os.unlink(path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
self.mode = self.im.mode
|
self.mode = self.im.mode
|
||||||
self.size = self.im.size
|
self.size = self.im.size
|
||||||
|
@ -372,6 +386,7 @@ def _getexif(self):
|
||||||
# version.
|
# version.
|
||||||
from PIL import TiffImagePlugin
|
from PIL import TiffImagePlugin
|
||||||
import io
|
import io
|
||||||
|
|
||||||
def fixup(value):
|
def fixup(value):
|
||||||
if len(value) == 1:
|
if len(value) == 1:
|
||||||
return value[0]
|
return value[0]
|
||||||
|
@ -441,16 +456,19 @@ samplings = {
|
||||||
(2, 2, 1, 1, 1, 1): 2,
|
(2, 2, 1, 1, 1, 1): 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def convert_dict_qtables(qtables):
|
def convert_dict_qtables(qtables):
|
||||||
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
|
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
|
||||||
for idx, table in enumerate(qtables):
|
for idx, table in enumerate(qtables):
|
||||||
qtables[idx] = [table[i] for i in zigzag_index]
|
qtables[idx] = [table[i] for i in zigzag_index]
|
||||||
return qtables
|
return qtables
|
||||||
|
|
||||||
|
|
||||||
def get_sampling(im):
|
def get_sampling(im):
|
||||||
sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
|
sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
|
||||||
return samplings.get(sampling, -1)
|
return samplings.get(sampling, -1)
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -563,10 +581,9 @@ def _save(im, fp, filename):
|
||||||
info.get("exif", b"")
|
info.get("exif", b"")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# if we optimize, libjpeg needs a buffer big enough to hold the whole image
|
||||||
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
|
# in a shot. Guessing on the size, at im.size bytes. (raw pizel size is
|
||||||
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
|
# channels*size, this is a value that's been used in a django patch.
|
||||||
# is a value that's been used in a django patch.
|
|
||||||
# https://github.com/jdriscoll/django-imagekit/issues/50
|
# 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 "optimize" in info or "progressive" in info or "progression" in info:
|
||||||
|
@ -581,13 +598,16 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
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):
|
def _save_cjpeg(im, fp, filename):
|
||||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
||||||
import os
|
import os
|
||||||
file = im._dump()
|
file = im._dump()
|
||||||
os.system("cjpeg %s >%s" % (file, filename))
|
os.system("cjpeg %s >%s" % (file, filename))
|
||||||
try: os.unlink(file)
|
try:
|
||||||
except: pass
|
os.unlink(file)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# -------------------------------------------------------------------q-
|
# -------------------------------------------------------------------q-
|
||||||
# Registry stuff
|
# Registry stuff
|
||||||
|
|
|
@ -46,9 +46,11 @@ def _obj(fp, obj, **dict):
|
||||||
fp.write("/%s %s\n" % (k, v))
|
fp.write("/%s %s\n" % (k, v))
|
||||||
fp.write(">>\n")
|
fp.write(">>\n")
|
||||||
|
|
||||||
|
|
||||||
def _endobj(fp):
|
def _endobj(fp):
|
||||||
fp.write("endobj\n")
|
fp.write("endobj\n")
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# (Internal) Image save plugin for the PDF format.
|
# (Internal) Image save plugin for the PDF format.
|
||||||
|
|
||||||
|
@ -64,8 +66,10 @@ def _save(im, fp, filename):
|
||||||
class TextWriter:
|
class TextWriter:
|
||||||
def __init__(self, fp):
|
def __init__(self, fp):
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self.fp, name)
|
return getattr(self.fp, name)
|
||||||
|
|
||||||
def write(self, value):
|
def write(self, value):
|
||||||
self.fp.write(value.encode('latin-1'))
|
self.fp.write(value.encode('latin-1'))
|
||||||
|
|
||||||
|
@ -105,7 +109,7 @@ def _save(im, fp, filename):
|
||||||
g = i8(palette[i*3+1])
|
g = i8(palette[i*3+1])
|
||||||
b = i8(palette[i*3+2])
|
b = i8(palette[i*3+2])
|
||||||
colorspace = colorspace + "%02x%02x%02x " % (r, g, b)
|
colorspace = colorspace + "%02x%02x%02x " % (r, g, b)
|
||||||
colorspace = colorspace + b"> ]"
|
colorspace = colorspace + "> ]"
|
||||||
procset = "/ImageI" # indexed color
|
procset = "/ImageI" # indexed color
|
||||||
elif im.mode == "RGB":
|
elif im.mode == "RGB":
|
||||||
filter = "/DCTDecode"
|
filter = "/DCTDecode"
|
||||||
|
@ -122,7 +126,9 @@ def _save(im, fp, filename):
|
||||||
# catalogue
|
# catalogue
|
||||||
|
|
||||||
xref[1] = fp.tell()
|
xref[1] = fp.tell()
|
||||||
_obj(fp, 1, Type = "/Catalog",
|
_obj(
|
||||||
|
fp, 1,
|
||||||
|
Type="/Catalog",
|
||||||
Pages="2 0 R")
|
Pages="2 0 R")
|
||||||
_endobj(fp)
|
_endobj(fp)
|
||||||
|
|
||||||
|
@ -130,7 +136,9 @@ def _save(im, fp, filename):
|
||||||
# pages
|
# pages
|
||||||
|
|
||||||
xref[2] = fp.tell()
|
xref[2] = fp.tell()
|
||||||
_obj(fp, 2, Type = "/Pages",
|
_obj(
|
||||||
|
fp, 2,
|
||||||
|
Type="/Pages",
|
||||||
Count=1,
|
Count=1,
|
||||||
Kids="[4 0 R]")
|
Kids="[4 0 R]")
|
||||||
_endobj(fp)
|
_endobj(fp)
|
||||||
|
@ -144,7 +152,7 @@ def _save(im, fp, filename):
|
||||||
if bits == 1:
|
if bits == 1:
|
||||||
# FIXME: the hex encoder doesn't support packed 1-bit
|
# FIXME: the hex encoder doesn't support packed 1-bit
|
||||||
# images; do things the hard way...
|
# 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 = Image.new("L", (len(data), 1), None)
|
||||||
im.putdata(data)
|
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)])
|
||||||
|
@ -158,7 +166,9 @@ def _save(im, fp, filename):
|
||||||
raise ValueError("unsupported PDF filter (%s)" % filter)
|
raise ValueError("unsupported PDF filter (%s)" % filter)
|
||||||
|
|
||||||
xref[3] = fp.tell()
|
xref[3] = fp.tell()
|
||||||
_obj(fp, 3, Type = "/XObject",
|
_obj(
|
||||||
|
fp, 3,
|
||||||
|
Type="/XObject",
|
||||||
Subtype="/Image",
|
Subtype="/Image",
|
||||||
Width=width, # * 72.0 / resolution,
|
Width=width, # * 72.0 / resolution,
|
||||||
Height=height, # * 72.0 / resolution,
|
Height=height, # * 72.0 / resolution,
|
||||||
|
@ -179,11 +189,14 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
xref[4] = fp.tell()
|
xref[4] = fp.tell()
|
||||||
_obj(fp, 4)
|
_obj(fp, 4)
|
||||||
fp.write("<<\n/Type /Page\n/Parent 2 0 R\n"\
|
fp.write(
|
||||||
"/Resources <<\n/ProcSet [ /PDF %s ]\n"\
|
"<<\n/Type /Page\n/Parent 2 0 R\n"
|
||||||
"/XObject << /image 3 0 R >>\n>>\n"\
|
"/Resources <<\n/ProcSet [ /PDF %s ]\n"
|
||||||
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" %\
|
"/XObject << /image 3 0 R >>\n>>\n"
|
||||||
(procset, int(width * 72.0 /resolution) , int(height * 72.0 / resolution)))
|
"/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)
|
_endobj(fp)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -191,7 +204,10 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
op = TextWriter(io.BytesIO())
|
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()
|
xref[5] = fp.tell()
|
||||||
_obj(fp, 5, Length=len(op.fp.getvalue()))
|
_obj(fp, 5, Length=len(op.fp.getvalue()))
|
||||||
|
|
|
@ -89,33 +89,33 @@ class ChunkStream:
|
||||||
"Fetch a new chunk. Returns header information."
|
"Fetch a new chunk. Returns header information."
|
||||||
|
|
||||||
if self.queue:
|
if self.queue:
|
||||||
cid, pos, len = self.queue[-1]
|
cid, pos, length = self.queue[-1]
|
||||||
del self.queue[-1]
|
del self.queue[-1]
|
||||||
self.fp.seek(pos)
|
self.fp.seek(pos)
|
||||||
else:
|
else:
|
||||||
s = self.fp.read(8)
|
s = self.fp.read(8)
|
||||||
cid = s[4:]
|
cid = s[4:]
|
||||||
pos = self.fp.tell()
|
pos = self.fp.tell()
|
||||||
len = i32(s)
|
length = i32(s)
|
||||||
|
|
||||||
if not is_cid(cid):
|
if not is_cid(cid):
|
||||||
raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
|
raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
|
||||||
|
|
||||||
return cid, pos, len
|
return cid, pos, length
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.queue = self.crc = self.fp = None
|
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"
|
"Call the appropriate chunk handler"
|
||||||
|
|
||||||
if Image.DEBUG:
|
if Image.DEBUG:
|
||||||
print("STREAM", cid, pos, len)
|
print("STREAM", cid, pos, length)
|
||||||
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, len)
|
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, length)
|
||||||
|
|
||||||
def crc(self, cid, data):
|
def crc(self, cid, data):
|
||||||
"Read and verify checksum"
|
"Read and verify checksum"
|
||||||
|
@ -139,10 +139,10 @@ class ChunkStream:
|
||||||
cids = []
|
cids = []
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
cid, pos, len = self.read()
|
cid, pos, length = self.read()
|
||||||
if cid == endchunk:
|
if cid == endchunk:
|
||||||
break
|
break
|
||||||
self.crc(cid, ImageFile._safe_read(self.fp, len))
|
self.crc(cid, ImageFile._safe_read(self.fp, length))
|
||||||
cids.append(cid)
|
cids.append(cid)
|
||||||
|
|
||||||
return cids
|
return cids
|
||||||
|
@ -190,10 +190,10 @@ class PngStream(ChunkStream):
|
||||||
self.im_tile = None
|
self.im_tile = None
|
||||||
self.im_palette = None
|
self.im_palette = None
|
||||||
|
|
||||||
def chunk_iCCP(self, pos, len):
|
def chunk_iCCP(self, pos, length):
|
||||||
|
|
||||||
# ICC profile
|
# ICC profile
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
# according to PNG spec, the iCCP chunk contains:
|
# according to PNG spec, the iCCP chunk contains:
|
||||||
# Profile name 1-79 bytes (character string)
|
# Profile name 1-79 bytes (character string)
|
||||||
# Null separator 1 byte (null character)
|
# Null separator 1 byte (null character)
|
||||||
|
@ -213,10 +213,10 @@ class PngStream(ChunkStream):
|
||||||
self.im_info["icc_profile"] = icc_profile
|
self.im_info["icc_profile"] = icc_profile
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_IHDR(self, pos, len):
|
def chunk_IHDR(self, pos, length):
|
||||||
|
|
||||||
# image header
|
# image header
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
self.im_size = i32(s), i32(s[4:])
|
self.im_size = i32(s), i32(s[4:])
|
||||||
try:
|
try:
|
||||||
self.im_mode, self.im_rawmode = _MODES[(i8(s[8]), i8(s[9]))]
|
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")
|
raise SyntaxError("unknown filter category")
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_IDAT(self, pos, len):
|
def chunk_IDAT(self, pos, length):
|
||||||
|
|
||||||
# image data
|
# image data
|
||||||
self.im_tile = [("zip", (0,0)+self.im_size, pos, self.im_rawmode)]
|
self.im_tile = [("zip", (0,0)+self.im_size, pos, self.im_rawmode)]
|
||||||
self.im_idat = len
|
self.im_idat = length
|
||||||
raise EOFError
|
raise EOFError
|
||||||
|
|
||||||
def chunk_IEND(self, pos, len):
|
def chunk_IEND(self, pos, length):
|
||||||
|
|
||||||
# end of PNG image
|
# end of PNG image
|
||||||
raise EOFError
|
raise EOFError
|
||||||
|
|
||||||
def chunk_PLTE(self, pos, len):
|
def chunk_PLTE(self, pos, length):
|
||||||
|
|
||||||
# palette
|
# palette
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
if self.im_mode == "P":
|
if self.im_mode == "P":
|
||||||
self.im_palette = "RGB", s
|
self.im_palette = "RGB", s
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_tRNS(self, pos, len):
|
def chunk_tRNS(self, pos, length):
|
||||||
|
|
||||||
# transparency
|
# transparency
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
if self.im_mode == "P":
|
if self.im_mode == "P":
|
||||||
if _simple_palette.match(s):
|
if _simple_palette.match(s):
|
||||||
i = s.find(b"\0")
|
i = s.find(b"\0")
|
||||||
|
@ -265,17 +265,17 @@ class PngStream(ChunkStream):
|
||||||
self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
|
self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_gAMA(self, pos, len):
|
def chunk_gAMA(self, pos, length):
|
||||||
|
|
||||||
# gamma setting
|
# gamma setting
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
self.im_info["gamma"] = i32(s) / 100000.0
|
self.im_info["gamma"] = i32(s) / 100000.0
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_pHYs(self, pos, len):
|
def chunk_pHYs(self, pos, length):
|
||||||
|
|
||||||
# pixels per unit
|
# pixels per unit
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
px, py = i32(s), i32(s[4:])
|
px, py = i32(s), i32(s[4:])
|
||||||
unit = i8(s[8])
|
unit = i8(s[8])
|
||||||
if unit == 1: # meter
|
if unit == 1: # meter
|
||||||
|
@ -285,10 +285,10 @@ class PngStream(ChunkStream):
|
||||||
self.im_info["aspect"] = px, py
|
self.im_info["aspect"] = px, py
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_tEXt(self, pos, len):
|
def chunk_tEXt(self, pos, length):
|
||||||
|
|
||||||
# text
|
# text
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
try:
|
try:
|
||||||
k, v = s.split(b"\0", 1)
|
k, v = s.split(b"\0", 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -301,10 +301,10 @@ class PngStream(ChunkStream):
|
||||||
self.im_info[k] = self.im_text[k] = v
|
self.im_info[k] = self.im_text[k] = v
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunk_zTXt(self, pos, len):
|
def chunk_zTXt(self, pos, length):
|
||||||
|
|
||||||
# compressed text
|
# compressed text
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
try:
|
try:
|
||||||
k, v = s.split(b"\0", 1)
|
k, v = s.split(b"\0", 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -358,16 +358,16 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
#
|
#
|
||||||
# get next chunk
|
# get next chunk
|
||||||
|
|
||||||
cid, pos, len = self.png.read()
|
cid, pos, length = self.png.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
s = self.png.call(cid, pos, len)
|
s = self.png.call(cid, pos, length)
|
||||||
except EOFError:
|
except EOFError:
|
||||||
break
|
break
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if Image.DEBUG:
|
if Image.DEBUG:
|
||||||
print(cid, pos, len, "(unknown)")
|
print(cid, pos, length, "(unknown)")
|
||||||
s = ImageFile._safe_read(self.fp, len)
|
s = ImageFile._safe_read(self.fp, length)
|
||||||
|
|
||||||
self.png.crc(cid, s)
|
self.png.crc(cid, s)
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
rawmode, data = self.png.im_palette
|
rawmode, data = self.png.im_palette
|
||||||
self.palette = ImagePalette.raw(rawmode, data)
|
self.palette = ImagePalette.raw(rawmode, data)
|
||||||
|
|
||||||
self.__idat = len # used by load_read()
|
self.__idat = length # used by load_read()
|
||||||
|
|
||||||
|
|
||||||
def verify(self):
|
def verify(self):
|
||||||
|
@ -413,7 +413,7 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
ImageFile.ImageFile.load_prepare(self)
|
ImageFile.ImageFile.load_prepare(self)
|
||||||
|
|
||||||
def load_read(self, bytes):
|
def load_read(self, read_bytes):
|
||||||
"internal: read more image data"
|
"internal: read more image data"
|
||||||
|
|
||||||
while self.__idat == 0:
|
while self.__idat == 0:
|
||||||
|
@ -421,23 +421,23 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
self.fp.read(4) # CRC
|
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"]:
|
if cid not in [b"IDAT", b"DDAT"]:
|
||||||
self.png.push(cid, pos, len)
|
self.png.push(cid, pos, length)
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
self.__idat = len # empty chunks are allowed
|
self.__idat = length # empty chunks are allowed
|
||||||
|
|
||||||
# read more data from this chunk
|
# read more data from this chunk
|
||||||
if bytes <= 0:
|
if read_bytes <= 0:
|
||||||
bytes = self.__idat
|
read_bytes = self.__idat
|
||||||
else:
|
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):
|
def load_end(self):
|
||||||
|
|
BIN
Tests/images/junk_jpeg_header.jpg
Normal file
BIN
Tests/images/junk_jpeg_header.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
|
@ -12,6 +12,7 @@ if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
|
|
||||||
test_file = "Images/lena.jpg"
|
test_file = "Images/lena.jpg"
|
||||||
|
|
||||||
|
|
||||||
def roundtrip(im, **options):
|
def roundtrip(im, **options):
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
im.save(out, "JPEG", **options)
|
im.save(out, "JPEG", **options)
|
||||||
|
@ -23,6 +24,7 @@ def roundtrip(im, **options):
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def test_sanity():
|
def test_sanity():
|
||||||
|
|
||||||
# internal version number
|
# internal version number
|
||||||
|
@ -34,6 +36,7 @@ def test_sanity():
|
||||||
assert_equal(im.size, (128, 128))
|
assert_equal(im.size, (128, 128))
|
||||||
assert_equal(im.format, "JPEG")
|
assert_equal(im.format, "JPEG")
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
def test_app():
|
def test_app():
|
||||||
|
@ -44,6 +47,7 @@ def test_app():
|
||||||
assert_equal(im.applist[1], ("COM", b"Python Imaging Library"))
|
assert_equal(im.applist[1], ("COM", b"Python Imaging Library"))
|
||||||
assert_equal(len(im.applist), 2)
|
assert_equal(len(im.applist), 2)
|
||||||
|
|
||||||
|
|
||||||
def test_cmyk():
|
def test_cmyk():
|
||||||
# Test CMYK handling. Thanks to Tim and Charlie for test data,
|
# Test CMYK handling. Thanks to Tim and Charlie for test data,
|
||||||
# Michael for getting me to look one more time.
|
# 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))]
|
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)
|
assert_true(k > 0.9)
|
||||||
|
|
||||||
|
|
||||||
def test_dpi():
|
def test_dpi():
|
||||||
def test(xdpi, ydpi=None):
|
def test(xdpi, ydpi=None):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
|
@ -72,6 +77,7 @@ def test_dpi():
|
||||||
assert_equal(test(100, 200), (100, 200))
|
assert_equal(test(100, 200), (100, 200))
|
||||||
assert_equal(test(0), None) # square pixels
|
assert_equal(test(0), None) # square pixels
|
||||||
|
|
||||||
|
|
||||||
def test_icc():
|
def test_icc():
|
||||||
# Test ICC support
|
# Test ICC support
|
||||||
im1 = Image.open("Tests/images/rgb.jpg")
|
im1 = Image.open("Tests/images/rgb.jpg")
|
||||||
|
@ -89,6 +95,7 @@ def test_icc():
|
||||||
assert_false(im1.info.get("icc_profile"))
|
assert_false(im1.info.get("icc_profile"))
|
||||||
assert_true(im2.info.get("icc_profile"))
|
assert_true(im2.info.get("icc_profile"))
|
||||||
|
|
||||||
|
|
||||||
def test_icc_big():
|
def test_icc_big():
|
||||||
# Make sure that the "extra" support handles large blocks
|
# Make sure that the "extra" support handles large blocks
|
||||||
def test(n):
|
def test(n):
|
||||||
|
@ -99,20 +106,25 @@ def test_icc_big():
|
||||||
assert len(icc_profile) == n # sanity
|
assert len(icc_profile) == n # sanity
|
||||||
im1 = roundtrip(lena(), icc_profile=icc_profile)
|
im1 = roundtrip(lena(), icc_profile=icc_profile)
|
||||||
assert_equal(im1.info.get("icc_profile"), icc_profile or None)
|
assert_equal(im1.info.get("icc_profile"), icc_profile or None)
|
||||||
test(0); test(1)
|
test(0)
|
||||||
test(3); test(4); test(5)
|
test(1)
|
||||||
|
test(3)
|
||||||
|
test(4)
|
||||||
|
test(5)
|
||||||
test(65533-14) # full JPEG marker block
|
test(65533-14) # full JPEG marker block
|
||||||
test(65533-14+1) # full block plus one byte
|
test(65533-14+1) # full block plus one byte
|
||||||
test(ImageFile.MAXBLOCK) # full buffer block
|
test(ImageFile.MAXBLOCK) # full buffer block
|
||||||
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
|
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
|
||||||
test(ImageFile.MAXBLOCK*4+3) # large block
|
test(ImageFile.MAXBLOCK*4+3) # large block
|
||||||
|
|
||||||
|
|
||||||
def test_optimize():
|
def test_optimize():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), optimize=1)
|
im2 = roundtrip(lena(), optimize=1)
|
||||||
assert_image_equal(im1, im2)
|
assert_image_equal(im1, im2)
|
||||||
assert_true(im1.bytes >= im2.bytes)
|
assert_true(im1.bytes >= im2.bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_optimize_large_buffer():
|
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')
|
f = tempfile('temp.jpg')
|
||||||
|
@ -120,18 +132,21 @@ def test_optimize_large_buffer():
|
||||||
im = Image.new("RGB", (4096, 4096), 0xff3333)
|
im = Image.new("RGB", (4096, 4096), 0xff3333)
|
||||||
im.save(f, format="JPEG", optimize=True)
|
im.save(f, format="JPEG", optimize=True)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive():
|
def test_progressive():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), progressive=True)
|
im2 = roundtrip(lena(), progressive=True)
|
||||||
assert_image_equal(im1, im2)
|
assert_image_equal(im1, im2)
|
||||||
assert_true(im1.bytes >= im2.bytes)
|
assert_true(im1.bytes >= im2.bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive_large_buffer():
|
def test_progressive_large_buffer():
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
# this requires ~ 1.5x Image.MAXBLOCK
|
# 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)
|
im.save(f, format="JPEG", progressive=True)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive_large_buffer_highest_quality():
|
def test_progressive_large_buffer_highest_quality():
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
if py3:
|
if py3:
|
||||||
|
@ -142,12 +157,14 @@ def test_progressive_large_buffer_highest_quality():
|
||||||
# this requires more bytes than pixels in the image
|
# this requires more bytes than pixels in the image
|
||||||
im.save(f, format="JPEG", progressive=True, quality=100)
|
im.save(f, format="JPEG", progressive=True, quality=100)
|
||||||
|
|
||||||
|
|
||||||
def test_large_exif():
|
def test_large_exif():
|
||||||
# https://github.com/python-imaging/Pillow/issues/148
|
# https://github.com/python-imaging/Pillow/issues/148
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
im = lena()
|
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():
|
def test_progressive_compat():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), progressive=1)
|
im2 = roundtrip(lena(), progressive=1)
|
||||||
|
@ -161,17 +178,20 @@ def test_progressive_compat():
|
||||||
assert_true(im3.info.get("progressive"))
|
assert_true(im3.info.get("progressive"))
|
||||||
assert_true(im3.info.get("progression"))
|
assert_true(im3.info.get("progression"))
|
||||||
|
|
||||||
|
|
||||||
def test_quality():
|
def test_quality():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), quality=50)
|
im2 = roundtrip(lena(), quality=50)
|
||||||
assert_image(im1, im2.mode, im2.size)
|
assert_image(im1, im2.mode, im2.size)
|
||||||
assert_true(im1.bytes >= im2.bytes)
|
assert_true(im1.bytes >= im2.bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_smooth():
|
def test_smooth():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), smooth=100)
|
im2 = roundtrip(lena(), smooth=100)
|
||||||
assert_image(im1, im2.mode, im2.size)
|
assert_image(im1, im2.mode, im2.size)
|
||||||
|
|
||||||
|
|
||||||
def test_subsampling():
|
def test_subsampling():
|
||||||
def getsampling(im):
|
def getsampling(im):
|
||||||
layer = im.layer
|
layer = im.layer
|
||||||
|
@ -197,6 +217,7 @@ def test_subsampling():
|
||||||
|
|
||||||
assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1"))
|
assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1"))
|
||||||
|
|
||||||
|
|
||||||
def test_exif():
|
def test_exif():
|
||||||
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||||
info = im._getexif()
|
info = im._getexif()
|
||||||
|
@ -207,3 +228,11 @@ def test_quality_keep():
|
||||||
im = Image.open("Images/lena.jpg")
|
im = Image.open("Images/lena.jpg")
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
assert_no_exception(lambda: im.save(f, quality='keep'))
|
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
|
||||||
|
|
58
Tests/test_file_pdf.py
Normal file
58
Tests/test_file_pdf.py
Normal 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
|
|
@ -2,6 +2,7 @@ from tester import *
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
def test_sanity():
|
def test_sanity():
|
||||||
|
|
||||||
def convert(im, mode):
|
def convert(im, mode):
|
||||||
|
@ -16,6 +17,7 @@ def test_sanity():
|
||||||
for mode in modes:
|
for mode in modes:
|
||||||
yield_test(convert, im, mode)
|
yield_test(convert, im, mode)
|
||||||
|
|
||||||
|
|
||||||
def test_default():
|
def test_default():
|
||||||
|
|
||||||
im = lena("P")
|
im = lena("P")
|
||||||
|
@ -26,7 +28,6 @@ def test_default():
|
||||||
assert_image(im, "RGB", im.size)
|
assert_image(im, "RGB", im.size)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ref https://github.com/python-imaging/Pillow/issues/274
|
# ref https://github.com/python-imaging/Pillow/issues/274
|
||||||
|
|
||||||
def _test_float_conversion(im):
|
def _test_float_conversion(im):
|
||||||
|
@ -34,18 +35,22 @@ def _test_float_conversion(im):
|
||||||
converted = im.convert('F').getpixel((5, 5))
|
converted = im.convert('F').getpixel((5, 5))
|
||||||
assert_equal(orig, converted)
|
assert_equal(orig, converted)
|
||||||
|
|
||||||
|
|
||||||
def test_8bit():
|
def test_8bit():
|
||||||
im = Image.open('Images/lena.jpg')
|
im = Image.open('Images/lena.jpg')
|
||||||
_test_float_conversion(im.convert('L'))
|
_test_float_conversion(im.convert('L'))
|
||||||
|
|
||||||
|
|
||||||
def test_16bit():
|
def test_16bit():
|
||||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
im = Image.open('Tests/images/16bit.cropped.tif')
|
||||||
_test_float_conversion(im)
|
_test_float_conversion(im)
|
||||||
|
|
||||||
|
|
||||||
def test_16bit_workaround():
|
def test_16bit_workaround():
|
||||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
im = Image.open('Tests/images/16bit.cropped.tif')
|
||||||
_test_float_conversion(im.convert('I'))
|
_test_float_conversion(im.convert('I'))
|
||||||
|
|
||||||
|
|
||||||
def test_rgba_p():
|
def test_rgba_p():
|
||||||
im = lena('RGBA')
|
im = lena('RGBA')
|
||||||
im.putalpha(lena('L'))
|
im.putalpha(lena('L'))
|
||||||
|
@ -55,6 +60,7 @@ def test_rgba_p():
|
||||||
|
|
||||||
assert_image_similar(im, comparable, 20)
|
assert_image_similar(im, comparable, 20)
|
||||||
|
|
||||||
|
|
||||||
def test_trns_p():
|
def test_trns_p():
|
||||||
im = lena('P')
|
im = lena('P')
|
||||||
im.info['transparency'] = 0
|
im.info['transparency'] = 0
|
||||||
|
@ -65,11 +71,25 @@ def test_trns_p():
|
||||||
assert_equal(l.info['transparency'], 0) # undone
|
assert_equal(l.info['transparency'], 0) # undone
|
||||||
assert_no_exception(lambda: l.save(f))
|
assert_no_exception(lambda: l.save(f))
|
||||||
|
|
||||||
|
|
||||||
rgb = im.convert('RGB')
|
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))
|
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():
|
def test_trns_l():
|
||||||
im = lena('L')
|
im = lena('L')
|
||||||
im.info['transparency'] = 128
|
im.info['transparency'] = 128
|
||||||
|
@ -108,5 +128,3 @@ def test_trns_RGB():
|
||||||
lambda: im.convert('P', palette=Image.ADAPTIVE))
|
lambda: im.convert('P', palette=Image.ADAPTIVE))
|
||||||
assert_false('transparency' in p.info)
|
assert_false('transparency' in p.info)
|
||||||
assert_no_exception(lambda: p.save(f))
|
assert_no_exception(lambda: p.save(f))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,9 @@ def _setup():
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if "--coverage" in sys.argv:
|
if "--coverage" in sys.argv:
|
||||||
|
# Temporary: ignore PendingDeprecationWarning from Coverage (Py3.4)
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
import coverage
|
import coverage
|
||||||
cov = coverage.coverage(auto_data=True, include="PIL/*")
|
cov = coverage.coverage(auto_data=True, include="PIL/*")
|
||||||
cov.start()
|
cov.start()
|
||||||
|
|
|
@ -3350,7 +3350,7 @@ extern PyObject* PyImaging_ZipEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args);
|
||||||
|
|
||||||
/* Display support etc (in display.c) */
|
/* Display support etc (in display.c) */
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
extern PyObject* PyImaging_CreateWindowWin32(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_CreateWindowWin32(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_DisplayWin32(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_DisplayWin32(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_DisplayModeWin32(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_DisplayModeWin32(PyObject* self, PyObject* args);
|
||||||
|
@ -3423,14 +3423,14 @@ static PyMethodDef functions[] = {
|
||||||
|
|
||||||
/* Memory mapping */
|
/* Memory mapping */
|
||||||
#ifdef WITH_MAPPING
|
#ifdef WITH_MAPPING
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
{"map", (PyCFunction)PyImaging_Mapper, 1},
|
{"map", (PyCFunction)PyImaging_Mapper, 1},
|
||||||
#endif
|
#endif
|
||||||
{"map_buffer", (PyCFunction)PyImaging_MapBuffer, 1},
|
{"map_buffer", (PyCFunction)PyImaging_MapBuffer, 1},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Display support */
|
/* Display support */
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
{"display", (PyCFunction)PyImaging_DisplayWin32, 1},
|
{"display", (PyCFunction)PyImaging_DisplayWin32, 1},
|
||||||
{"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, 1},
|
{"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, 1},
|
||||||
{"grabscreen", (PyCFunction)PyImaging_GrabScreenWin32, 1},
|
{"grabscreen", (PyCFunction)PyImaging_GrabScreenWin32, 1},
|
||||||
|
|
|
@ -28,12 +28,6 @@ http://www.cazabon.com\n\
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
#include "py3.h"
|
#include "py3.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#include <windef.h>
|
|
||||||
#include <wingdi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PYCMSVERSION "1.0.0 pil"
|
#define PYCMSVERSION "1.0.0 pil"
|
||||||
|
|
||||||
/* version history */
|
/* version history */
|
||||||
|
@ -450,7 +444,7 @@ cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args)
|
||||||
return PyInt_FromLong(result != 0);
|
return PyInt_FromLong(result != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
static PyObject *
|
static PyObject *
|
||||||
cms_get_display_profile_win32(PyObject* self, PyObject* args)
|
cms_get_display_profile_win32(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
|
@ -496,7 +490,7 @@ static PyMethodDef pyCMSdll_methods[] = {
|
||||||
{"createProfile", createProfile, 1},
|
{"createProfile", createProfile, 1},
|
||||||
|
|
||||||
/* platform specific tools */
|
/* platform specific tools */
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
{"get_display_profile_win32", cms_get_display_profile_win32, 1},
|
{"get_display_profile_win32", cms_get_display_profile_win32, 1},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
3
decode.c
3
decode.c
|
@ -433,9 +433,6 @@ PyImaging_TiffLzwDecoderNew(PyObject* self, PyObject* args)
|
||||||
#include "TiffDecode.h"
|
#include "TiffDecode.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef __WIN32__
|
|
||||||
#define strcasecmp(s1, s2) stricmp(s1, s2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
|
PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Windows DIB support */
|
/* Windows DIB support */
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include "ImDib.h"
|
#include "ImDib.h"
|
||||||
|
|
||||||
|
@ -864,4 +864,4 @@ error:
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
3
encode.c
3
encode.c
|
@ -670,9 +670,6 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
||||||
#include "TiffDecode.h"
|
#include "TiffDecode.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef __WIN32__
|
|
||||||
#define strcasecmp(s1, s2) stricmp(s1, s2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include "ImDib.h"
|
#include "ImDib.h"
|
||||||
|
|
||||||
|
@ -308,4 +308,4 @@ ImagingDeleteDIB(ImagingDIB dib)
|
||||||
free(dib->info);
|
free(dib->info);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
|
@ -59,7 +59,7 @@ typedef struct {
|
||||||
unsigned char buffer[GIFTABLE];
|
unsigned char buffer[GIFTABLE];
|
||||||
|
|
||||||
/* Symbol table */
|
/* Symbol table */
|
||||||
unsigned INT16 link[GIFTABLE];
|
UINT16 link[GIFTABLE];
|
||||||
unsigned char data[GIFTABLE];
|
unsigned char data[GIFTABLE];
|
||||||
int next;
|
int next;
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,9 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#if (defined(_MSC_VER) && _MSC_VER >= 1200) || (defined __GNUC__)
|
#include "ImPlatform.h"
|
||||||
/* already defined in basetsd.h */
|
|
||||||
#undef INT8
|
|
||||||
#undef UINT8
|
|
||||||
#undef INT16
|
|
||||||
#undef UINT16
|
|
||||||
#undef INT32
|
|
||||||
#undef INT64
|
|
||||||
#undef UINT32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -17,26 +17,22 @@
|
||||||
#error Sorry, this library requires ANSI header files.
|
#error Sorry, this library requires ANSI header files.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER) && !defined(__GNUC__)
|
||||||
#ifndef WIN32
|
#define inline __inline
|
||||||
#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' */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if !defined(PIL_USE_INLINE)
|
||||||
#define inline __inline
|
|
||||||
#elif !defined(USE_INLINE)
|
|
||||||
#define inline
|
#define inline
|
||||||
#endif
|
#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
|
#if SIZEOF_SHORT == 2
|
||||||
#define INT16 short
|
#define INT16 short
|
||||||
#elif SIZEOF_INT == 2
|
#elif SIZEOF_INT == 2
|
||||||
|
@ -61,12 +57,16 @@
|
||||||
#define INT64 long
|
#define INT64 long
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* assume IEEE; tweak if necessary (patches are welcome) */
|
|
||||||
#define FLOAT32 float
|
|
||||||
#define FLOAT64 double
|
|
||||||
|
|
||||||
#define INT8 signed char
|
#define INT8 signed char
|
||||||
#define UINT8 unsigned char
|
#define UINT8 unsigned char
|
||||||
|
|
||||||
#define UINT16 unsigned INT16
|
#define UINT16 unsigned INT16
|
||||||
#define UINT32 unsigned INT32
|
#define UINT32 unsigned INT32
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* assume IEEE; tweak if necessary (patches are welcome) */
|
||||||
|
#define FLOAT32 float
|
||||||
|
#define FLOAT64 double
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
two cases. */
|
two cases. */
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#else
|
#else
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
|
@ -45,7 +45,7 @@ typedef struct {
|
||||||
unsigned char buffer[LZWTABLE];
|
unsigned char buffer[LZWTABLE];
|
||||||
|
|
||||||
/* Symbol table */
|
/* Symbol table */
|
||||||
unsigned INT16 link[LZWTABLE];
|
UINT16 link[LZWTABLE];
|
||||||
unsigned char data[LZWTABLE];
|
unsigned char data[LZWTABLE];
|
||||||
int next;
|
int next;
|
||||||
|
|
||||||
|
|
18
map.c
18
map.c
|
@ -22,18 +22,6 @@
|
||||||
|
|
||||||
#include "Imaging.h"
|
#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"
|
#include "py3.h"
|
||||||
|
|
||||||
/* compatibility wrappers (defined in _imaging.c) */
|
/* compatibility wrappers (defined in _imaging.c) */
|
||||||
|
@ -48,7 +36,7 @@ typedef struct {
|
||||||
char* base;
|
char* base;
|
||||||
int size;
|
int size;
|
||||||
int offset;
|
int offset;
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hFile;
|
HANDLE hFile;
|
||||||
HANDLE hMap;
|
HANDLE hMap;
|
||||||
#endif
|
#endif
|
||||||
|
@ -71,7 +59,7 @@ PyImaging_MapperNew(const char* filename, int readonly)
|
||||||
mapper->base = NULL;
|
mapper->base = NULL;
|
||||||
mapper->size = mapper->offset = 0;
|
mapper->size = mapper->offset = 0;
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
mapper->hFile = (HANDLE)-1;
|
mapper->hFile = (HANDLE)-1;
|
||||||
mapper->hMap = (HANDLE)-1;
|
mapper->hMap = (HANDLE)-1;
|
||||||
|
|
||||||
|
@ -114,7 +102,7 @@ PyImaging_MapperNew(const char* filename, int readonly)
|
||||||
static void
|
static void
|
||||||
mapping_dealloc(ImagingMapperObject* mapper)
|
mapping_dealloc(ImagingMapperObject* mapper)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
if (mapper->base != 0)
|
if (mapper->base != 0)
|
||||||
UnmapViewOfFile(mapper->base);
|
UnmapViewOfFile(mapper->base);
|
||||||
if (mapper->hMap != (HANDLE)-1)
|
if (mapper->hMap != (HANDLE)-1)
|
||||||
|
|
26
setup.py
26
setup.py
|
@ -206,22 +206,28 @@ class pil_build_ext(build_ext):
|
||||||
_add_directory(library_dirs, "/opt/local/lib")
|
_add_directory(library_dirs, "/opt/local/lib")
|
||||||
_add_directory(include_dirs, "/opt/local/include")
|
_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
|
import subprocess
|
||||||
try:
|
try:
|
||||||
prefix = subprocess.check_output(['brew', '--prefix'])
|
prefix = subprocess.check_output(['brew', '--prefix']).strip()
|
||||||
|
except:
|
||||||
|
# Homebrew not installed
|
||||||
|
prefix = None
|
||||||
|
|
||||||
|
ft_prefix = None
|
||||||
|
|
||||||
if prefix:
|
if prefix:
|
||||||
prefix = prefix.strip()
|
# add Homebrew's include and lib directories
|
||||||
_add_directory(library_dirs, os.path.join(prefix, 'lib'))
|
_add_directory(library_dirs, os.path.join(prefix, 'lib'))
|
||||||
_add_directory(include_dirs, os.path.join(prefix, 'include'))
|
_add_directory(include_dirs, os.path.join(prefix, 'include'))
|
||||||
|
ft_prefix = os.path.join(prefix, 'opt', 'freetype')
|
||||||
|
|
||||||
# freetype2 is a key-only brew under opt/
|
if ft_prefix and os.path.isdir(ft_prefix):
|
||||||
_add_directory(library_dirs, os.path.join(prefix, 'opt', 'freetype', 'lib'))
|
# freetype might not be linked into Homebrew's prefix
|
||||||
_add_directory(include_dirs, os.path.join(prefix, 'opt', 'freetype', 'include'))
|
_add_directory(library_dirs, os.path.join(ft_prefix, 'lib'))
|
||||||
except:
|
_add_directory(include_dirs, os.path.join(ft_prefix, 'include'))
|
||||||
pass # homebrew not installed
|
else:
|
||||||
|
# fall back to freetype from XQuartz if Homebrew's freetype is missing
|
||||||
# freetype2 ships with X11 (after homebrew, so that homebrew freetype is preferred)
|
|
||||||
_add_directory(library_dirs, "/usr/X11/lib")
|
_add_directory(library_dirs, "/usr/X11/lib")
|
||||||
_add_directory(include_dirs, "/usr/X11/include")
|
_add_directory(include_dirs, "/usr/X11/include")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user