mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-11 12:17:14 +03:00
Merge pull request #962 from hugovk/sane
Remove Sane directory now it has its own repo
This commit is contained in:
commit
ffa8852ac0
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])
|
|
Loading…
Reference in New Issue
Block a user