mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 01:04:29 +03:00
Merge remote-tracking branch 'upstream/master' into landscape-fixes
This commit is contained in:
commit
947e34616c
35
CHANGES.rst
35
CHANGES.rst
|
@ -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]
|
||||
|
||||
|
|
25
MANIFEST.in
25
MANIFEST.in
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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
3
PIL/OleFileIO.py
Normal file → Executable 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
34
Sane/CHANGES
34
Sane/CHANGES
|
@ -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.
|
|
@ -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.
|
1405
Sane/_sane.c
1405
Sane/_sane.c
File diff suppressed because it is too large
Load Diff
|
@ -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()
|
|
@ -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()
|
288
Sane/sane.py
288
Sane/sane.py
|
@ -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
|
294
Sane/sanedoc.txt
294
Sane/sanedoc.txt
|
@ -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)
|
||||
|
|
@ -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
BIN
Tests/images/hopper.msp
Normal file
Binary file not shown.
BIN
Tests/images/hopper_gray_4bpp.tif
Normal file
BIN
Tests/images/hopper_gray_4bpp.tif
Normal file
Binary file not shown.
BIN
Tests/images/total-pages-zero.tif
Normal file
BIN
Tests/images/total-pages-zero.tif
Normal file
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
42
Tests/test_scipy.py
Normal 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)
|
||||
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -16,7 +16,7 @@ Let’s 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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
0
libImaging/Jpeg2KEncode.c
Executable file → Normal file
Loading…
Reference in New Issue
Block a user