mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 23:04:45 +03:00
commit
ea72529a21
46
.travis.yml
46
.travis.yml
|
@ -54,7 +54,6 @@ after_success:
|
||||||
- travis_retry pip install coveralls-merge
|
- travis_retry pip install coveralls-merge
|
||||||
- coveralls-merge coverage.c.json
|
- coveralls-merge coverage.c.json
|
||||||
|
|
||||||
|
|
||||||
- travis_retry pip install pep8 pyflakes
|
- travis_retry pip install pep8 pyflakes
|
||||||
- pep8 --statistics --count PIL/*.py
|
- pep8 --statistics --count PIL/*.py
|
||||||
- pep8 --statistics --count Tests/*.py
|
- pep8 --statistics --count Tests/*.py
|
||||||
|
@ -62,10 +61,53 @@ after_success:
|
||||||
- pyflakes PIL/*.py | tee >(wc -l)
|
- pyflakes PIL/*.py | tee >(wc -l)
|
||||||
- pyflakes Tests/*.py | tee >(wc -l)
|
- pyflakes Tests/*.py | tee >(wc -l)
|
||||||
|
|
||||||
|
|
||||||
# Coverage and quality reports on just the latest diff.
|
# Coverage and quality reports on just the latest diff.
|
||||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
# (Installation is very slow on Py3, so just do it for Py2.)
|
||||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-install.sh; fi
|
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-install.sh; fi
|
||||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-run.sh; fi
|
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-run.sh; fi
|
||||||
|
|
||||||
|
# after_all
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_REPO_SLUG" = "python-pillow/Pillow" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||||
|
curl -Lo travis_after_all.py https://raw.github.com/dmakhno/travis_after_all/master/travis_after_all.py
|
||||||
|
python travis_after_all.py
|
||||||
|
export $(cat .to_export_back)
|
||||||
|
if [ "$BUILD_LEADER" = "YES" ]; then
|
||||||
|
if [ "$BUILD_AGGREGATE_STATUS" = "others_succeeded" ]; then
|
||||||
|
echo "All jobs succeded! Triggering OS X build..."
|
||||||
|
# Trigger an OS X build at the pillow-wheels repo
|
||||||
|
./build_children.sh
|
||||||
|
else
|
||||||
|
echo "Some jobs failed"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
after_failure:
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_REPO_SLUG" = "python-pillow/Pillow" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||||
|
curl -Lo travis_after_all.py https://raw.github.com/dmakhno/travis_after_all/master/travis_after_all.py
|
||||||
|
python travis_after_all.py
|
||||||
|
export $(cat .to_export_back)
|
||||||
|
if [ "$BUILD_LEADER" = "YES" ]; then
|
||||||
|
if [ "$BUILD_AGGREGATE_STATUS" = "others_failed" ]; then
|
||||||
|
echo "All jobs failed"
|
||||||
|
else
|
||||||
|
echo "Some jobs failed"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_REPO_SLUG" = "python-pillow/Pillow" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||||
|
echo leader=$BUILD_LEADER status=$BUILD_AGGREGATE_STATUS
|
||||||
|
fi
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# travis encrypt AUTH_TOKEN=
|
||||||
|
secure: "Vzm7aG1Qv0SDQcqiPzZMedNLn5ZmpL7IzF0DYnqcD+/l+zmKU22SnJBcX0uVXumo+r7eZfpsShpqfcdsZvMlvmQnwz+Y6AGKQru9tCKZbTMnuRjWKKXekC+tr8Xt9CKvRVtte5PyXW31paxUI3/e+fQGBwoFjEEC+6EpEOjeRfE="
|
||||||
|
|
54
CHANGES.rst
54
CHANGES.rst
|
@ -1,13 +1,55 @@
|
||||||
Changelog (Pillow)
|
Changelog (Pillow)
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
2.8.0 (unreleased)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- Improve reference docs for PIL.ImageDraw.Draw.pieslice() #1145
|
||||||
|
[audreyr]
|
||||||
|
|
||||||
|
- Added copy method font_variant() and accessible properties to truetype() #1123
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Fix ImagingEffectNoise #1128
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Remove unreachable code
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- Let Python do the endian stuff + tests #1121
|
||||||
|
[amoibos, radarhere]
|
||||||
|
|
||||||
|
- Fix webp decode memory leak #1114
|
||||||
|
[benoit-pierre]
|
||||||
|
|
||||||
|
- Fast path for opaque pixels in RGBa unpacker #1088
|
||||||
|
[bgilbert]
|
||||||
|
|
||||||
|
- Enable basic support for 'RGBa' raw encoding/decoding #1096
|
||||||
|
[immerrr]
|
||||||
|
|
||||||
|
- Fix pickling L mode images with no palette, #1095
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
|
- iPython display hook #1091
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- Adjust buffer size when quality=keep, fixes #148 (again)
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- Fix for corrupted bitmaps embedded in truetype fonts. #1072
|
||||||
|
[jackyyf, wiredfool]
|
||||||
|
|
||||||
2.7.0 (2015-01-01)
|
2.7.0 (2015-01-01)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Split Sane into a separate repo: https://github.com/python-pillow/Sane
|
||||||
|
[hugovk]
|
||||||
|
|
||||||
- Look for OSX and Linux fonts in common places. #1054
|
- Look for OSX and Linux fonts in common places. #1054
|
||||||
[charleslaw]
|
[charleslaw]
|
||||||
|
|
||||||
- Fix potential PNG decompression DOS #1060
|
- Fix CVE-2014-9601, potential PNG decompression DOS #1060
|
||||||
[wiredfool]
|
[wiredfool]
|
||||||
|
|
||||||
- Use underscores, not spaces, in TIFF tag kwargs. #1044, #1058
|
- Use underscores, not spaces, in TIFF tag kwargs. #1044, #1058
|
||||||
|
@ -22,13 +64,13 @@ Changelog (Pillow)
|
||||||
- Fix MSVC compiler error: Use Py_ssize_t instead of ssize_t #1051
|
- Fix MSVC compiler error: Use Py_ssize_t instead of ssize_t #1051
|
||||||
[cgohlke]
|
[cgohlke]
|
||||||
|
|
||||||
- Fix compiler error: MSVC needs varaibles defined at the start of the block #1048
|
- Fix compiler error: MSVC needs variables defined at the start of the block #1048
|
||||||
[cgohlke]
|
[cgohlke]
|
||||||
|
|
||||||
- The GIF Palette optimization algorithm is only applicable to mode='P' or 'L' #993
|
- The GIF Palette optimization algorithm is only applicable to mode='P' or 'L' #993
|
||||||
[moriyoshi]
|
[moriyoshi]
|
||||||
|
|
||||||
- Use PySide as an alernative to PyQt4/5.
|
- Use PySide as an alternative to PyQt4/5.
|
||||||
[holg]
|
[holg]
|
||||||
|
|
||||||
- Replace affine-based im.resize implementation with convolution-based im.stretch #997
|
- Replace affine-based im.resize implementation with convolution-based im.stretch #997
|
||||||
|
@ -82,7 +124,7 @@ Changelog (Pillow)
|
||||||
2.6.2 (2015-01-01)
|
2.6.2 (2015-01-01)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- Fix potential PNG decompression DOS #1060
|
- Fix CVE-2014-9601, potential PNG decompression DOS #1060
|
||||||
[wiredfool]
|
[wiredfool]
|
||||||
|
|
||||||
- Fix Regression in PyPy 2.4 in streamio #958
|
- Fix Regression in PyPy 2.4 in streamio #958
|
||||||
|
@ -1757,7 +1799,7 @@ Changelog (Pillow)
|
||||||
(1.1.2c1 and 1.1.2 final released)
|
(1.1.2c1 and 1.1.2 final released)
|
||||||
|
|
||||||
+ Adapted to Python 2.1. Among other things, all uses of the
|
+ Adapted to Python 2.1. Among other things, all uses of the
|
||||||
"regex" module has been repleased with "re".
|
"regex" module have been replaced with "re".
|
||||||
|
|
||||||
+ Fixed attribute error when reading large PNG files (this bug
|
+ Fixed attribute error when reading large PNG files (this bug
|
||||||
was introduced in maintenance code released after the 1.1.1
|
was introduced in maintenance code released after the 1.1.1
|
||||||
|
@ -2381,7 +2423,7 @@ Changelog (Pillow)
|
||||||
the default value is 75.
|
the default value is 75.
|
||||||
|
|
||||||
JPEG smooth smooth dithered images. value
|
JPEG smooth smooth dithered images. value
|
||||||
is strengh (1-100). default is
|
is strength (1-100). default is
|
||||||
off (0).
|
off (0).
|
||||||
|
|
||||||
PNG optimize minimize output file at the
|
PNG optimize minimize output file at the
|
||||||
|
|
|
@ -2,6 +2,7 @@ include *.c
|
||||||
include *.h
|
include *.h
|
||||||
include *.md
|
include *.md
|
||||||
include *.py
|
include *.py
|
||||||
|
include *.sh
|
||||||
include *.rst
|
include *.rst
|
||||||
include *.txt
|
include *.txt
|
||||||
include *.yaml
|
include *.yaml
|
||||||
|
|
|
@ -273,7 +273,7 @@ class IcoImageFile(ImageFile.ImageFile):
|
||||||
self.size = im.size
|
self.size = im.size
|
||||||
|
|
||||||
def load_seek(self):
|
def load_seek(self):
|
||||||
# Flage the ImageFile.Parser so that it
|
# Flag the ImageFile.Parser so that it
|
||||||
# just does all the decode at the end.
|
# just does all the decode at the end.
|
||||||
pass
|
pass
|
||||||
#
|
#
|
||||||
|
|
14
PIL/Image.py
14
PIL/Image.py
|
@ -598,6 +598,16 @@ class Image:
|
||||||
id(self)
|
id(self)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _repr_png_(self):
|
||||||
|
""" iPython display hook support
|
||||||
|
|
||||||
|
:returns: png version of the image as bytes
|
||||||
|
"""
|
||||||
|
from io import BytesIO
|
||||||
|
b = BytesIO()
|
||||||
|
self.save(b, 'PNG')
|
||||||
|
return b.getvalue()
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name == "__array_interface__":
|
if name == "__array_interface__":
|
||||||
# numpy array interface support
|
# numpy array interface support
|
||||||
|
@ -625,7 +635,7 @@ class Image:
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.size = size
|
self.size = size
|
||||||
self.im = core.new(mode, size)
|
self.im = core.new(mode, size)
|
||||||
if mode in ("L", "P"):
|
if mode in ("L", "P") and palette:
|
||||||
self.putpalette(palette)
|
self.putpalette(palette)
|
||||||
self.frombytes(data)
|
self.frombytes(data)
|
||||||
|
|
||||||
|
@ -2024,7 +2034,7 @@ def frombytes(mode, size, data, decoder_name="raw", *args):
|
||||||
|
|
||||||
You can also use any pixel decoder supported by PIL. For more
|
You can also use any pixel decoder supported by PIL. For more
|
||||||
information on available decoders, see the section
|
information on available decoders, see the section
|
||||||
**Writing Your Own File Decoder**.
|
:ref:`Writing Your Own File Decoder <file-decoders>`.
|
||||||
|
|
||||||
Note that this function decodes pixel data only, not entire images.
|
Note that this function decodes pixel data only, not entire images.
|
||||||
If you have an entire image in a string, wrap it in a
|
If you have an entire image in a string, wrap it in a
|
||||||
|
|
|
@ -133,6 +133,11 @@ class FreeTypeFont:
|
||||||
DeprecationWarning)
|
DeprecationWarning)
|
||||||
font = file
|
font = file
|
||||||
|
|
||||||
|
self.path = font
|
||||||
|
self.size = size
|
||||||
|
self.index = index
|
||||||
|
self.encoding = encoding
|
||||||
|
|
||||||
if isPath(font):
|
if isPath(font):
|
||||||
self.font = core.getfont(font, size, index, encoding)
|
self.font = core.getfont(font, size, index, encoding)
|
||||||
else:
|
else:
|
||||||
|
@ -162,6 +167,22 @@ class FreeTypeFont:
|
||||||
self.font.render(text, im.id, mode == "1")
|
self.font.render(text, im.id, mode == "1")
|
||||||
return im, offset
|
return im, offset
|
||||||
|
|
||||||
|
def font_variant(self, font=None, size=None, index=None, encoding=None):
|
||||||
|
"""
|
||||||
|
Create a copy of this FreeTypeFont object,
|
||||||
|
using any specified arguments to override the settings.
|
||||||
|
|
||||||
|
Parameters are identical to the parameters used to initialize this
|
||||||
|
object, minus the deprecated 'file' argument.
|
||||||
|
|
||||||
|
:return: A FreeTypeFont object.
|
||||||
|
"""
|
||||||
|
return FreeTypeFont(font=self.path if font is None else font,
|
||||||
|
size=self.size if size is None else size,
|
||||||
|
index=self.index if index is None else index,
|
||||||
|
encoding=self.encoding if encoding is None else
|
||||||
|
encoding)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Wrapper that creates a transposed font from any existing font
|
# Wrapper that creates a transposed font from any existing font
|
||||||
# object.
|
# object.
|
||||||
|
@ -214,7 +235,7 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
|
||||||
|
|
||||||
This function requires the _imagingft service.
|
This function requires the _imagingft service.
|
||||||
|
|
||||||
:param filename: A truetype font file. Under Windows, if the file
|
:param font: A truetype font file. Under Windows, if the file
|
||||||
is not found in this filename, the loader also looks in
|
is not found in this filename, the loader also looks in
|
||||||
Windows :file:`fonts/` directory.
|
Windows :file:`fonts/` directory.
|
||||||
:param size: The requested size, in points.
|
:param size: The requested size, in points.
|
||||||
|
@ -224,6 +245,7 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
|
||||||
Symbol), "ADOB" (Adobe Standard), "ADBE" (Adobe Expert),
|
Symbol), "ADOB" (Adobe Standard), "ADBE" (Adobe Expert),
|
||||||
and "armn" (Apple Roman). See the FreeType documentation
|
and "armn" (Apple Roman). See the FreeType documentation
|
||||||
for more information.
|
for more information.
|
||||||
|
:param filename: Deprecated. Please use font instead.
|
||||||
:return: A font object.
|
:return: A font object.
|
||||||
:exception IOError: If the file could not be read.
|
:exception IOError: If the file could not be read.
|
||||||
"""
|
"""
|
||||||
|
@ -254,8 +276,8 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
|
||||||
elif sys.platform in ('linux', 'linux2'):
|
elif sys.platform in ('linux', 'linux2'):
|
||||||
lindirs = os.environ.get("XDG_DATA_DIRS", "")
|
lindirs = os.environ.get("XDG_DATA_DIRS", "")
|
||||||
if not lindirs:
|
if not lindirs:
|
||||||
#According to the freedesktop spec, XDG_DATA_DIRS should
|
# According to the freedesktop spec, XDG_DATA_DIRS should
|
||||||
#default to /usr/share
|
# default to /usr/share
|
||||||
lindirs = '/usr/share'
|
lindirs = '/usr/share'
|
||||||
lindirs = lindirs.split(":")
|
lindirs = lindirs.split(":")
|
||||||
for lindir in lindirs:
|
for lindir in lindirs:
|
||||||
|
@ -265,7 +287,8 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
|
||||||
filepath = os.path.join(walkroot, ttf_filename)
|
filepath = os.path.join(walkroot, ttf_filename)
|
||||||
return FreeTypeFont(filepath, size, index, encoding)
|
return FreeTypeFont(filepath, size, index, encoding)
|
||||||
elif sys.platform == 'darwin':
|
elif sys.platform == 'darwin':
|
||||||
macdirs = ['/Library/Fonts/', '/System/Library/Fonts/', os.path.expanduser('~/Library/Fonts/')]
|
macdirs = ['/Library/Fonts/', '/System/Library/Fonts/',
|
||||||
|
os.path.expanduser('~/Library/Fonts/')]
|
||||||
for macdir in macdirs:
|
for macdir in macdirs:
|
||||||
filepath = os.path.join(macdir, ttf_filename)
|
filepath = os.path.join(macdir, ttf_filename)
|
||||||
if os.path.exists(filepath):
|
if os.path.exists(filepath):
|
||||||
|
|
|
@ -684,7 +684,8 @@ def _save(im, fp, filename):
|
||||||
# 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:
|
||||||
if quality >= 95:
|
# keep sets quality to 0, but the actual value may be high.
|
||||||
|
if quality >= 95 or quality == 0:
|
||||||
bufsize = 2 * im.size[0] * im.size[1]
|
bufsize = 2 * im.size[0] * im.size[1]
|
||||||
else:
|
else:
|
||||||
bufsize = im.size[0] * im.size[1]
|
bufsize = im.size[0] * im.size[1]
|
||||||
|
|
|
@ -729,10 +729,6 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
|
||||||
alpha_bytes = 2**bits
|
alpha_bytes = 2**bits
|
||||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||||
|
|
||||||
if 0:
|
|
||||||
# FIXME: to be supported some day
|
|
||||||
chunk(fp, b"gAMA", o32(int(gamma * 100000.0)))
|
|
||||||
|
|
||||||
dpi = im.encoderinfo.get("dpi")
|
dpi = im.encoderinfo.get("dpi")
|
||||||
if dpi:
|
if dpi:
|
||||||
chunk(fp, b"pHYs",
|
chunk(fp, b"pHYs",
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from struct import unpack, pack
|
||||||
|
|
||||||
if bytes is str:
|
if bytes is str:
|
||||||
def i8(c):
|
def i8(c):
|
||||||
return ord(c)
|
return ord(c)
|
||||||
|
@ -34,7 +36,7 @@ def i16le(c, o=0):
|
||||||
c: string containing bytes to convert
|
c: string containing bytes to convert
|
||||||
o: offset of bytes to convert in string
|
o: offset of bytes to convert in string
|
||||||
"""
|
"""
|
||||||
return i8(c[o]) | (i8(c[o+1]) << 8)
|
return unpack("<H", c[o:o+2])[0]
|
||||||
|
|
||||||
|
|
||||||
def i32le(c, o=0):
|
def i32le(c, o=0):
|
||||||
|
@ -44,33 +46,31 @@ def i32le(c, o=0):
|
||||||
c: string containing bytes to convert
|
c: string containing bytes to convert
|
||||||
o: offset of bytes to convert in string
|
o: offset of bytes to convert in string
|
||||||
"""
|
"""
|
||||||
return (i8(c[o]) | (i8(c[o+1]) << 8) | (i8(c[o+2]) << 16) |
|
return unpack("<I", c[o:o+4])[0]
|
||||||
(i8(c[o+3]) << 24))
|
|
||||||
|
|
||||||
|
|
||||||
def i16be(c, o=0):
|
def i16be(c, o=0):
|
||||||
return (i8(c[o]) << 8) | i8(c[o+1])
|
return unpack(">H", c[o:o+2])[0]
|
||||||
|
|
||||||
|
|
||||||
def i32be(c, o=0):
|
def i32be(c, o=0):
|
||||||
return ((i8(c[o]) << 24) | (i8(c[o+1]) << 16) |
|
return unpack(">I", c[o:o+4])[0]
|
||||||
(i8(c[o+2]) << 8) | i8(c[o+3]))
|
|
||||||
|
|
||||||
|
|
||||||
# Output, le = little endian, be = big endian
|
# Output, le = little endian, be = big endian
|
||||||
def o16le(i):
|
def o16le(i):
|
||||||
return o8(i) + o8(i >> 8)
|
return pack("<H", i)
|
||||||
|
|
||||||
|
|
||||||
def o32le(i):
|
def o32le(i):
|
||||||
return o8(i) + o8(i >> 8) + o8(i >> 16) + o8(i >> 24)
|
return pack("<I", i)
|
||||||
|
|
||||||
|
|
||||||
def o16be(i):
|
def o16be(i):
|
||||||
return o8(i >> 8) + o8(i)
|
return pack(">H", i)
|
||||||
|
|
||||||
|
|
||||||
def o32be(i):
|
def o32be(i):
|
||||||
return o8(i >> 24) + o8(i >> 16) + o8(i >> 8) + o8(i)
|
return pack(">I", i)
|
||||||
|
|
||||||
# End of file
|
# End of file
|
||||||
|
|
23
README.rst
23
README.rst
|
@ -1,13 +1,18 @@
|
||||||
Pillow
|
Pillow
|
||||||
======
|
======
|
||||||
|
|
||||||
*Python Imaging Library (Fork)*
|
Python Imaging Library (Fork)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
Pillow is the "friendly" PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. For more information, please `read the documentation <http://pillow.readthedocs.org/>`_, `check the changelog <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst>`_ and `find out how to contribute <https://github.com/python-pillow/Pillow/blob/master/CONTRIBUTING.md>`_.
|
Pillow is the "friendly PIL fork" by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
||||||
|
|
||||||
.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master
|
.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master
|
||||||
:target: https://travis-ci.org/python-pillow/Pillow
|
:target: https://travis-ci.org/python-pillow/Pillow
|
||||||
:alt: Travis CI build status
|
:alt: Travis CI build status (Linux)
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/python-pillow/pillow-wheels.svg?branch=latest
|
||||||
|
:target: https://travis-ci.org/python-pillow/pillow-wheels
|
||||||
|
:alt: Travis CI build status (OS X)
|
||||||
|
|
||||||
.. image:: https://pypip.in/v/Pillow/badge.png
|
.. image:: https://pypip.in/v/Pillow/badge.png
|
||||||
:target: https://pypi.python.org/pypi/Pillow/
|
:target: https://pypi.python.org/pypi/Pillow/
|
||||||
|
@ -24,3 +29,15 @@ Pillow is the "friendly" PIL fork by `Alex Clark and Contributors <https://githu
|
||||||
.. image:: https://landscape.io/github/python-pillow/Pillow/master/landscape.png
|
.. image:: https://landscape.io/github/python-pillow/Pillow/master/landscape.png
|
||||||
:target: https://landscape.io/github/python-pillow/Pillow/master
|
:target: https://landscape.io/github/python-pillow/Pillow/master
|
||||||
:alt: Code health
|
:alt: Code health
|
||||||
|
|
||||||
|
More Information
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- `Changelog <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst>`_
|
||||||
|
- `Contribute <https://github.com/python-pillow/Pillow/blob/master/CONTRIBUTING.md>`_
|
||||||
|
- `Documentation <http://pillow.readthedocs.org/>`_
|
||||||
|
|
||||||
|
- `About <http://pillow.readthedocs.org/about.html>`_
|
||||||
|
- `Guides <http://pillow.readthedocs.org/guides.html>`_
|
||||||
|
- `Installation <http://pillow.readthedocs.org/installation.html>`_
|
||||||
|
- `Reference <http://pillow.readthedocs.org/reference/index.html>`_
|
||||||
|
|
|
@ -78,7 +78,7 @@ def makedelta(fp, sequence):
|
||||||
if not previous:
|
if not previous:
|
||||||
|
|
||||||
# global header
|
# global header
|
||||||
for s in getheader(im) + getdata(im):
|
for s in getheader(im)[0] + getdata(im):
|
||||||
fp.write(s)
|
fp.write(s)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -3,7 +3,7 @@ Pillow Tests
|
||||||
|
|
||||||
Test scripts are named ``test_xxx.py`` and use the ``unittest`` module. A base class and helper functions can be found in ``helper.py``.
|
Test scripts are named ``test_xxx.py`` and use the ``unittest`` module. A base class and helper functions can be found in ``helper.py``.
|
||||||
|
|
||||||
Depedencies
|
Dependencies
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Install::
|
Install::
|
||||||
|
|
37
Tests/check_webp_leaks.py
Normal file
37
Tests/check_webp_leaks.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
import sys
|
||||||
|
from PIL import Image
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
# Limits for testing the leak
|
||||||
|
mem_limit = 16 # max increase in MB
|
||||||
|
iterations = 5000
|
||||||
|
test_file = "Tests/images/hopper.webp"
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
|
||||||
|
class TestWebPLeaks(PillowTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
try:
|
||||||
|
from PIL import _webp
|
||||||
|
except ImportError:
|
||||||
|
self.skipTest('WebP support not installed')
|
||||||
|
|
||||||
|
def _get_mem_usage(self):
|
||||||
|
from resource import getpagesize, getrusage, RUSAGE_SELF
|
||||||
|
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||||
|
return mem * getpagesize() / 1024 / 1024
|
||||||
|
|
||||||
|
def test_leak_load(self):
|
||||||
|
with open(test_file, 'rb') as f:
|
||||||
|
im_data = f.read()
|
||||||
|
start_mem = self._get_mem_usage()
|
||||||
|
for count in range(iterations):
|
||||||
|
with Image.open(BytesIO(im_data)) as im:
|
||||||
|
im.load()
|
||||||
|
mem = (self._get_mem_usage() - start_mem)
|
||||||
|
self.assertLess(mem, mem_limit, msg='memory usage limit exceeded')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
BIN
Tests/fonts/DejaVuSans-bitmap.ttf
Normal file
BIN
Tests/fonts/DejaVuSans-bitmap.ttf
Normal file
Binary file not shown.
BIN
Tests/fonts/DejaVuSans.ttf
Normal file
BIN
Tests/fonts/DejaVuSans.ttf
Normal file
Binary file not shown.
28
Tests/test_binary.py
Normal file
28
Tests/test_binary.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import _binary
|
||||||
|
|
||||||
|
class TestBinary(PillowTestCase):
|
||||||
|
|
||||||
|
def test_standard(self):
|
||||||
|
self.assertEqual(_binary.i8(b'*'), 42)
|
||||||
|
self.assertEqual(_binary.o8(42), b'*')
|
||||||
|
|
||||||
|
def test_little_endian(self):
|
||||||
|
self.assertEqual(_binary.i16le(b'\xff\xff\x00\x00'), 65535)
|
||||||
|
self.assertEqual(_binary.i32le(b'\xff\xff\x00\x00'), 65535)
|
||||||
|
|
||||||
|
self.assertEqual(_binary.o16le(65535), b'\xff\xff')
|
||||||
|
self.assertEqual(_binary.o32le(65535), b'\xff\xff\x00\x00')
|
||||||
|
|
||||||
|
def test_big_endian(self):
|
||||||
|
self.assertEqual(_binary.i16be(b'\x00\x00\xff\xff'), 0)
|
||||||
|
self.assertEqual(_binary.i32be(b'\x00\x00\xff\xff'), 65535)
|
||||||
|
|
||||||
|
self.assertEqual(_binary.o16be(65535), b'\xff\xff')
|
||||||
|
self.assertEqual(_binary.o32be(65535), b'\x00\x00\xff\xff')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
# End of file
|
|
@ -3,6 +3,7 @@ from helper import djpeg_available, cjpeg_available
|
||||||
|
|
||||||
import random
|
import random
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
import os
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL import ImageFile
|
from PIL import ImageFile
|
||||||
|
@ -334,6 +335,24 @@ class TestFileJpeg(PillowTestCase):
|
||||||
self.assertEqual(tag_ids['RelatedImageWidth'], 0x1001)
|
self.assertEqual(tag_ids['RelatedImageWidth'], 0x1001)
|
||||||
self.assertEqual(tag_ids['RelatedImageLength'], 0x1002)
|
self.assertEqual(tag_ids['RelatedImageLength'], 0x1002)
|
||||||
|
|
||||||
|
def test_MAXBLOCK_scaling(self):
|
||||||
|
def gen_random_image(size):
|
||||||
|
""" Generates a very hard to compress file
|
||||||
|
:param size: tuple
|
||||||
|
"""
|
||||||
|
return Image.frombytes('RGB',size, os.urandom(size[0]*size[1] *3))
|
||||||
|
|
||||||
|
im = gen_random_image((512,512))
|
||||||
|
f = self.tempfile("temp.jpeg")
|
||||||
|
im.save(f, quality=100, optimize=True)
|
||||||
|
|
||||||
|
reloaded = Image.open(f)
|
||||||
|
|
||||||
|
# none of these should crash
|
||||||
|
reloaded.save(f, quality='keep')
|
||||||
|
reloaded.save(f, quality='keep', progressive=True)
|
||||||
|
reloaded.save(f, quality='keep', optimize=True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -374,6 +374,14 @@ class TestFilePng(PillowTestCase):
|
||||||
im = roundtrip(im)
|
im = roundtrip(im)
|
||||||
self.assertEqual(im.info['icc_profile'], expected_icc)
|
self.assertEqual(im.info['icc_profile'], expected_icc)
|
||||||
|
|
||||||
|
def test_repr_png(self):
|
||||||
|
im = hopper()
|
||||||
|
|
||||||
|
repr_png = Image.open(BytesIO(im._repr_png_()))
|
||||||
|
self.assertEqual(repr_png.format, 'PNG')
|
||||||
|
self.assert_image_equal(im, repr_png)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -176,12 +176,23 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertIsInstance(ret, str)
|
self.assertIsInstance(ret, str)
|
||||||
|
|
||||||
|
def test_as_dict(self):
|
||||||
|
# Arrange
|
||||||
|
filename = "Tests/images/pil136.tiff"
|
||||||
|
im = Image.open(filename)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
ret = im.ifd.as_dict()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertIsInstance(ret, dict)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ret,
|
ret, {256: (55,), 257: (43,), 258: (8, 8, 8, 8), 259: (1,),
|
||||||
'{256: (55,), 257: (43,), 258: (8, 8, 8, 8), 259: (1,), '
|
262: (2,), 296: (2,), 273: (8,), 338: (1,), 277: (4,),
|
||||||
'262: (2,), 296: (2,), 273: (8,), 338: (1,), 277: (4,), '
|
279: (9460,), 282: ((720000, 10000),),
|
||||||
'279: (9460,), 282: ((720000, 10000),), '
|
283: ((720000, 10000),), 284: (1,)})
|
||||||
'283: ((720000, 10000),), 284: (1,)}')
|
|
||||||
|
|
||||||
def test__delitem__(self):
|
def test__delitem__(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -83,7 +83,11 @@ class TestFileWebpAlpha(PillowTestCase):
|
||||||
image.load()
|
image.load()
|
||||||
image.getdata()
|
image.getdata()
|
||||||
|
|
||||||
self.assert_image_similar(image, pil_image, 1.0)
|
# early versions of webp are known to produce higher deviations: deal with it
|
||||||
|
if _webp.WebPDecoderVersion(self) <= 0x201:
|
||||||
|
self.assert_image_similar(image, pil_image, 3.0)
|
||||||
|
else:
|
||||||
|
self.assert_image_similar(image, pil_image, 1.0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -168,8 +168,6 @@ class TestImage(PillowTestCase):
|
||||||
ValueError,
|
ValueError,
|
||||||
lambda: Image.effect_mandelbrot(size, extent, quality))
|
lambda: Image.effect_mandelbrot(size, extent, quality))
|
||||||
|
|
||||||
@unittest.skipUnless(sys.platform.startswith('win32'),
|
|
||||||
"Stalls on Travis CI, passes on Windows")
|
|
||||||
def test_effect_noise(self):
|
def test_effect_noise(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
size = (100, 100)
|
size = (100, 100)
|
||||||
|
@ -180,8 +178,8 @@ class TestImage(PillowTestCase):
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im.size, (100, 100))
|
self.assertEqual(im.size, (100, 100))
|
||||||
self.assertEqual(im.getpixel((0, 0)), 60)
|
self.assertEqual(im.mode, "L")
|
||||||
self.assertEqual(im.getpixel((0, 1)), 28)
|
self.assertNotEqual(im.getpixel((0, 0)), im.getpixel((0, 1)))
|
||||||
|
|
||||||
def test_effect_spread(self):
|
def test_effect_spread(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -44,6 +44,22 @@ try:
|
||||||
self.assertRegexpMatches(
|
self.assertRegexpMatches(
|
||||||
ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$")
|
ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$")
|
||||||
|
|
||||||
|
def test_font_properties(self):
|
||||||
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
self.assertEqual(ttf.path, FONT_PATH)
|
||||||
|
self.assertEqual(ttf.size, FONT_SIZE)
|
||||||
|
|
||||||
|
ttf_copy = ttf.font_variant()
|
||||||
|
self.assertEqual(ttf_copy.path, FONT_PATH)
|
||||||
|
self.assertEqual(ttf_copy.size, FONT_SIZE)
|
||||||
|
|
||||||
|
ttf_copy = ttf.font_variant(size=FONT_SIZE+1)
|
||||||
|
self.assertEqual(ttf_copy.size, FONT_SIZE+1)
|
||||||
|
|
||||||
|
second_font_path = "Tests/fonts/DejaVuSans.ttf"
|
||||||
|
ttf_copy = ttf.font_variant(font=second_font_path)
|
||||||
|
self.assertEqual(ttf_copy.path, second_font_path)
|
||||||
|
|
||||||
def test_font_with_name(self):
|
def test_font_with_name(self):
|
||||||
ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
self._render(FONT_PATH)
|
self._render(FONT_PATH)
|
||||||
|
|
24
Tests/test_imagefont_bitmap.py
Normal file
24
Tests/test_imagefont_bitmap.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
from PIL import Image, ImageFont, ImageDraw
|
||||||
|
|
||||||
|
class TestImageFontBitmap(PillowTestCase):
|
||||||
|
def test_similar(self):
|
||||||
|
text = 'EmbeddedBitmap'
|
||||||
|
font_outline = ImageFont.truetype(font='Tests/fonts/DejaVuSans.ttf', size=24)
|
||||||
|
font_bitmap = ImageFont.truetype(font='Tests/fonts/DejaVuSans-bitmap.ttf', size=24)
|
||||||
|
size_outline, size_bitmap = font_outline.getsize(text), font_bitmap.getsize(text)
|
||||||
|
size_final = max(size_outline[0], size_bitmap[0]), max(size_outline[1], size_bitmap[1])
|
||||||
|
im_bitmap = Image.new('RGB', size_final, (255, 255, 255))
|
||||||
|
im_outline = im_bitmap.copy()
|
||||||
|
draw_bitmap, draw_outline = ImageDraw.Draw(im_bitmap), ImageDraw.Draw(im_outline)
|
||||||
|
|
||||||
|
# Metrics are different on the bitmap and ttf fonts, more so on some platforms
|
||||||
|
# and versions of freetype than others. Mac has a 1px difference, linux doesn't.
|
||||||
|
draw_bitmap.text((0, size_final[1] - size_bitmap[1]),
|
||||||
|
text, fill=(0, 0, 0), font=font_bitmap)
|
||||||
|
draw_outline.text((0, size_final[1] - size_outline[1]),
|
||||||
|
text, fill=(0, 0, 0), font=font_outline)
|
||||||
|
self.assert_image_similar(im_bitmap, im_outline, 20)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -48,6 +48,10 @@ class TestLibPack(PillowTestCase):
|
||||||
|
|
||||||
self.assertEqual(pack("RGBA", "RGBA"), [1, 2, 3, 4])
|
self.assertEqual(pack("RGBA", "RGBA"), [1, 2, 3, 4])
|
||||||
|
|
||||||
|
self.assertEqual(pack("RGBa", "RGBa"), [1, 2, 3, 4])
|
||||||
|
self.assertEqual(pack("RGBa", "BGRa"), [3, 2, 1, 4])
|
||||||
|
self.assertEqual(pack("RGBa", "aBGR"), [4, 3, 2, 1])
|
||||||
|
|
||||||
self.assertEqual(pack("CMYK", "CMYK"), [1, 2, 3, 4])
|
self.assertEqual(pack("CMYK", "CMYK"), [1, 2, 3, 4])
|
||||||
self.assertEqual(pack("YCbCr", "YCbCr"), [1, 2, 3])
|
self.assertEqual(pack("YCbCr", "YCbCr"), [1, 2, 3])
|
||||||
|
|
||||||
|
@ -125,6 +129,11 @@ class TestLibPack(PillowTestCase):
|
||||||
self.assertEqual(unpack("RGBA", "BGRA;15", 2), (0, 131, 8, 0))
|
self.assertEqual(unpack("RGBA", "BGRA;15", 2), (0, 131, 8, 0))
|
||||||
self.assertEqual(unpack("RGBA", "RGBA;4B", 2), (17, 0, 34, 0))
|
self.assertEqual(unpack("RGBA", "RGBA;4B", 2), (17, 0, 34, 0))
|
||||||
|
|
||||||
|
self.assertEqual(unpack("RGBa", "RGBa", 4), (1, 2, 3, 4))
|
||||||
|
self.assertEqual(unpack("RGBa", "BGRa", 4), (3, 2, 1, 4))
|
||||||
|
self.assertEqual(unpack("RGBa", "aRGB", 4), (2, 3, 4, 1))
|
||||||
|
self.assertEqual(unpack("RGBa", "aBGR", 4), (4, 3, 2, 1))
|
||||||
|
|
||||||
self.assertEqual(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255?
|
self.assertEqual(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255?
|
||||||
self.assertEqual(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255))
|
self.assertEqual(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255))
|
||||||
self.assertEqual(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255))
|
self.assertEqual(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255))
|
||||||
|
|
|
@ -5,10 +5,12 @@ from PIL import Image
|
||||||
|
|
||||||
class TestPickle(PillowTestCase):
|
class TestPickle(PillowTestCase):
|
||||||
|
|
||||||
def helper_pickle_file(self, pickle, protocol=0):
|
def helper_pickle_file(self, pickle, protocol=0, mode=None):
|
||||||
# Arrange
|
# Arrange
|
||||||
im = Image.open('Tests/images/hopper.jpg')
|
im = Image.open('Tests/images/hopper.jpg')
|
||||||
filename = self.tempfile('temp.pkl')
|
filename = self.tempfile('temp.pkl')
|
||||||
|
if mode:
|
||||||
|
im = im.convert(mode)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
with open(filename, 'wb') as f:
|
with open(filename, 'wb') as f:
|
||||||
|
@ -19,9 +21,11 @@ class TestPickle(PillowTestCase):
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(im, loaded_im)
|
self.assertEqual(im, loaded_im)
|
||||||
|
|
||||||
def helper_pickle_string(
|
def helper_pickle_string(self, pickle, protocol=0,
|
||||||
self, pickle, protocol=0, file='Tests/images/hopper.jpg'):
|
file='Tests/images/hopper.jpg', mode=None):
|
||||||
im = Image.open(file)
|
im = Image.open(file)
|
||||||
|
if mode:
|
||||||
|
im = im.convert(mode)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
dumped_string = pickle.dumps(im, protocol)
|
dumped_string = pickle.dumps(im, protocol)
|
||||||
|
@ -67,6 +71,26 @@ class TestPickle(PillowTestCase):
|
||||||
]:
|
]:
|
||||||
self.helper_pickle_string(pickle, file=file)
|
self.helper_pickle_string(pickle, file=file)
|
||||||
|
|
||||||
|
def test_pickle_l_mode(self):
|
||||||
|
# Arrange
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
# Act / Assert
|
||||||
|
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
self.helper_pickle_string(pickle, protocol, mode="L")
|
||||||
|
self.helper_pickle_file(pickle, protocol, mode="L")
|
||||||
|
|
||||||
|
def test_cpickle_l_mode(self):
|
||||||
|
# Arrange
|
||||||
|
try:
|
||||||
|
import cPickle
|
||||||
|
except ImportError:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Act / Assert
|
||||||
|
for protocol in range(0, cPickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
self.helper_pickle_string(cPickle, protocol, mode="L")
|
||||||
|
self.helper_pickle_file(cPickle, protocol, mode="L")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
13
_imagingft.c
13
_imagingft.c
|
@ -243,7 +243,11 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
&delta);
|
&delta);
|
||||||
x += delta.x;
|
x += delta.x;
|
||||||
}
|
}
|
||||||
error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT);
|
|
||||||
|
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960
|
||||||
|
* Yifu Yu<root@jackyyf.com>, 2014-10-15
|
||||||
|
*/
|
||||||
|
error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
|
||||||
if (error)
|
if (error)
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
|
@ -316,7 +320,8 @@ font_getabc(FontObject* self, PyObject* args)
|
||||||
int index, error;
|
int index, error;
|
||||||
face = self->face;
|
face = self->face;
|
||||||
index = FT_Get_Char_Index(face, ch);
|
index = FT_Get_Char_Index(face, ch);
|
||||||
error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT);
|
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
|
||||||
|
error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
|
||||||
if (error)
|
if (error)
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
a = face->glyph->metrics.horiBearingX / 64.0;
|
a = face->glyph->metrics.horiBearingX / 64.0;
|
||||||
|
@ -363,8 +368,8 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
im = (Imaging) id;
|
im = (Imaging) id;
|
||||||
|
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
|
||||||
load_flags = FT_LOAD_RENDER;
|
load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP;
|
||||||
if (mask)
|
if (mask)
|
||||||
load_flags |= FT_LOAD_TARGET_MONO;
|
load_flags |= FT_LOAD_TARGET_MONO;
|
||||||
|
|
||||||
|
|
46
_webp.c
46
_webp.c
|
@ -136,9 +136,9 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
|
||||||
PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
|
PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
PyBytesObject *webp_string;
|
PyBytesObject *webp_string;
|
||||||
uint8_t *webp;
|
const uint8_t *webp;
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
PyObject *ret, *bytes, *pymode, *icc_profile = Py_None, *exif = Py_None;
|
PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL, *icc_profile = NULL, *exif = NULL;
|
||||||
WebPDecoderConfig config;
|
WebPDecoderConfig config;
|
||||||
VP8StatusCode vp8_status_code = VP8_STATUS_OK;
|
VP8StatusCode vp8_status_code = VP8_STATUS_OK;
|
||||||
char* mode = "RGB";
|
char* mode = "RGB";
|
||||||
|
@ -173,31 +173,34 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
|
||||||
WebPData exif_data = {0};
|
WebPData exif_data = {0};
|
||||||
|
|
||||||
WebPMux* mux = WebPMuxCreate(&data, copy_data);
|
WebPMux* mux = WebPMuxCreate(&data, copy_data);
|
||||||
WebPMuxGetFrame(mux, 1, &image);
|
if (NULL == mux)
|
||||||
webp = (uint8_t*)image.bitstream.bytes;
|
goto end;
|
||||||
|
|
||||||
|
if (WEBP_MUX_OK != WebPMuxGetFrame(mux, 1, &image))
|
||||||
|
{
|
||||||
|
WebPMuxDelete(mux);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
webp = image.bitstream.bytes;
|
||||||
size = image.bitstream.size;
|
size = image.bitstream.size;
|
||||||
|
|
||||||
vp8_status_code = WebPDecode(webp, size, &config);
|
vp8_status_code = WebPDecode(webp, size, &config);
|
||||||
|
|
||||||
WebPMuxGetChunk(mux, "ICCP", &icc_profile_data);
|
if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "ICCP", &icc_profile_data))
|
||||||
if (icc_profile_data.size > 0) {
|
|
||||||
icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size);
|
icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size);
|
||||||
}
|
|
||||||
|
|
||||||
WebPMuxGetChunk(mux, "EXIF", &exif_data);
|
if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "EXIF", &exif_data))
|
||||||
if (exif_data.size > 0) {
|
|
||||||
exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size);
|
exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size);
|
||||||
}
|
|
||||||
|
|
||||||
|
WebPDataClear(&image.bitstream);
|
||||||
WebPMuxDelete(mux);
|
WebPMuxDelete(mux);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vp8_status_code != VP8_STATUS_OK) {
|
if (vp8_status_code != VP8_STATUS_OK)
|
||||||
WebPFreeDecBuffer(&config.output);
|
goto end;
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.output.colorspace < MODE_YUV) {
|
if (config.output.colorspace < MODE_YUV) {
|
||||||
bytes = PyBytes_FromStringAndSize((char *)config.output.u.RGBA.rgba,
|
bytes = PyBytes_FromStringAndSize((char *)config.output.u.RGBA.rgba,
|
||||||
|
@ -215,8 +218,21 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
|
||||||
pymode = PyString_FromString(mode);
|
pymode = PyString_FromString(mode);
|
||||||
#endif
|
#endif
|
||||||
ret = Py_BuildValue("SiiSSS", bytes, config.output.width,
|
ret = Py_BuildValue("SiiSSS", bytes, config.output.width,
|
||||||
config.output.height, pymode, icc_profile, exif);
|
config.output.height, pymode,
|
||||||
|
NULL == icc_profile ? Py_None : icc_profile,
|
||||||
|
NULL == exif ? Py_None : exif);
|
||||||
|
|
||||||
|
end:
|
||||||
WebPFreeDecBuffer(&config.output);
|
WebPFreeDecBuffer(&config.output);
|
||||||
|
|
||||||
|
Py_XDECREF(bytes);
|
||||||
|
Py_XDECREF(pymode);
|
||||||
|
Py_XDECREF(icc_profile);
|
||||||
|
Py_XDECREF(exif);
|
||||||
|
|
||||||
|
if (Py_None == ret)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
build_children.sh
Executable file
7
build_children.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Get last child project build number from branch named "latest"
|
||||||
|
BUILD_NUM=$(curl -s 'https://api.travis-ci.org/repos/python-pillow/pillow-wheels/branches/latest' | grep -o '^{"branch":{"id":[0-9]*,' | grep -o '[0-9]' | tr -d '\n')
|
||||||
|
|
||||||
|
# Restart last child project build
|
||||||
|
curl -X POST https://api.travis-ci.org/builds/$BUILD_NUM/restart --header "Authorization: token "$AUTH_TOKEN
|
|
@ -357,6 +357,12 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||||
**pnginfo**
|
**pnginfo**
|
||||||
A :py:class:`PIL.PngImagePlugin.PngInfo` instance containing text tags.
|
A :py:class:`PIL.PngImagePlugin.PngInfo` instance containing text tags.
|
||||||
|
|
||||||
|
**compress_level**
|
||||||
|
ZLIB compression level, a number between 0 and 9: 1 gives best speed,
|
||||||
|
9 gives best compression, 0 gives no compression at all. Default is 6.
|
||||||
|
When ``optimize`` option is True ``compress_level`` has no effect
|
||||||
|
(it is set to 9 regardless of a value passed).
|
||||||
|
|
||||||
**bits (experimental)**
|
**bits (experimental)**
|
||||||
For ``P`` images, this option controls how many bits to store. If omitted,
|
For ``P`` images, this option controls how many bits to store. If omitted,
|
||||||
the PNG writer uses 8 bits (256 colors).
|
the PNG writer uses 8 bits (256 colors).
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
Writing your own file decoder
|
.. _file-decoders:
|
||||||
|
|
||||||
|
Writing Your Own File Decoder
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
The Python Imaging Library uses a plug-in model which allows you to
|
The Python Imaging Library uses a plug-in model which allows you to
|
||||||
|
@ -116,7 +118,8 @@ The fields are used as follows:
|
||||||
Note that the :py:attr:`tile` attribute contains a list of tile descriptors,
|
Note that the :py:attr:`tile` attribute contains a list of tile descriptors,
|
||||||
not just a single descriptor.
|
not just a single descriptor.
|
||||||
|
|
||||||
The ``raw`` decoder
|
The raw decoder
|
||||||
|
---------------
|
||||||
|
|
||||||
The ``raw`` decoder is used to read uncompressed data from an image file. It
|
The ``raw`` decoder is used to read uncompressed data from an image file. It
|
||||||
can be used with most uncompressed file formats, such as PPM, BMP, uncompressed
|
can be used with most uncompressed file formats, such as PPM, BMP, uncompressed
|
||||||
|
|
|
@ -12,7 +12,7 @@ Installation
|
||||||
|
|
||||||
.. note:: Pillow < 2.0.0 supports Python versions 2.4, 2.5, 2.6, 2.7.
|
.. note:: Pillow < 2.0.0 supports Python versions 2.4, 2.5, 2.6, 2.7.
|
||||||
|
|
||||||
Simple installation
|
Simple Installation
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -121,7 +121,7 @@ Sample Usage::
|
||||||
$ MAX_CONCURRENCY=1 python setup.py build-ext --enable-[feature] install
|
$ MAX_CONCURRENCY=1 python setup.py build-ext --enable-[feature] install
|
||||||
|
|
||||||
|
|
||||||
Linux installation
|
Linux Installation
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -160,10 +160,10 @@ Prerequisites are installed on **Fedora 20** with::
|
||||||
lcms2-devel libwebp-devel tcl-devel tk-devel
|
lcms2-devel libwebp-devel tcl-devel tk-devel
|
||||||
|
|
||||||
|
|
||||||
Mac OS X installation
|
OS X Installation
|
||||||
---------------------
|
-----------------
|
||||||
|
|
||||||
We provide binaries for OS X in the form of `Python Wheels <http://wheel.readthedocs.org/en/latest/index.html>`_. Alternatively you can compile Pillow with with XCode.
|
We provide binaries for OS X in the form of `Python Wheels <http://wheel.readthedocs.org/en/latest/index.html>`_. Alternatively you can compile Pillow from soure with XCode.
|
||||||
|
|
||||||
The easiest way to install external libraries is via `Homebrew <http://mxcl.github.com/homebrew/>`_. After you install Homebrew, run::
|
The easiest way to install external libraries is via `Homebrew <http://mxcl.github.com/homebrew/>`_. After you install Homebrew, run::
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ Install Pillow with::
|
||||||
|
|
||||||
$ pip install Pillow
|
$ pip install Pillow
|
||||||
|
|
||||||
Windows installation
|
Windows Installation
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
We provide binaries for Windows in the form of Python Eggs and `Python Wheels
|
We provide binaries for Windows in the form of Python Eggs and `Python Wheels
|
||||||
|
@ -194,11 +194,11 @@ Python Eggs
|
||||||
Python Wheels
|
Python Wheels
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. Note:: Experimental. Requires setuptools >=0.8 and pip >=1.4.1
|
.. Note:: Requires setuptools >=0.8 and pip >=1.4.1. Some older versions of pip required the ``--use-wheel`` flag.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
$ pip install --use-wheel Pillow
|
$ pip install Pillow
|
||||||
|
|
||||||
If the above does not work, it's likely because we haven't uploaded a
|
If the above does not work, it's likely because we haven't uploaded a
|
||||||
wheel for the latest version of Pillow. In that case, try pinning it
|
wheel for the latest version of Pillow. In that case, try pinning it
|
||||||
|
@ -206,10 +206,10 @@ to a specific version:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
$ pip install --use-wheel Pillow==2.6.1
|
$ pip install Pillow==2.6.1
|
||||||
|
|
||||||
FreeBSD installation
|
FreeBSD Installation
|
||||||
---------------------
|
--------------------
|
||||||
|
|
||||||
.. Note:: Only FreeBSD 10 tested
|
.. Note:: Only FreeBSD 10 tested
|
||||||
|
|
||||||
|
|
|
@ -184,8 +184,11 @@ Methods
|
||||||
|
|
||||||
:param xy: Four points to define the bounding box. Sequence of
|
:param xy: Four points to define the bounding box. Sequence of
|
||||||
``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``.
|
``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``.
|
||||||
:param outline: Color to use for the outline.
|
:param start: Starting angle, in degrees. Angles are measured from
|
||||||
|
3 o'clock, increasing clockwise.
|
||||||
|
:param end: Ending angle, in degrees.
|
||||||
:param fill: Color to use for the fill.
|
:param fill: Color to use for the fill.
|
||||||
|
:param outline: Color to use for the outline.
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.Draw.point(xy, fill=None)
|
.. py:method:: PIL.ImageDraw.Draw.point(xy, fill=None)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ Example: Using the :py:mod:`~PIL.ImageMath` module
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import Image, ImageMath
|
from PIL import Image, ImageMath
|
||||||
|
|
||||||
im1 = Image.open("image1.jpg")
|
im1 = Image.open("image1.jpg")
|
||||||
im2 = Image.open("image2.jpg")
|
im2 = Image.open("image2.jpg")
|
||||||
|
|
|
@ -53,7 +53,7 @@ vector data. Path objects can be passed to the methods on the
|
||||||
Converts the path to a Python list [(x, y), …].
|
Converts the path to a Python list [(x, y), …].
|
||||||
|
|
||||||
:param flat: By default, this function returns a list of 2-tuples
|
:param flat: By default, this function returns a list of 2-tuples
|
||||||
[(x, y), ...]. If this argument is :keyword:`True`, it
|
[(x, y), ...]. If this argument is `True`, it
|
||||||
returns a flat list [x, y, ...] instead.
|
returns a flat list [x, y, ...] instead.
|
||||||
:return: A list of coordinates. See **flat**.
|
:return: A list of coordinates. See **flat**.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
Pillow 2.7.0
|
Pillow 2.7.0
|
||||||
============
|
============
|
||||||
|
|
||||||
|
Sane Plugin
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The Sane plugin has now been split into its own repo:
|
||||||
|
https://github.com/python-pillow/Sane .
|
||||||
|
|
||||||
|
|
||||||
Png text chunk size limits
|
Png text chunk size limits
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
@ -157,7 +164,7 @@ so the quality was worse compared to other Gaussian blur software.
|
||||||
|
|
||||||
The new implementation does not have this drawback.
|
The new implementation does not have this drawback.
|
||||||
|
|
||||||
TFF Parameter Changes
|
TIFF Parameter Changes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Several kwarg parameters for saving TIFF images were previously
|
Several kwarg parameters for saving TIFF images were previously
|
||||||
|
|
|
@ -204,19 +204,6 @@ ImagingNewDIB(const char *mode, int xsize, int ysize)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
/* DEBUG: dump palette to file */
|
|
||||||
FILE *err = fopen("dib.pal", "w");
|
|
||||||
for (i = 0; i < 256; i++)
|
|
||||||
fprintf(err, "%d: %d/%d/%d\n", i,
|
|
||||||
pal->palPalEntry[i].peRed,
|
|
||||||
pal->palPalEntry[i].peGreen,
|
|
||||||
pal->palPalEntry[i].peBlue);
|
|
||||||
fclose(err);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dib->palette = CreatePalette(pal);
|
dib->palette = CreatePalette(pal);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,8 +98,8 @@ ImagingEffectNoise(int xsize, int ysize, float sigma)
|
||||||
/* after numerical recipes */
|
/* after numerical recipes */
|
||||||
double v1, v2, radius, factor;
|
double v1, v2, radius, factor;
|
||||||
do {
|
do {
|
||||||
v1 = rand()*(2.0/32767.0) - 1.0;
|
v1 = rand()*(2.0/RAND_MAX) - 1.0;
|
||||||
v2 = rand()*(2.0/32767.0) - 1.0;
|
v2 = rand()*(2.0/RAND_MAX) - 1.0;
|
||||||
radius= v1*v1 + v2*v2;
|
radius= v1*v1 + v2*v2;
|
||||||
} while (radius >= 1.0);
|
} while (radius >= 1.0);
|
||||||
factor = sqrt(-2.0*log(radius)/radius);
|
factor = sqrt(-2.0*log(radius)/radius);
|
||||||
|
|
|
@ -304,23 +304,6 @@ perspective_transform(double* xin, double* yin, int x, int y, void* data)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int
|
|
||||||
quadratic_transform(double* xin, double* yin, int x, int y, void* data)
|
|
||||||
{
|
|
||||||
double* a = (double*) data;
|
|
||||||
|
|
||||||
double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3];
|
|
||||||
double a4 = a[4]; double a5 = a[5]; double a6 = a[6]; double a7 = a[7];
|
|
||||||
double a8 = a[8]; double a9 = a[9]; double a10 = a[10]; double a11 = a[11];
|
|
||||||
|
|
||||||
xin[0] = a0 + a1*x + a2*y + a3*x*x + a4*x*y + a5*y*y;
|
|
||||||
yin[0] = a6 + a7*x + a8*y + a9*x*x + a10*x*y + a11*y*y;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
quad_transform(double* xin, double* yin, int x, int y, void* data)
|
quad_transform(double* xin, double* yin, int x, int y, void* data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -530,6 +530,11 @@ static struct {
|
||||||
{"RGBA", "B", 8, band2},
|
{"RGBA", "B", 8, band2},
|
||||||
{"RGBA", "A", 8, band3},
|
{"RGBA", "A", 8, band3},
|
||||||
|
|
||||||
|
/* true colour w. alpha premultiplied */
|
||||||
|
{"RGBa", "RGBa", 32, copy4},
|
||||||
|
{"RGBa", "BGRa", 32, ImagingPackBGRA},
|
||||||
|
{"RGBa", "aBGR", 32, ImagingPackABGR},
|
||||||
|
|
||||||
/* true colour w. padding */
|
/* true colour w. padding */
|
||||||
{"RGBX", "RGBX", 32, copy4},
|
{"RGBX", "RGBX", 32, copy4},
|
||||||
{"RGBX", "RGBX;L", 32, packRGBXL},
|
{"RGBX", "RGBX;L", 32, packRGBXL},
|
||||||
|
|
|
@ -44,9 +44,6 @@ struct _HashTable {
|
||||||
#define RESIZE_FACTOR 3
|
#define RESIZE_FACTOR 3
|
||||||
|
|
||||||
static int _hashtable_insert_node(HashTable *,HashNode *,int,int,CollisionFunc);
|
static int _hashtable_insert_node(HashTable *,HashNode *,int,int,CollisionFunc);
|
||||||
#if 0
|
|
||||||
static int _hashtable_test(HashTable *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
HashTable *hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
HashTable *hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
||||||
HashTable *h;
|
HashTable *h;
|
||||||
|
@ -132,22 +129,6 @@ static void _hashtable_resize(HashTable *h) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int _hashtable_test(HashTable *h) {
|
|
||||||
uint32_t i;
|
|
||||||
int j;
|
|
||||||
HashNode *n;
|
|
||||||
for (i=0;i<h->length;i++) {
|
|
||||||
for (n=h->table[i];n&&n->next;n=n->next) {
|
|
||||||
j=h->cmpFunc(h,n->key,n->next->key);
|
|
||||||
printf ("%c",j?(j<0?'-':'+'):'=');
|
|
||||||
}
|
|
||||||
printf ("\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int _hashtable_insert_node(HashTable *h,HashNode *node,int resize,int update,CollisionFunc cf) {
|
static int _hashtable_insert_node(HashTable *h,HashNode *node,int resize,int update,CollisionFunc cf) {
|
||||||
uint32_t hash=h->hashFunc(h,node->key)%h->length;
|
uint32_t hash=h->hashFunc(h,node->key)%h->length;
|
||||||
HashNode **n,*nv;
|
HashNode **n,*nv;
|
||||||
|
|
|
@ -638,7 +638,12 @@ unpackRGBa(UINT8* out, const UINT8* in, int pixels)
|
||||||
int a = in[3];
|
int a = in[3];
|
||||||
if (!a)
|
if (!a)
|
||||||
out[R] = out[G] = out[B] = out[A] = 0;
|
out[R] = out[G] = out[B] = out[A] = 0;
|
||||||
else {
|
else if (a == 255) {
|
||||||
|
out[R] = in[0];
|
||||||
|
out[G] = in[1];
|
||||||
|
out[B] = in[2];
|
||||||
|
out[A] = a;
|
||||||
|
} else {
|
||||||
out[R] = CLIP(in[0] * 255 / a);
|
out[R] = CLIP(in[0] * 255 / a);
|
||||||
out[G] = CLIP(in[1] * 255 / a);
|
out[G] = CLIP(in[1] * 255 / a);
|
||||||
out[B] = CLIP(in[2] * 255 / a);
|
out[B] = CLIP(in[2] * 255 / a);
|
||||||
|
@ -1114,6 +1119,12 @@ static struct {
|
||||||
{"RGBA", "B", 8, band2},
|
{"RGBA", "B", 8, band2},
|
||||||
{"RGBA", "A", 8, band3},
|
{"RGBA", "A", 8, band3},
|
||||||
|
|
||||||
|
/* true colour w. alpha premultiplied */
|
||||||
|
{"RGBa", "RGBa", 32, copy4},
|
||||||
|
{"RGBa", "BGRa", 32, unpackBGRA},
|
||||||
|
{"RGBa", "aRGB", 32, unpackARGB},
|
||||||
|
{"RGBa", "aBGR", 32, unpackABGR},
|
||||||
|
|
||||||
/* true colour w. padding */
|
/* true colour w. padding */
|
||||||
{"RGBX", "RGB", 24, ImagingUnpackRGB},
|
{"RGBX", "RGB", 24, ImagingUnpackRGB},
|
||||||
{"RGBX", "RGB;L", 24, unpackRGBL},
|
{"RGBX", "RGB;L", 24, unpackRGBL},
|
||||||
|
|
5
setup.py
5
setup.py
|
@ -722,6 +722,9 @@ class pil_build_ext(build_ext):
|
||||||
os.unlink(tmpfile)
|
os.unlink(tmpfile)
|
||||||
|
|
||||||
|
|
||||||
|
def debug_build():
|
||||||
|
return hasattr(sys, 'gettotalrefcount')
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
version=PILLOW_VERSION,
|
version=PILLOW_VERSION,
|
||||||
|
@ -754,6 +757,6 @@ setup(
|
||||||
test_suite='PIL.tests',
|
test_suite='PIL.tests',
|
||||||
keywords=["Imaging", ],
|
keywords=["Imaging", ],
|
||||||
license='Standard PIL License',
|
license='Standard PIL License',
|
||||||
zip_safe=True,
|
zip_safe= not debug_build(),
|
||||||
)
|
)
|
||||||
# End of file
|
# End of file
|
||||||
|
|
Loading…
Reference in New Issue
Block a user