Merge remote-tracking branch 'upstream/master' into landscape-fixes

This commit is contained in:
hugovk 2014-11-01 09:44:10 +02:00
commit 947e34616c
38 changed files with 251 additions and 2233 deletions

View File

@ -1,9 +1,42 @@
Changelog (Pillow)
==================
2.6.0 (unreleased)
2.7.0 (unreleased)
------------------
- Support for 4-bit greyscale TIFF images #980
[hugovk, wiredfool]
- Updated manifest #957
[wiredfool]
- Fix PyPy 2.4 regression #952
[wiredfool]
- Webp Metadata Skip Test comments #954
[wiredfool]
- Fixes for things rpmlint complains about #942
[manisandro]
2.6.1 (2014-10-11)
------------------
- Fix SciPy regression in Image.resize #945
[wiredfool]
- Fix manifest to include all test files.
[aclark]
2.6.0 (2014-10-01)
------------------
- Relax precision of ImageDraw tests for x86, GimpGradient for PPC
[wiredfool]
2.6.0-rc1 (2014-09-29)
----------------------
- Use redistributable image for testing #884
[hugovk]

View File

@ -1,40 +1,26 @@
include *.c
include *.h
include *.md
include *.py
include *.rst
include *.txt
include *.yaml
include .coveragerc
include .gitattributes
include .travis.yml
include Makefile
include tox.ini
recursive-include Images *.bdf
recursive-include Images *.fli
recursive-include Images *.gif
recursive-include Images *.icns
recursive-include Images *.ico
recursive-include Images *.jpg
recursive-include Images *.pbm
recursive-include Images *.pil
recursive-include Images *.png
recursive-include Images *.ppm
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 *.rst
recursive-include Sane *.txt
recursive-include Sane CHANGES
recursive-include Sane README
recursive-include Sane README.rst
recursive-include Scripts *.py
recursive-include Scripts *.rst
recursive-include Scripts *.sh
recursive-include Scripts README
recursive-include Scripts README.rst
recursive-include Tests *.bdf
recursive-include Tests *.bin
recursive-include Tests *.bmp
@ -44,10 +30,11 @@ recursive-include Tests *.dcx
recursive-include Tests *.doc
recursive-include Tests *.eps
recursive-include Tests *.fli
recursive-include Tests *.ggr
recursive-include Tests *.gif
recursive-include Tests *.gnuplot
recursive-include Tests *.html
recursive-include Tests *.icm
recursive-include Tests *.icc
recursive-include Tests *.icns
recursive-include Tests *.ico
recursive-include Tests *.j2k
@ -70,6 +57,7 @@ recursive-include Tests *.rst
recursive-include Tests *.sgi
recursive-include Tests *.spider
recursive-include Tests *.tar
recursive-include Tests *.tga
recursive-include Tests *.tif
recursive-include Tests *.tiff
recursive-include Tests *.ttf
@ -78,7 +66,6 @@ recursive-include Tests *.webp
recursive-include Tests *.xpm
recursive-include Tk *.c
recursive-include Tk *.rst
recursive-include Tk *.txt
recursive-include depends *.rst
recursive-include depends *.sh
recursive-include docs *.bat

View File

@ -1010,8 +1010,6 @@ class Image:
def draft(self, mode, size):
"""
NYI
Configures the image file loader so it returns a version of the
image that as closely as possible matches the given mode and
size. For example, you can use this method to convert a color
@ -1530,6 +1528,7 @@ class Image:
self.load()
size=tuple(size)
if self.size == size:
return self._new(self.im)
@ -2335,7 +2334,7 @@ def composite(image1, image2, mask):
:param image1: The first image.
:param image2: The second image. Must have the same mode and
size as the first image.
:param mask: A mask image. This image can can have mode
:param mask: A mask image. This image can have mode
"1", "L", or "RGBA", and must have the same size as the
other two images.
"""

View File

@ -90,8 +90,8 @@ try:
except ImportError as ex:
# Allow error import for doc purposes, but error out when accessing
# anything in core.
from _util import import_err
_imagingcms = import_err(ex)
from _util import deferred_error
_imagingcms = deferred_error(ex)
from PIL._util import isStringType
core = _imagingcms

3
PIL/OleFileIO.py Normal file → Executable file
View File

@ -1,5 +1,4 @@
#!/usr/local/bin/python
# -*- coding: latin-1 -*-
#!/usr/bin/env python
## OleFileIO_PL:
## Module to read Microsoft OLE2 files (also called Structured Storage or
## Microsoft Compound Document File Format), such as Microsoft Office

View File

@ -149,6 +149,7 @@ OPEN_INFO = {
(II, 0, 1, 2, (8,), ()): ("L", "L;IR"),
(II, 0, 3, 1, (32,), ()): ("F", "F;32F"),
(II, 1, 1, 1, (1,), ()): ("1", "1"),
(II, 1, 1, 1, (4,), ()): ("L", "L;4"),
(II, 1, 1, 2, (1,), ()): ("1", "1;R"),
(II, 1, 1, 1, (8,), ()): ("L", "L"),
(II, 1, 1, 1, (8, 8), (2,)): ("LA", "LA"),
@ -449,10 +450,10 @@ class ImageFileDirectory(collections.MutableMapping):
if size > 4:
here = fp.tell()
if Image.DEBUG:
print ("Tag Location: %s" %here)
print("Tag Location: %s" % here)
fp.seek(i32(ifd, 8))
if Image.DEBUG:
print ("Data Location: %s" %fp.tell())
print("Data Location: %s" % fp.tell())
data = ImageFile._safe_read(fp, size)
fp.seek(here)
else:
@ -659,19 +660,19 @@ class TiffImageFile(ImageFile.ImageFile):
if not self.__next:
raise EOFError("no more images in TIFF file")
if Image.DEBUG:
print("Seeking to frame %s, on frame %s, __next %s, location: %s"%
(frame, self.__frame, self.__next, self.fp.tell()))
print("Seeking to frame %s, on frame %s, __next %s, location: %s" %
(frame, self.__frame, self.__next, self.fp.tell()))
# reset python3 buffered io handle in case fp
# was passed to libtiff, invalidating the buffer
self.fp.tell()
self.fp.seek(self.__next)
if Image.DEBUG:
print("Loading tags, location: %s"%self.fp.tell())
print("Loading tags, location: %s" % self.fp.tell())
self.tag.load(self.fp)
self.__next = self.tag.next
self.__frame += 1
self._setup()
def _tell(self):
return self.__frame
@ -883,6 +884,10 @@ class TiffImageFile(ImageFile.ImageFile):
try:
fp = hasattr(self.fp, "fileno") and \
os.dup(self.fp.fileno())
# flush the file descriptor, prevents error on pypy 2.4+
# should also eliminate the need for fp.tell for py3
# in _seek
self.fp.flush()
except IOError:
# io.BytesIO have a fileno, but returns an IOError if
# it doesn't use a file descriptor.
@ -1149,8 +1154,11 @@ def _save(im, fp, filename):
# following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = float(v[0][0])/float(v[0][1])
continue
if type(v) == tuple and len(v) > 2:
if (type(v) == tuple and
(len(v) > 2 or
(len(v) == 2 and v[1] == 0))):
# List of ints?
# Avoid divide by zero in next if-clause
if type(v[0]) in (int, float):
atts[k] = list(v)
continue

View File

@ -1,5 +1,3 @@
# -*- coding: iso-8859-1 -*-
#
# The Python Imaging Library.
# $Id$
#
@ -76,7 +74,7 @@ def open(filename):
quake2palette = (
# default palette taken from piffo 0.93 by Hans Häggström
# default palette taken from piffo 0.93 by Hans Häggström
b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"

View File

@ -12,7 +12,7 @@
# ;-)
VERSION = '1.1.7' # PIL version
PILLOW_VERSION = '2.5.3' # Pillow
PILLOW_VERSION = '2.6.0' # Pillow
_plugins = ['BmpImagePlugin',
'BufrStubImagePlugin',

View File

@ -6,6 +6,7 @@ Released quarterly.
* [ ] Get master to the appropriate code release state. [Travis CI](https://travis-ci.org/python-pillow/Pillow) should be running cleanly for all merges to master.
* [ ] Update version in `PIL/__init__.py`, `setup.py`, `_imaging.c`, Update date in `CHANGES.rst`.
* [ ] Run pre-release check via `make pre`
* [ ] Tag and push to release branch in python-pillow repo.
* [ ] Upload binaries.
@ -16,6 +17,7 @@ Released as required for security or installation fixes.
* [ ] Make necessary changes in master.
* [ ] Cherry pick individual commits. Touch up `CHANGES.rst` to reflect reality.
* [ ] Update version in `PIL/__init__.py`, `setup.py`, `_imaging.c`
* [ ] Run pre-release check via `make pre`
* [ ] Push to release branch in personal repo. Let Travis run cleanly.
* [ ] Tag and push to release branch in python-pillow repo.
* [ ] Upload binaries.
@ -28,6 +30,7 @@ Security fixes that need to be pushed to the distros prior to public release.
* [ ] Commit against master, cherry pick to affected release branches.
* [ ] Run local test matrix on each release & Python version.
* [ ] Privately send to distros.
* [ ] Run pre-release check via `make pre`
* [ ] Amend any commits with the CVE #
* [ ] On release date, tag and push to GitHub.
```
@ -53,3 +56,4 @@ python setup.py sdist upload
* [ ] Retrieve the OS X Wheels from Rackspace files, upload to PyPi (Twine?)
* [ ] Grab Windows binaries, `twine upload dist/*.[whl|egg]`. Manually upload .exe installers.
* [ ] Announce release availability. [Twitter](https://twitter.com/pythonpillow), web.

View File

@ -1,34 +0,0 @@
from V1.0 to V2.0
_sane.c:
- Values for option constraints are correctly translated to floats
if value type is TYPE_FIXED for SANE_CONSTRAINT_RANGE and
SANE_CONSTRAINT_WORD_LIST
- added constants INFO_INEXACT, INFO_RELOAD_OPTIONS,
INFO_RELOAD_PARAMS (possible return values of set_option())
to module dictionnary.
- removed additional return variable 'i' from SaneDev_get_option(),
because it is only set when SANE_ACTION_SET_VALUE is used.
- scanDev.get_parameters() now returns the scanner mode as 'format',
no more the typical PIL codes. So 'L' became 'gray', 'RGB' is now
'color', 'R' is 'red', 'G' is 'green', 'B' is 'red'. This matches
the way scanDev.mode is set.
This should be the only incompatibility vs. version 1.0.
sane.py
- ScanDev got new method __load_option_dict() called from __init__()
and from __setattr__() if backend reported that the frontend should
reload the options.
- Nice human-readable __repr__() method added for class Option
- if __setattr__ (i.e. set_option) reports that all other options
have to be reloaded due to a change in the backend then they are reloaded.
- due to the change in SaneDev_get_option() only the 'value' is
returned from get_option().
- in __setattr__ integer values are automatically converted to floats
if SANE backend expects SANE_FIXED (i.e. fix-point float)
- The scanner options can now directly be accessed via scanDev[optionName]
instead scanDev.opt[optionName]. (The old way still works).
V1.0:
A.M. Kuchling's original pysane package.

View File

@ -1,22 +0,0 @@
Python SANE module V1.1 (30 Sep. 2004)
================================================================================
The SANE module provides an interface to the SANE scanner and frame
grabber interface for Linux. This module was contributed by Andrew
Kuchling and is extended and currently maintained by Ralph Heinkel
(rheinkel-at-email.de). If you write to me please make sure to have the
word 'SANE' or 'sane' in the subject of your mail, otherwise it might
be classified as spam in the future.
To build this module, type (in the Sane directory)::
python setup.py build
In order to install the module type::
python setup.py install
For some basic documentation please look at the file sanedoc.txt
The two demo_*.py scripts give basic examples on how to use the software.

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +0,0 @@
#!/usr/bin/env python
#
# Shows how to scan a 16 bit grayscale image into a numarray object
#
from __future__ import print_function
# Get the path set up to find PIL modules if not installed yet:
import sys ; sys.path.append('../PIL')
from numarray import *
import sane
import Image
def toImage(arr):
if arr.type().bytes == 1:
# need to swap coordinates btw array and image (with [::-1])
im = Image.frombytes('L', arr.shape[::-1], arr.tostring())
else:
arr_c = arr - arr.min()
arr_c *= (255./arr_c.max())
arr = arr_c.astype(UInt8)
# need to swap coordinates btw array and image (with [::-1])
im = Image.frombytes('L', arr.shape[::-1], arr.tostring())
return im
print('SANE version:', sane.init())
print('Available devices=', sane.get_devices())
s = sane.open(sane.get_devices()[0][0])
# Set scan parameters
s.mode = 'gray'
s.br_x=320. ; s.br_y=240.
print('Device parameters:', s.get_parameters())
s.depth=16
arr16 = s.arr_scan()
toImage(arr16).show()

View File

@ -1,35 +0,0 @@
#!/usr/bin/env python
#
# Shows how to scan a color image into a PIL rgb-image
#
from __future__ import print_function
# Get the path set up to find PIL modules if not installed yet:
import sys ; sys.path.append('../PIL')
import sane
print('SANE version:', sane.init())
print('Available devices=', sane.get_devices())
s = sane.open(sane.get_devices()[0][0])
s.mode = 'color'
s.br_x=320. ; s.br_y=240.
print('Device parameters:', s.get_parameters())
# Initiate the scan
s.start()
# Get an Image object
# (For my B&W QuickCam, this is a grey-scale image. Other scanning devices
# may return a
im=s.snap()
# Write the image out as a GIF file
#im.save('foo.gif')
# The show method() simply saves the image to a temporary file and calls "xv".
im.show()

View File

@ -1,288 +0,0 @@
# sane.py
#
# Python wrapper on top of the _sane module, which is in turn a very
# thin wrapper on top of the SANE library. For a complete understanding
# of SANE, consult the documentation at the SANE home page:
# http://www.mostang.com/sane/ .
__version__ = '2.0'
__author__ = ['Andrew Kuchling', 'Ralph Heinkel']
from PIL import Image
import _sane
from _sane import *
TYPE_STR = { TYPE_BOOL: "TYPE_BOOL", TYPE_INT: "TYPE_INT",
TYPE_FIXED: "TYPE_FIXED", TYPE_STRING: "TYPE_STRING",
TYPE_BUTTON: "TYPE_BUTTON", TYPE_GROUP: "TYPE_GROUP" }
UNIT_STR = { UNIT_NONE: "UNIT_NONE",
UNIT_PIXEL: "UNIT_PIXEL",
UNIT_BIT: "UNIT_BIT",
UNIT_MM: "UNIT_MM",
UNIT_DPI: "UNIT_DPI",
UNIT_PERCENT: "UNIT_PERCENT",
UNIT_MICROSECOND: "UNIT_MICROSECOND" }
class Option:
"""Class representing a SANE option.
Attributes:
index -- number from 0 to n, giving the option number
name -- a string uniquely identifying the option
title -- single-line string containing a title for the option
desc -- a long string describing the option; useful as a help message
type -- type of this option. Possible values: TYPE_BOOL,
TYPE_INT, TYPE_STRING, and so forth.
unit -- units of this option. Possible values: UNIT_NONE,
UNIT_PIXEL, etc.
size -- size of the value in bytes
cap -- capabilities available; CAP_EMULATED, CAP_SOFT_SELECT, etc.
constraint -- constraint on values. Possible values:
None : No constraint
(min,max,step) Integer values, from min to max, stepping by
list of integers or strings: only the listed values are allowed
"""
def __init__(self, args, scanDev):
self.scanDev = scanDev # needed to get current value of this option
self.index, self.name = args[0], args[1]
self.title, self.desc = args[2], args[3]
self.type, self.unit = args[4], args[5]
self.size, self.cap = args[6], args[7]
self.constraint = args[8]
def f(x):
if x=='-': return '_'
else: return x
if not isinstance(self.name, str): self.py_name=str(self.name)
else: self.py_name=''.join(map(f, self.name))
def is_active(self):
return _sane.OPTION_IS_ACTIVE(self.cap)
def is_settable(self):
return _sane.OPTION_IS_SETTABLE(self.cap)
def __repr__(self):
if self.is_settable():
settable = 'yes'
else:
settable = 'no'
if self.is_active():
active = 'yes'
curValue = repr(getattr(self.scanDev, self.py_name))
else:
active = 'no'
curValue = '<not available, inactive option>'
s = """\nName: %s
Cur value: %s
Index: %d
Title: %s
Desc: %s
Type: %s
Unit: %s
Constr: %s
active: %s
settable: %s\n""" % (self.py_name, curValue,
self.index, self.title, self.desc,
TYPE_STR[self.type], UNIT_STR[self.unit],
repr(self.constraint), active, settable)
return s
class _SaneIterator:
""" intended for ADF scans.
"""
def __init__(self, device):
self.device = device
def __iter__(self):
return self
def __del__(self):
self.device.cancel()
def next(self):
try:
self.device.start()
except error as v:
if v == 'Document feeder out of documents':
raise StopIteration
else:
raise
return self.device.snap(1)
class SaneDev:
"""Class representing a SANE device.
Methods:
start() -- initiate a scan, using the current settings
snap() -- snap a picture, returning an Image object
arr_snap() -- snap a picture, returning a numarray object
cancel() -- cancel an in-progress scanning operation
fileno() -- return the file descriptor for the scanner (handy for select)
Also available, but rather low-level:
get_parameters() -- get the current parameter settings of the device
get_options() -- return a list of tuples describing all the options.
Attributes:
optlist -- list of option names
You can also access an option name to retrieve its value, and to
set it. For example, if one option has a .name attribute of
imagemode, and scanner is a SaneDev object, you can do:
print scanner.imagemode
scanner.imagemode = 'Full frame'
scanner.['imagemode'] returns the corresponding Option object.
"""
def __init__(self, devname):
d=self.__dict__
d['sane_signature'] = self._getSaneSignature(devname)
d['scanner_model'] = d['sane_signature'][1:3]
d['dev'] = _sane._open(devname)
self.__load_option_dict()
def _getSaneSignature(self, devname):
devices = get_devices()
if not devices:
raise RuntimeError('no scanner available')
for dev in devices:
if devname == dev[0]:
return dev
raise RuntimeError('no such scan device "%s"' % devname)
def __load_option_dict(self):
d=self.__dict__
d['opt']={}
optlist=d['dev'].get_options()
for t in optlist:
o=Option(t, self)
if o.type!=TYPE_GROUP:
d['opt'][o.py_name]=o
def __setattr__(self, key, value):
dev=self.__dict__['dev']
optdict=self.__dict__['opt']
if key not in optdict:
self.__dict__[key]=value ; return
opt=optdict[key]
if opt.type==TYPE_GROUP:
raise AttributeError("Groups can't be set: "+key)
if not _sane.OPTION_IS_ACTIVE(opt.cap):
raise AttributeError('Inactive option: '+key)
if not _sane.OPTION_IS_SETTABLE(opt.cap):
raise AttributeError("Option can't be set by software: "+key)
if isinstance(value, int) and opt.type == TYPE_FIXED:
# avoid annoying errors of backend if int is given instead float:
value = float(value)
self.last_opt = dev.set_option(opt.index, value)
# do binary AND to find if we have to reload options:
if self.last_opt & INFO_RELOAD_OPTIONS:
self.__load_option_dict()
def __getattr__(self, key):
dev=self.__dict__['dev']
optdict=self.__dict__['opt']
if key=='optlist':
return list(self.opt.keys())
if key=='area':
return (self.tl_x, self.tl_y),(self.br_x, self.br_y)
if key not in optdict:
raise AttributeError('No such attribute: '+key)
opt=optdict[key]
if opt.type==TYPE_BUTTON:
raise AttributeError("Buttons don't have values: "+key)
if opt.type==TYPE_GROUP:
raise AttributeError("Groups don't have values: "+key)
if not _sane.OPTION_IS_ACTIVE(opt.cap):
raise AttributeError('Inactive option: '+key)
value = dev.get_option(opt.index)
return value
def __getitem__(self, key):
return self.opt[key]
def get_parameters(self):
"""Return a 5-tuple holding all the current device settings:
(format, last_frame, (pixels_per_line, lines), depth, bytes_per_line)
- format is one of 'L' (grey), 'RGB', 'R' (red), 'G' (green), 'B' (blue).
- last_frame [bool] indicates if this is the last frame of a multi frame image
- (pixels_per_line, lines) specifies the size of the scanned image (x,y)
- lines denotes the number of scanlines per frame
- depth gives number of pixels per sample
"""
return self.dev.get_parameters()
def get_options(self):
"Return a list of tuples describing all the available options"
return self.dev.get_options()
def start(self):
"Initiate a scanning operation"
return self.dev.start()
def cancel(self):
"Cancel an in-progress scanning operation"
return self.dev.cancel()
def snap(self, no_cancel=0):
"Snap a picture, returning a PIL image object with the results"
(mode, last_frame,
(xsize, ysize), depth, bytes_per_line) = self.get_parameters()
if mode in ['gray', 'red', 'green', 'blue']:
format = 'L'
elif mode == 'color':
format = 'RGB'
else:
raise ValueError('got unknown "mode" from self.get_parameters()')
im=Image.new(format, (xsize,ysize))
self.dev.snap( im.im.id, no_cancel )
return im
def scan(self):
self.start()
return self.snap()
def multi_scan(self):
return _SaneIterator(self)
def arr_snap(self, multipleOf=1):
"""Snap a picture, returning a numarray object with the results.
By default the resulting array has the same number of pixels per
line as specified in self.get_parameters()[2][0]
However sometimes it is necessary to obtain arrays where
the number of pixels per line is e.g. a multiple of 4. This can then
be achieved with the option 'multipleOf=4'. So if the scanner
scanned 34 pixels per line, you will obtain an array with 32 pixels
per line.
"""
(mode, last_frame, (xsize, ysize), depth, bpl) = self.get_parameters()
if not mode in ['gray', 'red', 'green', 'blue']:
raise RuntimeError('arr_snap() only works with monochrome images')
if multipleOf < 1:
raise ValueError('option "multipleOf" must be a positive number')
elif multipleOf > 1:
pixels_per_line = xsize - divmod(xsize, 4)[1]
else:
pixels_per_line = xsize
return self.dev.arr_snap(pixels_per_line)
def arr_scan(self, multipleOf=1):
self.start()
return self.arr_snap(multipleOf=multipleOf)
def fileno(self):
"Return the file descriptor for the scanning device"
return self.dev.fileno()
def close(self):
self.dev.close()
def open(devname):
"Open a device for scanning"
new=SaneDev(devname)
return new

View File

@ -1,294 +0,0 @@
The _sane_ module is an Python interface to the SANE (Scanning is Now
Easy) library, which provides access to various raster scanning
devices such as flatbed scanners and digital cameras. For more
information about SANE, consult the SANE Web site at
http://www.mostang.com/sane/ . Note that this
documentation doesn't duplicate all the information in the SANE
documentation, which you must also consult to get a complete
understanding.
This module has been originally developed by A.M. Kuchling (amk1@erols.com),
now development has been taken over by Ralph Heinkel (rheinkel-at-email.de).
If you write to me please make sure to have the word 'SANE' or 'sane' in
the subject of your mail, otherwise it might be classified as spam in the
future.
The module exports two object types, a bunch of constants, and two
functions.
get_devices()
Return a list of 4-tuples containing the available scanning
devices. Each tuple contains 4 strings: the device name, suitable for
passing to _open()_; the device's vendor; the model; and the type of
device, such as 'virtual device' or 'video camera'.
>>> import sane ; sane.get_devices()
[('epson:libusb:001:004', 'Epson', 'GT-8300', 'flatbed scanner')]
open(devicename)
Open a device, given a string containing its name. SANE
devices have names like 'epson:libusb:001:004'. If the attempt
to open the device fails, a _sane.error_ exception will be raised. If
there are no problems, a SaneDev object will be returned.
As an easy way to open the scanner (if only one is available) just type
>>> sane.open(sane.get_devices()[0][0])
SaneDev objects
===============
The basic process of scanning an image consists of getting a SaneDev
object for the device, setting various parameters, starting the scan,
and then reading the image data. Images are composed of one or more
frames; greyscale and one-pass colour scanners return a single frame
containing all the image data, but 3-pass scanners will usually return
3 frames, one for each of the red, green, blue channels.
Methods:
--------
fileno()
Returns a file descriptor for the scanning device. This
method's existence means that SaneDev objects can be used by the
select module.
get_parameters()
Return a tuple containing information about the current settings of
the device and the current frame: (format, last_frame,
pixels_per_line, lines, depth, bytes_per_line).
mode -- 'gray' for greyscale image, 'color' for RGB image, or
one of 'red', 'green', 'blue' if the image is a single
channel of an RGB image (from PIL's point of view,
this is equivalent to 'L').
last_frame -- A Boolean value, which is true if this is the
last frame of the image, and false otherwise.
pixels_per_line -- Width of the frame.
lines -- Height of the frame.
depth -- Depth of the image, measured in bits. SANE will only
allow using 8, 16, or 24-bit depths.
bytes_per_line -- Bytes required to store a single line of
data, as computed from pixels_per_line and depth.
start()
Start a scan. This function must be called before the
_snap()_ method can be used.
cancel()
Cancel a scan already in progress.
snap(no_cancel=0)
Snap a single frame of data, returning a PIL Image object
containing the data. If no_cancel is false, the Sane library function
sane_cancel is called after the scan. This is reasonable in most cases,
but may cause backends for duplex ADF scanners to drop the backside image,
when snap() is called for the front side image. If no_cancel is true,
cancel() should be called manually, after all scans are finished.
scan()
This is just a shortcut for s.start(); s.snap()
Returns a PIL image
multi_scan()
This method returns an iterator. It is intended to be used for
scanning with an automatic document feeder. The next() method of the
iterator tries to start a scan. If this is successful, it returns a
PIL Image object, like scan(); if the document feeder runs out of
paper, it raises StopIteration, thereby signaling that the sequence
is ran out of items.
arr_snap(multipleOf=1)
same as snap, but the result is a NumArray object. (Not that
num_array must be installed already at compilation time, otherwise
this feature will not be activated).
By default the resulting array has the same number of pixels per
line as specified in self.get_parameters()[2][0]
However sometimes it is necessary to obtain arrays where
the number of pixels per line is e.g. a multiple of 4. This can then
be achieved with the option 'multipleOf=4'. So if the scanner
scanned 34 pixels per line, you will obtain an array with 32 pixels
per line.
Note that this only works with monochrome images (e.g. gray-scales)
arr_scan(multipleOf=1)
This is just a shortcut for s.start(); s.arr_snap(multipleOf=1)
Returns a NumArray object
close()
Closes the object.
Attributes:
-----------
SaneDev objects have a few fixed attributes which are always
available, and a larger collection of attributes which vary depending
on the device. An Epson 1660 photo scanner has attributes like
'mode', 'depth', etc.
Another (pseudo scanner), the _pnm:0_ device, takes a PNM file and
simulates a scanner using the image data; a SaneDev object
representing the _pnm:0_ device therefore has a _filename_ attribute
which can be changed to specify the filename, _contrast_ and
_brightness_ attributes to modify the returned image, and so forth.
The values of the scanner options may be an integer, floating-point
value, or string, depending on the nature of the option.
sane_signature
The tuple for this scandev that is returned by sane.get_devices()
e.g. ('epson:libusb:001:006', 'Epson', 'GT-8300', 'flatbed scanner')
scanner_model
same as sane_signature[1:3], i.e. ('Epson', 'GT-8300') for the case above.
optlist
A list containing the all the options supported by this device.
>>> import sane ; s=sane.open('epson:libusb:001:004') ; s.optlist
['focus_position', 'color_correction', 'sharpness', ...., 'br_x']
A closer look at all options listed in s.optlist can be obtained
through the SaneOption objects.
SaneOption objects
==================
SANE's option handling is its most elaborate subsystem, intended to
allow automatically generating dialog boxes and prompts for user
configuration of the scanning device. The SaneOption object can be
used to get a human-readable name and description for an option, the
units to use, and what the legal values are. No information about the
current value of the option is available; for that, read the
corresponding attribute of a SaneDev object.
This documentation does not explain all the details of SANE's option
handling; consult the SANE documentation for all the details.
A scandevice option is accessed via __getitem__. For example
s['mode'] returns the option descriptor for the mode-option which
controls whether the scanner works in color, grayscale, or b/w mode.
>>> s['mode']
Name: mode
Cur value: Color
Index: 2
Title: Scan mode
Desc: Selects the scan mode (e.g., lineart, monochrome, or color).
Type: TYPE_STRING
Unit: UNIT_NONE
Constr: ['Binary', 'Gray', 'Color']
active: yes
settable: yes
In order to change 'mode' to 'gray', just type:
>>> s.mode = 'gray'
With the attributes and methods of sane-option objects it is possible
to access individual option values:
is_active()
Returns true if the option is active.
is_settable()
Returns true if the option can be set under software control.
Attributes:
cap
An integer containing various flags about the object's
capabilities; whether it's active, whether it's settable, etc. Also
available as the _capability_ attribute.
constraint
The constraint placed on the value of this option. If it's
_None_, there are essentially no constraint of the value. It may also
be a list of integers or strings, in which case the value *must* be
one of the possibilities in the list. Numeric values may have a
3-tuple as the constraint; this 3-tuple contains _(minimum, maximum,
increment)_, and the value must be in the defined range.
desc
A lengthy description of what the option does; it may be shown
to the user for clarification.
index
An integer giving the option's index in the option list.
name
A short name for the option, as it comes from the sane-backend.
py_name
The option's name, as a legal Python identifier. The name
attribute may contain the '-' character, so it will be converted to
'_' for the py_name attribute.
size
For a string-valued option, this is the maximum length allowed.
title
A single-line string that can be used as a title string.
type
A constant giving the type of this option: will be one of the following
constants found in the SANE module:
TYPE_BOOL
TYPE_INT
TYPE_FIXED
TYPE_STRING
TYPE_BUTTON
TYPE_GROUP
unit
For numeric-valued options, this is a constant representing
the unit used for this option. It will be one of the following
constants found in the SANE module:
UNIT_NONE
UNIT_PIXEL
UNIT_BIT
UNIT_MM
UNIT_DPI
UNIT_PERCENT
Example us usage:
=================
>>> import sane
>>> print 'SANE version:', sane.init()
>>> print 'Available devices=', sane.get_devices()
SANE version: (16777230, 1, 0, 14)
>>> s = sane.open(sane.get_devices()[0][0])
>>> print 'Device parameters:', s.get_parameters()
Device parameters: ('L', 1, (424, 585), 1, 53)
>>> print s.resolution
50
## In order to scan a color image into a PIL object:
>>> s.mode = 'color'
>>> s.start()
>>> img = s.snap()
>>> img.show()
## In order to obtain a 16-bit grayscale image at 100DPI in a numarray object
## with bottom-right coordinates set to (160, 120) [in millimeter] :
>>> s.mode = 'gray'
>>> s.br_x=160. ; s.br_y=120.
>>> s.resolution = 100
>>> s.depth=16
>>> s.start()
>>> s.get_parameters()[2] # just check the size
(624, 472)
>>> arr16 = s.arr_snap()
>>> arr16
array([[63957, 64721, 65067, ..., 65535, 65535, 65535],
[63892, 64342, 64236, ..., 65535, 65535, 65535],
[64286, 64248, 64705, ..., 65535, 65535, 65535],
...,
[65518, 65249, 65058, ..., 65535, 65535, 65535],
[64435, 65047, 65081, ..., 65535, 65535, 65535],
[65309, 65438, 65535, ..., 65535, 65535, 65535]], type=UInt16)
>>> arr16.shape # inverse order of coordinates, first y, then x!
(472, 624)

View File

@ -1,24 +0,0 @@
from distutils.core import setup, Extension
PIL_BUILD_DIR = '..'
PIL_IMAGING_DIR = PIL_BUILD_DIR+'/libImaging'
defs = []
try:
import numarray
defs.append(('WITH_NUMARRAY',None))
except ImportError:
pass
sane = Extension('_sane',
include_dirs = [PIL_IMAGING_DIR],
libraries = ['sane'],
library_dirs = [PIL_IMAGING_DIR],
define_macros = defs,
sources = ['_sane.c'])
setup (name = 'pysane',
version = '2.0',
description = 'This is the pysane package',
py_modules = ['sane'],
ext_modules = [sane])

BIN
Tests/images/hopper.msp Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -80,7 +80,7 @@ class TestImage(PillowTestCase):
ret = GimpGradientFile.sphere_increasing(middle, pos)
# Assert
self.assertEqual(ret, 0.9682458365518543)
self.assert_almost_equal(ret, 0.9682458365518543)
def test_sphere_decreasing(self):
# Arrange

View File

@ -342,6 +342,24 @@ class TestFileLibTiff(LibTiffTestCase):
im.load()
self.assertFalse(im.tag.next)
def test_4bit(self):
# Arrange
test_file = "Tests/images/hopper_gray_4bpp.tif"
original = hopper("L")
# Act
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open(test_file)
TiffImagePlugin.READ_LIBTIFF = False
# Assert
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
if __name__ == '__main__':
unittest.main()

View File

@ -2,11 +2,12 @@ from helper import unittest, PillowTestCase, hopper
from PIL import Image
TEST_FILE = "Tests/images/hopper.msp"
class TestFileMsp(PillowTestCase):
def test_sanity(self):
file = self.tempfile("temp.msp")
hopper("1").save(file)
@ -17,6 +18,23 @@ class TestFileMsp(PillowTestCase):
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "MSP")
def test_open(self):
# Arrange
# Act
im = Image.open(TEST_FILE)
# Assert
self.assertEqual(im.size, (128, 128))
self.assert_image_similar(im, hopper("1"), 4)
def test_cannot_save_save_wrong_mode(self):
# Arrange
im = hopper()
file = self.tempfile("temp.msp")
# Act/Assert
self.assertRaises(IOError, lambda: im.save(file))
if __name__ == '__main__':
unittest.main()

View File

@ -144,28 +144,27 @@ class TestFileTiff(PillowTestCase):
def test_multipage(self):
# issue #862
im = Image.open('Tests/images/multipage.tiff')
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
im.seek(0)
self.assertEqual(im.size, (10,10))
self.assertEqual(im.convert('RGB').getpixel((0,0)), (0,128,0))
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 128, 0))
im.seek(1)
im.load()
self.assertEqual(im.size, (10,10))
self.assertEqual(im.convert('RGB').getpixel((0,0)), (255,0,0))
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (255, 0, 0))
im.seek(2)
im.load()
self.assertEqual(im.size, (20,20))
self.assertEqual(im.convert('RGB').getpixel((0,0)), (0,0,255))
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 0, 255))
def test_multipage_last_frame(self):
im = Image.open('Tests/images/multipage-lastframe.tif')
im.load()
self.assertEqual(im.size, (20,20))
self.assertEqual(im.convert('RGB').getpixel((0,0)), (0,0,255))
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert('RGB').getpixel((0, 0)), (0, 0, 255))
def test___str__(self):
# Arrange
@ -294,6 +293,39 @@ class TestFileTiff(PillowTestCase):
# Assert
self.assertEqual(ret, [0, 1])
def test_4bit(self):
# Arrange
test_file = "Tests/images/hopper_gray_4bpp.tif"
original = hopper("L")
# Act
im = Image.open(test_file)
# Assert
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
def test_page_number_x_0(self):
# Issue 973
# Test TIFF with tag 297 (Page Number) having value of 0 0.
# The first number is the current page number.
# The second is the total number of pages, zero means not available.
# Arrange
outfile = self.tempfile("temp.tif")
# Created by printing a page in Chrome to PDF, then:
# /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
# -dNOPAUSE /tmp/test.pdf -c quit
infile = "Tests/images/total-pages-zero.tif"
im = Image.open(infile)
# Act / Assert
# Should not divide by zero
im.save(outfile)
if __name__ == '__main__':
unittest.main()

View File

@ -8,10 +8,13 @@ class TestFileWebpMetadata(PillowTestCase):
def setUp(self):
try:
from PIL import _webp
if not _webp.HAVE_WEBPMUX:
self.skipTest('webpmux support not installed')
except:
self.skipTest('WebP support not installed')
return
if not _webp.HAVE_WEBPMUX:
self.skipTest('WebPMux support not installed')
def test_read_exif_metadata(self):

View File

@ -63,8 +63,8 @@ class TestImageDraw(PillowTestCase):
del draw
# Assert
self.assert_image_equal(
im, Image.open("Tests/images/imagedraw_arc.png"))
self.assert_image_similar(
im, Image.open("Tests/images/imagedraw_arc.png"),1)
def test_arc1(self):
self.helper_arc(BBOX1)
@ -96,8 +96,8 @@ class TestImageDraw(PillowTestCase):
del draw
# Assert
self.assert_image_equal(
im, Image.open("Tests/images/imagedraw_chord.png"))
self.assert_image_similar(
im, Image.open("Tests/images/imagedraw_chord.png"),1)
def test_chord1(self):
self.helper_chord(BBOX1)
@ -115,8 +115,8 @@ class TestImageDraw(PillowTestCase):
del draw
# Assert
self.assert_image_equal(
im, Image.open("Tests/images/imagedraw_ellipse.png"))
self.assert_image_similar(
im, Image.open("Tests/images/imagedraw_ellipse.png"),1)
def test_ellipse1(self):
self.helper_ellipse(BBOX1)
@ -153,8 +153,8 @@ class TestImageDraw(PillowTestCase):
del draw
# Assert
self.assert_image_equal(
im, Image.open("Tests/images/imagedraw_pieslice.png"))
self.assert_image_similar(
im, Image.open("Tests/images/imagedraw_pieslice.png"),1)
def test_pieslice1(self):
self.helper_pieslice(BBOX1)

View File

@ -55,6 +55,12 @@ class TestImageFile(PillowTestCase):
if EpsImagePlugin.has_ghostscript():
im1, im2 = roundtrip("EPS")
# This test fails on Ubuntu 12.04, PPC (Bigendian) It
# appears to be a ghostscript 9.05 bug, since the
# ghostscript rendering is wonky and the file is identical
# to that written on ubuntu 12.04 x64
# md5sum: ba974835ff2d6f3f2fd0053a23521d4a
# EPS comes back in RGB:
self.assert_image_similar(im1, im2.convert('L'), 20)

View File

@ -1,5 +1,7 @@
from helper import unittest, PillowTestCase
from PIL import PILLOW_VERSION
try:
import pyroma
except ImportError:
@ -23,8 +25,14 @@ class TestPyroma(PillowTestCase):
rating = pyroma.ratings.rate(data)
# Assert
# Should have a perfect score
self.assertEqual(rating, (10, []))
if 'rc' in PILLOW_VERSION:
#Pyroma needs to chill about RC versions and not kill all our tests.
self.assertEqual(rating, (9,
['The packages version number does not comply with PEP-386.']))
else:
# Should have a perfect score
self.assertEqual(rating, (10, []))
if __name__ == '__main__':

42
Tests/test_scipy.py Normal file
View File

@ -0,0 +1,42 @@
from helper import PillowTestCase
try:
import numpy as np
from numpy.testing import assert_equal
from scipy import misc
HAS_SCIPY = True
except:
HAS_SCIPY = False
class Test_scipy_resize(PillowTestCase):
""" Tests for scipy regression in 2.6.0 """
def setUp(self):
if not HAS_SCIPY:
self.skipTest("Scipy Required")
def test_imresize(self):
im = np.random.random((10,20))
for T in np.sctypes['float'] + [float]:
# 1.1 rounds to below 1.1 for float16, 1.101 works
im1 = misc.imresize(im,T(1.101))
self.assertEqual(im1.shape,(11,22))
def test_imresize4(self):
im = np.array([[1,2],
[3,4]])
res = np.array([[ 1. , 1. , 1.5, 2. ],
[ 1. , 1. , 1.5, 2. ],
[ 2. , 2. , 2.5, 3. ],
[ 3. , 3. , 3.5, 4. ]], dtype=np.float32)
# Check that resizing by target size, float and int are the same
im2 = misc.imresize(im, (4,4), mode='F') # output size
im3 = misc.imresize(im, 2., mode='F') # fraction
im4 = misc.imresize(im, 200, mode='F') # percentage
assert_equal(im2, res)
assert_equal(im3, res)
assert_equal(im4, res)

View File

@ -71,7 +71,7 @@
* See the README file for information on usage and redistribution.
*/
#define PILLOW_VERSION "2.5.3"
#define PILLOW_VERSION "2.6.0"
#include "Python.h"

View File

@ -35,9 +35,9 @@ pygments_style = 'sphinx'
### HTML output ###
from better import better_theme_path
html_theme_path = [better_theme_path]
html_theme = 'better'
#from better import better_theme_path
#html_theme_path = [better_theme_path]
#html_theme = 'better'
html_title = "Pillow v{release} (PIL fork)".format(release=release)
html_short_title = "Home"

View File

@ -16,7 +16,7 @@ Lets look at a few possible uses of this library.
Image Archives
--------------
The Python Imaging Library is ideal for for image archival and batch processing
The Python Imaging Library is ideal for image archival and batch processing
applications. You can use the library to create thumbnails, convert between
file formats, print images, etc.

View File

@ -296,7 +296,7 @@ Point Operations
The :py:meth:`~PIL.Image.Image.point` method can be used to translate the pixel
values of an image (e.g. image contrast manipulation). In most cases, a
function object expecting one argument can be passed to the this method. Each
function object expecting one argument can be passed to this method. Each
pixel is processed according to that function:
Applying point transforms
@ -397,7 +397,7 @@ Note that most drivers in the current version of the library only allow you to
seek to the next frame (as in the above example). To rewind the file, you may
have to reopen it.
The following iterator class lets you to use the for-statement to loop over the
The following iterator class lets you use the for-statement to loop over the
sequence:
A sequence iterator class

View File

@ -67,10 +67,10 @@ Many of Pillow's features require external libraries:
* Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and
above uses liblcms2. Tested with **1.19** and **2.2**.
* **libwebp** provides the Webp format.
* **libwebp** provides the WebP format.
* Pillow has been tested with version **0.1.3**, which does not read
transparent webp files. Versions **0.3.0** and **0.4.0** support
transparent WebP files. Versions **0.3.0** and **0.4.0** support
transparency.
* **tcl/tk** provides support for tkinter bitmap and photo images.
@ -121,12 +121,17 @@ Prerequisites are installed on **Ubuntu 10.04 LTS** with::
$ sudo apt-get install libtiff4-dev libjpeg62-dev zlib1g-dev \
libfreetype6-dev tcl8.5-dev tk8.5-dev python-tk
Prerequisites are installed with on **Ubuntu 12.04 LTS** or **Raspian Wheezy
Prerequisites are installed on **Ubuntu 12.04 LTS** or **Raspian Wheezy
7.0** with::
$ sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk
Prerequisites are installed on **Ubuntu 14.04 LTS** with::
$ sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk
Prerequisites are installed on **Fedora 20** with::
$ sudo yum install libtiff-devel libjpeg-devel libzip-devel freetype-devel \

View File

@ -1,17 +1,19 @@
# requirements for working on docs
sphinx-better-theme
# install pillow from master if you're into that, but RtD needs this
pillow>=2.4.0
Jinja2==2.7.1
MarkupSafe==0.18
Pygments==1.6
Sphinx==1.1.3
docopt==0.6.1
docutils==0.11
wsgiref==0.1.2
sphinx-better-theme==0.1.5
# livereload not strictly necessary but really useful (make livehtml)
tornado==3.1.1
livereload==1.0.1
## requirements for working on docs
#
## install pillow from master if you're into that, but RtD needs this
#pillow>=2.4.0
#
#Jinja2==2.7.1
#MarkupSafe==0.18
#Pygments==1.6
#Sphinx==1.1.3
#docopt==0.6.1
#docutils==0.11
#wsgiref==0.1.2
#sphinx-better-theme==0.1.5
#
## livereload not strictly necessary but really useful (make livehtml)
#tornado==3.1.1
#livereload==1.0.1

View File

@ -600,7 +600,6 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
double big_hypotenuse, small_hypotenuse, ratio_max, ratio_min;
int dxmin, dxmax, dymin, dymax;
Edge e[4];
int vertices[4][2];
DRAWINIT();

0
libImaging/Jpeg2KEncode.c Executable file → Normal file
View File

View File

@ -90,7 +90,7 @@ except (ImportError, OSError):
NAME = 'Pillow'
PILLOW_VERSION = '2.5.3'
PILLOW_VERSION = '2.6.0'
TCL_ROOT = None
JPEG_ROOT = None
JPEG2K_ROOT = None