Merge branch 'master' into icns-support

This commit is contained in:
Alastair Houghton 2014-03-28 09:15:20 +00:00
commit 5dd67abd71
41 changed files with 2541 additions and 556 deletions

8
.gitignore vendored
View File

@ -5,3 +5,11 @@ dist
.tox
*.so
docs/_build
# Vim cruft
.*.swp
#emacs
*~
\#*#
.#*

View File

@ -4,19 +4,32 @@ language: python
virtualenv:
system_site_packages: true
notifications:
irc: "chat.freenode.net#pil"
python:
- 2.6
- 2.7
- 3.2
- 3.3
- "pypy"
install:
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev libwebp-dev python-qt4 ghostscript libffi-dev"
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake"
- "pip install cffi"
# webp
- pushd depends && ./install_webp.sh && popd
# openjpeg
- pushd depends && ./install_openjpeg.sh && popd
script:
- python setup.py clean
- python setup.py build_ext --inplace
- python selftest.py
- python Tests/run.py
matrix:
allow_failures:
- python: "pypy"

View File

@ -4,9 +4,42 @@ Changelog (Pillow)
2.4.0 (unreleased)
------------------
- Fixes for Jpeg encoding in Python 3, fixes #577
[wiredfool]
- Added support for JPEG 2000
[al45tair]
- Add more detailed error messages to Image.py
[larsmans]
- Avoid conflicting _expand functions in PIL & MINGW, fixes #538
[aclark]
- Merge from Philippe Lagadecs OleFileIO_PL fork
[vadmium]
- Fix ImageColor.getcolor
[homm]
- Make ICO files work with the ImageFile.Parser interface, fixes #522
[wiredfool]
- Handle 32bit compiled python on 64bit architecture
[choppsv1]
- Fix support for characters >128 using .pcf or .pil fonts in Py3k. Fixes #505
[wiredfool]
- Skip CFFI test earlier if it's not installed
[wiredfool]
- Fixed opening and saving odd sized .pcx files, fixes #523
[wiredfool]
- Fixed palette handling when converting from mode P->RGB->P
[d_schmidt]
- Fixed saving mode P image as a PNG with transparency = palette color 0
[d-schmidt]
@ -49,6 +82,12 @@ Changelog (Pillow)
- Prefer homebrew freetype over X11 freetype (but still allow both)
[dmckeone]
2.3.1 (2014-03-14)
------------------
- Fix insecure use of tempfile.mktemp (CVE-2014-1932 CVE-2014-1933)
[wiredfool]
2.3.0 (2014-01-01)
------------------

View File

@ -19,6 +19,7 @@ recursive-include Images *.psd
recursive-include Images *.tar
recursive-include Images *.webp
recursive-include Images *.xpm
recursive-include PIL *.md
recursive-include Sane *.c
recursive-include Sane *.py
recursive-include Sane *.txt
@ -27,9 +28,13 @@ recursive-include Sane README
recursive-include Scripts *.py
recursive-include Scripts README
recursive-include Tests *.bin
recursive-include Tests *.bmp
recursive-include Tests *.eps
recursive-include Tests *.gif
recursive-include Tests *.gnuplot
recursive-include Tests *.html
recursive-include Tests *.icm
recursive-include Tests *.ico
recursive-include Tests *.jpg
recursive-include Tests *.pcf
recursive-include Tests *.pcx

View File

@ -67,8 +67,10 @@ def Ghostscript(tile, size, fp, scale=1):
import tempfile, os, subprocess
outfile = tempfile.mktemp()
infile = tempfile.mktemp()
out_fd, outfile = tempfile.mkstemp()
os.close(out_fd)
in_fd, infile = tempfile.mkstemp()
os.close(in_fd)
with open(infile, 'wb') as f:
fp.seek(offset)

View File

@ -237,7 +237,10 @@ def _save(im, fp, filename):
# convert on the fly (EXPERIMENTAL -- I'm not sure PIL
# should automatically convert images on save...)
if Image.getmodebase(im.mode) == "RGB":
imOut = im.convert("P")
palette_size = 256
if im.palette:
palette_size = len(im.palette.getdata()[1]) // 3
imOut = im.convert("P", palette=1, colors=palette_size)
rawmode = "P"
else:
imOut = im.convert("L")
@ -248,9 +251,13 @@ def _save(im, fp, filename):
palette = im.encoderinfo["palette"]
except KeyError:
palette = None
if im.palette:
# use existing if possible
palette = im.palette.getdata()[1]
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
if im.encoderinfo["optimize"]:
# When the mode is L, and we optimize, we end up with
# im.mode == P and rawmode = L, which fails.
# If we're optimizing the palette, we're going to be
# in a rawmode of P anyway.
rawmode = 'P'
header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo)
for s in header:
@ -391,6 +398,9 @@ def getheader(im, palette=None, info=None):
for i in range(len(imageBytes)):
imageBytes[i] = newPositions[imageBytes[i]]
im.frombytes(bytes(imageBytes))
newPaletteBytes = paletteBytes + (768 - len(paletteBytes)) * b'\x00'
im.putpalette(newPaletteBytes)
im.palette = ImagePalette.ImagePalette("RGB", palette = paletteBytes, size = len(paletteBytes))
if not paletteBytes:
paletteBytes = sourcePalette

View File

@ -222,6 +222,10 @@ class IcoImageFile(ImageFile.ImageFile):
self.mode = im.mode
self.size = im.size
def load_seek(self):
# Flage the ImageFile.Parser so that it just does all the decode at the end.
pass
#
# --------------------------------------------------------------------

View File

@ -504,13 +504,16 @@ class Image:
self.readonly = 0
def _dump(self, file=None, format=None):
import tempfile
import tempfile, os
if not file:
file = tempfile.mktemp()
f, file = tempfile.mkstemp(format or '')
os.close(f)
self.load()
if not format or format == "PPM":
self.im.save_ppm(file)
else:
if file.endswith(format):
file = file + "." + format
self.save(file, format)
return file
@ -734,7 +737,10 @@ class Image:
if mode == "P" and palette == ADAPTIVE:
im = self.im.quantize(colors)
return self._new(im)
new = self._new(im)
from PIL import ImagePalette
new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB"))
return new
# colorspace conversion
if dither is None:
@ -1959,7 +1965,7 @@ def fromarray(obj, mode=None):
else:
ndmax = 4
if ndim > ndmax:
raise ValueError("Too many dimensions.")
raise ValueError("Too many dimensions: %d > %d." % (ndim, ndmax))
size = shape[1], shape[0]
if strides is not None:
@ -2012,7 +2018,7 @@ def open(fp, mode="r"):
"""
if mode != "r":
raise ValueError("bad mode")
raise ValueError("bad mode %r" % mode)
if isPath(fp):
filename = fp
@ -2048,7 +2054,8 @@ def open(fp, mode="r"):
#traceback.print_exc()
pass
raise IOError("cannot identify image file")
raise IOError("cannot identify image file %r"
% (filename if filename else fp))
#
# Image processing.

View File

@ -20,15 +20,6 @@
from PIL import Image
import re
##
# Convert color string to RGB tuple.
#
# @param color A CSS3-style colour string.
# @return An RGB-tuple.
# @exception ValueError If the color string could not be interpreted
# as an RGB value.
def getrgb(color):
"""
Convert a color string to an RGB tuple. If the string cannot be parsed,
@ -37,7 +28,7 @@ def getrgb(color):
.. versionadded:: 1.1.4
:param color: A color string
:return: ``(red, green, blue)``
:return: ``(red, green, blue[, alpha])``
"""
try:
rgb = colormap[color]
@ -114,20 +105,21 @@ def getcolor(color, mode):
.. versionadded:: 1.1.4
:param color: A color string
:return: ``(red, green, blue)``
:return: ``(graylevel [, alpha]) or (red, green, blue[, alpha])``
"""
# same as getrgb, but converts the result to the given mode
color = getrgb(color)
if mode == "RGB":
return color
if mode == "RGBA":
if len(color) == 3:
color = (color + (255,))
r, g, b, a = color
return r, g, b, a
color, alpha = getrgb(color), 255
if len(color) == 4:
color, alpha = color[0:3], color[3]
if Image.getmodebase(mode) == "L":
r, g, b = color
return (r*299 + g*587 + b*114)//1000
color = (r*299 + g*587 + b*114)//1000
if mode[-1] == 'A':
return (color, alpha)
else:
if mode[-1] == 'A':
return color + (alpha,)
return color
colormap = {

View File

@ -23,13 +23,14 @@ from PIL import Image, ImageColor
class ImagePalette:
"Color palette for palette mapped images"
def __init__(self, mode = "RGB", palette = None):
def __init__(self, mode = "RGB", palette = None, size = 0):
self.mode = mode
self.rawmode = None # if set, palette contains raw data
self.palette = palette or list(range(256))*len(self.mode)
self.colors = {}
self.dirty = None
if len(self.mode)*256 != len(self.palette):
if ((size == 0 and len(self.mode)*256 != len(self.palette)) or
(size != 0 and size != len(self.palette))):
raise ValueError("wrong palette size")
def getdata(self):

View File

@ -172,8 +172,8 @@ class IptcImageFile(ImageFile.ImageFile):
self.fp.seek(offset)
# Copy image data to temporary file
outfile = tempfile.mktemp()
o = open(outfile, "wb")
o_fd, outfile = tempfile.mkstemp(text=False)
o = os.fdopen(o_fd)
if encoding == "raw":
# To simplify access to the extracted file,
# prepend a PPM header

View File

@ -344,13 +344,17 @@ class JpegImageFile(ImageFile.ImageFile):
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
import tempfile, os
file = tempfile.mktemp()
os.system("djpeg %s >%s" % (self.filename, file))
f, path = tempfile.mkstemp()
os.close(f)
if os.path.exists(self.filename):
os.system("djpeg '%s' >'%s'" % (self.filename, path))
else:
raise ValueError("Invalid Filename")
try:
self.im = Image.core.open_ppm(file)
self.im = Image.core.open_ppm(path)
finally:
try: os.unlink(file)
try: os.unlink(path)
except: pass
self.mode = self.im.mode
@ -438,7 +442,7 @@ samplings = {
}
def convert_dict_qtables(qtables):
qtables = [qtables[key] for key in xrange(len(qtables)) if qtables.has_key(key)]
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
for idx, table in enumerate(qtables):
qtables[idx] = [table[i] for i in zigzag_index]
return qtables
@ -500,7 +504,7 @@ def _save(im, fp, filename):
except ValueError:
raise ValueError("Invalid quantization table")
else:
qtables = [lines[s:s+64] for s in xrange(0, len(lines), 64)]
qtables = [lines[s:s+64] for s in range(0, len(lines), 64)]
if isinstance(qtables, (tuple, list, dict)):
if isinstance(qtables, dict):
qtables = convert_dict_qtables(qtables)

141
PIL/OleFileIO-README.md Normal file
View File

@ -0,0 +1,141 @@
OleFileIO_PL
============
[OleFileIO_PL](http://www.decalage.info/python/olefileio) is a Python module to read [Microsoft OLE2 files (also called Structured Storage, Compound File Binary Format or Compound Document File Format)](http://en.wikipedia.org/wiki/Compound_File_Binary_Format), such as Microsoft Office documents, Image Composer and FlashPix files, Outlook messages, ...
This is an improved version of the OleFileIO module from [PIL](http://www.pythonware.com/products/pil/index.htm), the excellent Python Imaging Library, created and maintained by Fredrik Lundh. The API is still compatible with PIL, but I have improved the internal implementation significantly, with new features, bugfixes and a more robust design.
As far as I know, this module is now the most complete and robust Python implementation to read MS OLE2 files, portable on several operating systems. (please tell me if you know other similar Python modules)
WARNING: THIS IS (STILL) WORK IN PROGRESS.
Main improvements over PIL version of OleFileIO:
------------------------------------------------
- Better compatibility with Python 2.6 (also compatible with Python 3.0+)
- Support for files larger than 6.8MB
- Robust: many checks to detect malformed files
- Improved API
- New features: metadata extraction, stream/storage timestamps
- Added setup.py and install.bat to ease installation
News
----
- 2013-07-24 v0.26: added methods to parse stream/storage timestamps, improved listdir to include storages, fixed parsing of direntry timestamps
- 2013-05-27 v0.25: improved metadata extraction, properties parsing and exception handling, fixed [issue #12](https://bitbucket.org/decalage/olefileio_pl/issue/12/error-when-converting-timestamps-in-ole)
- 2013-05-07 v0.24: new features to extract metadata (get\_metadata method and OleMetadata class), improved getproperties to convert timestamps to Python datetime
- 2012-10-09: published [python-oletools](http://www.decalage.info/python/oletools), a package of analysis tools based on OleFileIO_PL
- 2012-09-11 v0.23: added support for file-like objects, fixed [issue #8](https://bitbucket.org/decalage/olefileio_pl/issue/8/bug-with-file-object)
- 2012-02-17 v0.22: fixed issues #7 (bug in getproperties) and #2 (added close method)
- 2011-10-20: code hosted on bitbucket to ease contributions and bug tracking
- 2010-01-24 v0.21: fixed support for big-endian CPUs, such as PowerPC Macs.
- 2009-12-11 v0.20: small bugfix in OleFileIO.open when filename is not plain str.
- 2009-12-10 v0.19: fixed support for 64 bits platforms (thanks to Ben G. and Martijn for reporting the bug)
- see changelog in source code for more info.
Download:
---------
The archive is available on [the project page](https://bitbucket.org/decalage/olefileio_pl/downloads).
How to use this module:
-----------------------
See sample code at the end of the module, and also docstrings.
Here are a few examples:
:::python
import OleFileIO_PL
# Test if a file is an OLE container:
assert OleFileIO_PL.isOleFile('myfile.doc')
# Open an OLE file from disk:
ole = OleFileIO_PL.OleFileIO('myfile.doc')
# Get list of streams:
print(ole.listdir())
# Test if known streams/storages exist:
if ole.exists('worddocument'):
print("This is a Word document.")
print("size :", ole.get_size('worddocument'))
if ole.exists('macros/vba'):
print("This document seems to contain VBA macros.")
# Extract the "Pictures" stream from a PPT file:
if ole.exists('Pictures'):
pics = ole.openstream('Pictures')
data = pics.read()
f = open('Pictures.bin', 'wb')
f.write(data)
f.close()
# Extract metadata (new in v0.24) - see source code for all attributes:
meta = ole.get_metadata()
print('Author:', meta.author)
print('Title:', meta.title)
print('Creation date:', meta.create_time)
# print all metadata:
meta.dump()
# Close the OLE file:
ole.close()
# Work with a file-like object (e.g. StringIO) instead of a file on disk:
data = open('myfile.doc', 'rb').read()
f = io.BytesIO(data)
ole = OleFileIO_PL.OleFileIO(f)
print(ole.listdir())
ole.close()
It can also be used as a script from the command-line to display the structure of an OLE file, for example:
OleFileIO_PL.py myfile.doc
A real-life example: [using OleFileIO_PL for malware analysis and forensics](http://blog.gregback.net/2011/03/using-remnux-for-forensic-puzzle-6/).
How to contribute:
------------------
The code is available in [a Mercurial repository on bitbucket](https://bitbucket.org/decalage/olefileio_pl). You may use it to submit enhancements or to report any issue.
If you would like to help us improve this module, or simply provide feedback, you may also send an e-mail to decalage(at)laposte.net. You can help in many ways:
- test this module on different platforms / Python versions
- find and report bugs
- improve documentation, code samples, docstrings
- write unittest test cases
- provide tricky malformed files
How to report bugs:
-------------------
To report a bug, for example a normal file which is not parsed correctly, please use the [issue reporting page](https://bitbucket.org/decalage/olefileio_pl/issues?status=new&status=open), or send an e-mail with an attachment containing the debugging output of OleFileIO_PL.
For this, launch the following command :
OleFileIO_PL.py -d -c file >debug.txt
License
-------
OleFileIO_PL is open-source.
OleFileIO_PL changes are Copyright (c) 2005-2013 by Philippe Lagadec.
The Python Imaging Library (PIL) is
- Copyright (c) 1997-2005 by Secret Labs AB
- Copyright (c) 1995-2005 by Fredrik Lundh
By obtaining, using, and/or copying this software and/or its associated documentation, you agree that you have read, understood, and will comply with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its associated documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies, and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Secret Labs AB or the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -55,12 +55,18 @@ class PcxImageFile(ImageFile.ImageFile):
bbox = i16(s,4), i16(s,6), i16(s,8)+1, i16(s,10)+1
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
raise SyntaxError("bad PCX image size")
if Image.DEBUG:
print ("BBox: %s %s %s %s" % bbox)
# format
version = i8(s[1])
bits = i8(s[3])
planes = i8(s[65])
stride = i16(s,66)
if Image.DEBUG:
print ("PCX version %s, bits %s, planes %s, stride %s" %
(version, bits, planes, stride))
self.info["dpi"] = i16(s,12), i16(s,14)
@ -98,6 +104,8 @@ class PcxImageFile(ImageFile.ImageFile):
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
bbox = (0, 0) + self.size
if Image.DEBUG:
print ("size: %sx%s" % self.size)
self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
@ -126,6 +134,16 @@ def _save(im, fp, filename, check=0):
# bytes per plane
stride = (im.size[0] * bits + 7) // 8
# stride should be even
stride = stride + (stride % 2)
# Stride needs to be kept in sync with the PcxEncode.c version.
# Ideally it should be passed in in the state, but the bytes value
# gets overwritten.
if Image.DEBUG:
print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % (
im.size[0], bits, stride))
# under windows, we could determine the current screen size with
# "Image.core.display_mode()[1]", but I think that's overkill...

View File

@ -505,7 +505,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
else:
# check palette contents
if im.palette:
colors = len(im.palette.getdata()[1])//3
colors = max(min(len(im.palette.getdata()[1])//3, 256), 2)
else:
colors = 256

View File

@ -25,10 +25,23 @@ else:
return bytes((i&255,))
# Input, le = little endian, be = big endian
#TODO: replace with more readable struct.unpack equivalent
def i16le(c, o=0):
"""
Converts a 2-bytes (16 bits) string to an integer.
c: string containing bytes to convert
o: offset of bytes to convert in string
"""
return i8(c[o]) | (i8(c[o+1])<<8)
def i32le(c, o=0):
"""
Converts a 4-bytes (32 bits) string to an integer.
c: string containing bytes to convert
o: offset of bytes to convert in string
"""
return i8(c[o]) | (i8(c[o+1])<<8) | (i8(c[o+2])<<16) | (i8(c[o+3])<<24)
def i16be(c, o=0):

View File

@ -916,10 +916,13 @@ SaneDev_snap(SaneDevObject *self, PyObject *args)
call which returns SANE_STATUS_EOF in order to start
a new frame.
*/
if (st != SANE_STATUS_EOF)
{
do {
st = sane_read(self->h, buffer, READSIZE, &len);
}
while (st == SANE_STATUS_GOOD);
}
if (st != SANE_STATUS_EOF)
{
Py_BLOCK_THREADS
@ -937,10 +940,13 @@ SaneDev_snap(SaneDevObject *self, PyObject *args)
}
}
/* enforce SANE_STATUS_EOF. Can be necessary for ADF scans for some backends */
if (st != SANE_STATUS_EOF)
{
do {
st = sane_read(self->h, buffer, READSIZE, &len);
}
while (st == SANE_STATUS_GOOD);
}
if (st != SANE_STATUS_EOF)
{
sane_cancel(self->h);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
Tests/images/python.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -3,7 +3,7 @@ from tester import *
from PIL import Image
import os
base = 'Tests/images/bmp/'
base = os.path.join('Tests', 'images', 'bmp')
def get_files(d, ext='.bmp'):
@ -78,9 +78,9 @@ def test_good():
except Exception as msg:
# there are three here that are unsupported:
unsupported = ('Tests/images/bmp/g/rgb32bf.bmp',
'Tests/images/bmp/g/pal8rle.bmp',
'Tests/images/bmp/g/pal4rle.bmp')
unsupported = (os.path.join(base, 'g', 'rgb32bf.bmp'),
os.path.join(base, 'g', 'pal8rle.bmp'),
os.path.join(base, 'g', 'pal4rle.bmp'))
if f not in unsupported:
assert_true(False, "Unsupported Image %s: %s" %(f,msg))

View File

@ -1,17 +1,16 @@
from tester import *
try:
import cffi
except:
skip()
from PIL import Image, PyAccess
import test_image_putpixel as put
import test_image_getpixel as get
try:
import cffi
except:
skip()
Image.USE_CFFI_ACCESS = True
def test_put():

View File

@ -38,7 +38,7 @@ def test_roundtrip():
def test_roundtrip2():
#see https://github.com/python-imaging/Pillow/issues/403
out = 'temp.gif'#tempfile('temp.gif')
out = tempfile('temp.gif')
im = Image.open('Images/lena.gif')
im2 = im.copy()
im2.save(out)
@ -46,3 +46,42 @@ def test_roundtrip2():
assert_image_similar(reread.convert('RGB'), lena(), 50)
def test_palette_handling():
# see https://github.com/python-imaging/Pillow/issues/513
im = Image.open('Images/lena.gif')
im = im.convert('RGB')
im = im.resize((100,100), Image.ANTIALIAS)
im2 = im.convert('P', palette=Image.ADAPTIVE, colors=256)
f = tempfile('temp.gif')
im2.save(f, optimize=True)
reloaded = Image.open(f)
assert_image_similar(im, reloaded.convert('RGB'), 10)
def test_palette_434():
# see https://github.com/python-imaging/Pillow/issues/434
def roundtrip(im, *args, **kwargs):
out = tempfile('temp.gif')
im.save(out, *args, **kwargs)
reloaded = Image.open(out)
return [im, reloaded]
orig = "Tests/images/test.colors.gif"
im = Image.open(orig)
assert_image_equal(*roundtrip(im))
assert_image_equal(*roundtrip(im, optimize=True))
im = im.convert("RGB")
# check automatic P conversion
reloaded = roundtrip(im)[1].convert('RGB')
assert_image_equal(im, reloaded)

View File

@ -10,9 +10,7 @@ codecs = dir(Image.core)
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
skip("jpeg support not available")
# sample jpeg stream
file = "Images/lena.jpg"
data = open(file, "rb").read()
test_file = "Images/lena.jpg"
def roundtrip(im, **options):
out = BytesIO()
@ -30,7 +28,7 @@ def test_sanity():
# internal version number
assert_match(Image.core.jpeglib_version, "\d+\.\d+$")
im = Image.open(file)
im = Image.open(test_file)
im.load()
assert_equal(im.mode, "RGB")
assert_equal(im.size, (128, 128))
@ -40,7 +38,7 @@ def test_sanity():
def test_app():
# Test APP/COM reader (@PIL135)
im = Image.open(file)
im = Image.open(test_file)
assert_equal(im.applist[0],
("APP0", b"JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00"))
assert_equal(im.applist[1], ("COM", b"Python Imaging Library"))
@ -49,8 +47,8 @@ def test_app():
def test_cmyk():
# Test CMYK handling. Thanks to Tim and Charlie for test data,
# Michael for getting me to look one more time.
file = "Tests/images/pil_sample_cmyk.jpg"
im = Image.open(file)
f = "Tests/images/pil_sample_cmyk.jpg"
im = Image.open(f)
# the source image has red pixels in the upper left corner.
c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))]
assert_true(c == 0.0 and m > 0.8 and y > 0.8 and k == 0.0)
@ -66,7 +64,7 @@ def test_cmyk():
def test_dpi():
def test(xdpi, ydpi=None):
im = Image.open(file)
im = Image.open(test_file)
im = roundtrip(im, dpi=(xdpi, ydpi or xdpi))
return im.info.get("dpi")
assert_equal(test(72), (72, 72))
@ -80,9 +78,9 @@ def test_icc():
icc_profile = im1.info["icc_profile"]
assert_equal(len(icc_profile), 3144)
# Roundtrip via physical file.
file = tempfile("temp.jpg")
im1.save(file, icc_profile=icc_profile)
im2 = Image.open(file)
f = tempfile("temp.jpg")
im1.save(f, icc_profile=icc_profile)
im2 = Image.open(f)
assert_equal(im2.info.get("icc_profile"), icc_profile)
# Roundtrip via memory buffer.
im1 = roundtrip(lena())
@ -203,3 +201,9 @@ def test_exif():
im = Image.open("Tests/images/pil_sample_rgb.jpg")
info = im._getexif()
assert_equal(info[305], 'Adobe Photoshop CS Macintosh')
def test_quality_keep():
im = Image.open("Images/lena.jpg")
f = tempfile('temp.jpg')
assert_no_exception(lambda: im.save(f, quality='keep'))

View File

@ -2,29 +2,30 @@ from tester import *
from PIL import Image
def _roundtrip(im):
f = tempfile("temp.pcx")
im.save(f)
im2 = Image.open(f)
assert_equal(im2.mode, im.mode)
assert_equal(im2.size, im.size)
assert_equal(im2.format, "PCX")
assert_image_equal(im2, im)
def test_sanity():
for mode in ('1', 'L', 'P', 'RGB'):
_roundtrip(lena(mode))
file = tempfile("temp.pcx")
def test_odd():
# see issue #523, odd sized images should have a stride that's even.
# not that imagemagick or gimp write pcx that way.
# we were not handling properly.
for mode in ('1', 'L', 'P', 'RGB'):
# larger, odd sized images are better here to ensure that
# we handle interrupted scan lines properly.
_roundtrip(lena(mode).resize((511,511)))
lena("1").save(file)
im = Image.open(file)
im.load()
assert_equal(im.mode, "1")
assert_equal(im.size, (128, 128))
assert_equal(im.format, "PCX")
lena("1").save(file)
im = Image.open(file)
lena("L").save(file)
im = Image.open(file)
lena("P").save(file)
im = Image.open(file)
lena("RGB").save(file)
im = Image.open(file)
def test_pil184():
# Check reading of files where xmin/xmax is not zero.

View File

@ -22,10 +22,28 @@ def test_sanity():
font.save(tempname)
def test_draw():
def xtest_draw():
font = ImageFont.load(tempname)
image = Image.new("L", font.getsize(message), "white")
draw = ImageDraw.Draw(image)
draw.text((0, 0), message, font=font)
# assert_signature(image, "7216c60f988dea43a46bb68321e3c1b03ec62aee")
def _test_high_characters(message):
font = ImageFont.load(tempname)
image = Image.new("L", font.getsize(message), "white")
draw = ImageDraw.Draw(image)
draw.text((0, 0), message, font=font)
compare = Image.open('Tests/images/high_ascii_chars.png')
assert_image_equal(image, compare)
def test_high_characters():
message = "".join([chr(i+1) for i in range(140,232)])
_test_high_characters(message)
# accept bytes instances in Py3.
if bytes is not str:
_test_high_characters(message.encode('latin1'))

View File

@ -2,6 +2,11 @@ from tester import *
from PIL import Image
if hasattr(sys, 'pypy_version_info'):
# This takes _forever_ on pypy. Open Bug,
# see https://github.com/python-imaging/Pillow/issues/484
skip()
def test_sanity():
im = lena()

View File

@ -26,9 +26,29 @@ for color in list(ImageColor.colormap.keys()):
assert_equal((0, 0, 0), ImageColor.getcolor("black", "RGB"))
assert_equal((255, 255, 255), ImageColor.getcolor("white", "RGB"))
assert_equal((0, 255, 115), ImageColor.getcolor("rgba(0, 255, 115, 33)", "RGB"))
Image.new("RGB", (1, 1), "white")
assert_equal((0, 0, 0, 255), ImageColor.getcolor("black", "RGBA"))
assert_equal((255, 255, 255, 255), ImageColor.getcolor("white", "RGBA"))
assert_equal((0, 255, 115, 33), ImageColor.getcolor("rgba(0, 255, 115, 33)", "RGBA"))
Image.new("RGBA", (1, 1), "white")
assert_equal(0, ImageColor.getcolor("black", "L"))
assert_equal(255, ImageColor.getcolor("white", "L"))
assert_equal(162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "L"))
Image.new("L", (1, 1), "white")
assert_equal(0, ImageColor.getcolor("black", "1"))
assert_equal(255, ImageColor.getcolor("white", "1"))
# The following test is wrong, but is current behavior
# The correct result should be 255 due to the mode 1
assert_equal(162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "1"))
# Correct behavior
# assert_equal(255, ImageColor.getcolor("rgba(0, 255, 115, 33)", "1"))
Image.new("1", (1, 1), "white")
assert_equal((0, 255), ImageColor.getcolor("black", "LA"))
assert_equal((255, 255), ImageColor.getcolor("white", "LA"))
assert_equal((162, 33), ImageColor.getcolor("rgba(0, 255, 115, 33)", "LA"))
Image.new("LA", (1, 1), "white")

View File

@ -57,6 +57,13 @@ def test_parser():
# https://github.com/python-imaging/Pillow/issues/78
#assert_exception(IOError, lambda: roundtrip("PDF"))
def test_ico():
with open('Tests/images/python.ico', 'rb') as f:
data = f.read()
p = ImageFile.Parser()
p.feed(data)
assert_equal((48,48), p.image.size)
def test_safeblock():
im1 = lena()

View File

@ -3,7 +3,7 @@ from tester import *
from PIL import Image
try:
from PIL import ImageTk
except ImportError as v:
except (OSError, ImportError) as v:
skip(v)
success()

View File

@ -846,7 +846,7 @@ _crop(ImagingObject* self, PyObject* args)
}
static PyObject*
_expand(ImagingObject* self, PyObject* args)
_expand_image(ImagingObject* self, PyObject* args)
{
int x, y;
int mode = 0;
@ -2239,30 +2239,66 @@ textwidth(ImagingFontObject* self, const unsigned char* text)
return xsize;
}
void _font_text_asBytes(PyObject* encoded_string, unsigned char** text){
PyObject* bytes = NULL;
*text = NULL;
if (PyUnicode_CheckExact(encoded_string)){
bytes = PyUnicode_AsLatin1String(encoded_string);
} else if (PyBytes_Check(encoded_string)) {
bytes = encoded_string;
}
if (bytes) {
*text = (unsigned char*)PyBytes_AsString(bytes);
return;
}
#if PY_VERSION_HEX < 0x03000000
/* likely case here is py2.x with an ordinary string.
but this isn't defined in Py3.x */
if (PyString_Check(encoded_string)) {
*text = (unsigned char *)PyString_AsString(encoded_string);
}
#endif
}
static PyObject*
_font_getmask(ImagingFontObject* self, PyObject* args)
{
Imaging im;
Imaging bitmap;
int x, b;
int i=0;
int status;
Glyph* glyph;
PyObject* encoded_string;
unsigned char* text;
char* mode = "";
if (!PyArg_ParseTuple(args, "s|s:getmask", &text, &mode))
if (!PyArg_ParseTuple(args, "O|s:getmask", &encoded_string, &mode)){
return NULL;
}
_font_text_asBytes(encoded_string, &text);
if (!text) {
return NULL;
}
im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize);
if (!im)
if (!im) {
return NULL;
}
b = 0;
(void) ImagingFill(im, &b);
b = self->baseline;
for (x = 0; *text; text++) {
glyph = &self->glyphs[*text];
for (x = 0; text[i]; i++) {
glyph = &self->glyphs[text[i]];
bitmap = ImagingCrop(
self->bitmap,
glyph->sx0, glyph->sy0, glyph->sx1, glyph->sy1
@ -2279,7 +2315,6 @@ _font_getmask(ImagingFontObject* self, PyObject* args)
x = x + glyph->dx;
b = b + glyph->dy;
}
return PyImagingNew(im);
failed:
@ -2291,9 +2326,16 @@ static PyObject*
_font_getsize(ImagingFontObject* self, PyObject* args)
{
unsigned char* text;
if (!PyArg_ParseTuple(args, "s:getsize", &text))
PyObject* encoded_string;
if (!PyArg_ParseTuple(args, "O:getsize", &encoded_string))
return NULL;
_font_text_asBytes(encoded_string, &text);
if (!text) {
return NULL;
}
return Py_BuildValue("ii", textwidth(self, text), self->ysize);
}
@ -2954,7 +2996,7 @@ static struct PyMethodDef methods[] = {
{"crackcode", (PyCFunction)_crackcode, 1},
#endif
{"crop", (PyCFunction)_crop, 1},
{"expand", (PyCFunction)_expand, 1},
{"expand", (PyCFunction)_expand_image, 1},
{"filter", (PyCFunction)_filter, 1},
{"histogram", (PyCFunction)_histogram, 1},
#ifdef WITH_MODEFILTER

18
depends/install_openjpeg.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
# install openjpeg
if [ ! -f openjpeg-2.0.0.tar.gz ]; then
wget 'https://openjpeg.googlecode.com/files/openjpeg-2.0.0.tar.gz'
fi
rm -r openjpeg-2.0.0
tar -xvzf openjpeg-2.0.0.tar.gz
pushd openjpeg-2.0.0
cmake -DCMAKE_INSTALL_PREFIX=/usr . && make && sudo make install
popd

18
depends/install_webp.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
# install webp
if [ ! -f libwebp-0.4.0.tar.gz ]; then
wget 'https://webp.googlecode.com/files/libwebp-0.4.0.tar.gz'
fi
rm -r libwebp-0.4.0
tar -xvzf libwebp-0.4.0.tar.gz
pushd libwebp-0.4.0
./configure --prefix=/usr --enable-libwebpmux --enable-libwebpdemux && make && sudo make install
popd

View File

@ -105,7 +105,6 @@ Create JPEG thumbnails
except IOError:
print("cannot create thumbnail for", infile)
It is important to note that the library doesnt decode or load the raster data
unless it really has to. When you open a file, the file header is read to
determine the file format and extract things like mode, size, and other

View File

@ -1,7 +1,7 @@
Pillow: a modern fork of PIL
============================
Pillow
======
Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the
Pillow is the 'friendly' PIL fork by Alex Clark and Contributors. PIL is the
Python Imaging Library by Fredrik Lundh and Contributors.
.. image:: https://travis-ci.org/python-imaging/Pillow.png
@ -15,7 +15,7 @@ Python Imaging Library by Fredrik Lundh and Contributors.
:target: https://pypi.python.org/pypi/Pillow/
:alt: Number of PyPI downloads
To start using Pillow, read the :doc:`installation
To start using Pillow, please read the :doc:`installation
instructions <installation>`.
If you can't find the information you need, try the old `PIL Handbook`_, but be

View File

@ -172,6 +172,15 @@ Python Wheels
$ pip install --use-wheel Pillow
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
to a specific version:
::
$ pip install --use-wheel Pillow==2.3.0
Platform support
----------------
@ -216,4 +225,6 @@ current versions of Linux, OS X, and Windows.
+----------------------------------+-------------+------------------------------+------------------------------+-----------------------+
| Windows 8 Pro |Yes | 2.6,2.7,3.2,3.3,3.4a3 | 2.2.0 |x86,x86-64 |
+----------------------------------+-------------+------------------------------+------------------------------+-----------------------+
| Windows 8.1 Pro |Yes | 2.6,2.7,3.2,3.3,3.4 | 2.3.0 |x86,x86-64 |
+----------------------------------+-------------+------------------------------+------------------------------+-----------------------+

View File

@ -364,15 +364,19 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
char *mode;
char *rawmode;
int bits = 8;
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits))
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits)) {
return NULL;
}
encoder = PyImaging_EncoderNew(0);
if (encoder == NULL)
if (encoder == NULL) {
return NULL;
}
if (get_packer(encoder, mode, rawmode) < 0)
if (get_packer(encoder, mode, rawmode) < 0) {
return NULL;
}
encoder->encode = ImagingPcxEncode;

View File

@ -57,7 +57,16 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
}
if (state->x >= state->bytes) {
if (state->bytes % state->xsize && state->bytes > state->xsize) {
int bands = state->bytes / state->xsize;
int stride = state->bytes / bands;
int i;
for (i=1; i< bands; i++) { // note -- skipping first band
memmove(&state->buffer[i*state->xsize],
&state->buffer[i*stride],
state->xsize);
}
}
/* Got a full line, unpack it */
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
state->xoff * im->pixelsize, state->buffer,

View File

@ -26,23 +26,41 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
UINT8* ptr;
int this;
int bytes_per_line = 0;
int padding = 0;
int stride = 0;
int bpp = 0;
int planes = 1;
int i;
ptr = buf;
if (!state->state) {
/* sanity check */
if (state->xsize <= 0 || state->ysize <= 0) {
state->errcode = IMAGING_CODEC_END;
return 0;
}
state->bytes = (state->xsize*state->bits + 7) / 8;
state->state = FETCH;
}
for (;;)
bpp = state->bits;
if (state->bits == 24){
planes = 3;
bpp = 8;
}
bytes_per_line = (state->xsize*bpp + 7) / 8;
/* The stride here needs to be kept in sync with the version in
PcxImagePlugin.py. If it's not, the header and the body of the
image will be out of sync and bad things will happen on decode.
*/
stride = bytes_per_line + (bytes_per_line % 2);
padding = stride - bytes_per_line;
for (;;) {
switch (state->state) {
case FETCH:
@ -68,17 +86,22 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* fall through */
case ENCODE:
/* compress this line */
/* when we arrive here, "count" contains the number of
bytes having the value of "LAST" that we've already
seen */
while (state->x < state->bytes) {
while (state->x < planes * bytes_per_line) {
/* If we're encoding an odd width file, and we've
got more than one plane, we need to pad each
color row with padding bytes at the end. Since
The pixels are stored RRRRRGGGGGBBBBB, so we need
to have the padding be RRRRRPGGGGGPBBBBBP. Hence
the double loop
*/
while (state->x % bytes_per_line) {
if (state->count == 63) {
/* this run is full; flush it */
if (bytes < 2)
return ptr - buf;
@ -93,23 +116,23 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
this = state->buffer[state->x];
if (this == state->LAST) {
/* extend the current run */
state->x++;
state->count++;
} else {
/* start a new run */
if (state->count == 1 && (state->LAST < 0xc0)) {
if (bytes < 1)
if (bytes < 1) {
return ptr - buf;
}
*ptr++ = state->LAST;
bytes--;
} else {
if (state->count > 0) {
if (bytes < 2)
if (bytes < 2) {
return ptr - buf;
}
*ptr++ = 0xc0 | state->count;
*ptr++ = state->LAST;
bytes -= 2;
@ -126,23 +149,40 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* end of line; flush the current run */
if (state->count == 1 && (state->LAST < 0xc0)) {
if (bytes < 1)
if (bytes < 1 + padding) {
return ptr - buf;
}
*ptr++ = state->LAST;
bytes--;
} else {
if (state->count > 0) {
if (bytes < 2)
if (bytes < 2 + padding) {
return ptr - buf;
}
*ptr++ = 0xc0 | state->count;
*ptr++ = state->LAST;
bytes -= 2;
}
}
if (bytes < padding) {
return ptr - buf;
}
/* add the padding */
for (i=0;i<padding;i++){
*ptr++=0;
bytes--;
}
/* reset for the next color plane. */
if (state->x < planes * bytes_per_line) {
state->count = 1;
state->LAST = state->buffer[state->x];
state->x++;
}
}
/* read next line */
state->state = FETCH;
break;
}
}
}
}
}

View File

@ -81,7 +81,8 @@ def _read(file):
try:
import _tkinter
except ImportError:
except (ImportError, OSError):
# pypy emits an oserror
_tkinter = None
@ -225,7 +226,7 @@ class pil_build_ext(build_ext):
_add_directory(include_dirs, "/usr/X11/include")
elif sys.platform.startswith("linux"):
for platform_ in (plat.processor(), plat.architecture()[0]):
for platform_ in (plat.architecture()[0], plat.processor()):
if not platform_:
continue