2019-10-29 11:56:06 +00:00
|
|
|
|
.. _chap:environ:
|
|
|
|
|
|
|
|
|
|
The SANE Environment
|
|
|
|
|
====================
|
|
|
|
|
|
|
|
|
|
SANE is defined as a C-callable library interface. Accessing a raster
|
|
|
|
|
scanner device typically consists of two phases: first, various controls
|
|
|
|
|
of the scanner need to be setup or queried. In the second phase, one or
|
|
|
|
|
more images are acquired.
|
|
|
|
|
|
|
|
|
|
Since the device controls are widely different from device to device,
|
|
|
|
|
SANE provides a generic interface that makes it easy for a frontend to
|
|
|
|
|
give a user access to all controls without having to understand each and
|
|
|
|
|
every device control. The design principle used here is to abstract each
|
|
|
|
|
device control into a SANE *option*. An option is a self-describing
|
|
|
|
|
name/value pair. For example, the brightness control of a camera might
|
|
|
|
|
be represented by an option called ``brightness`` whose
|
|
|
|
|
value is an integer in the range from 0 to 255.
|
|
|
|
|
|
|
|
|
|
With self-describing options, a backend need not be concerned with
|
|
|
|
|
*presentation* issues: the backend simply provides a list of options
|
|
|
|
|
that describe all the controls available in the device. Similarly, there
|
|
|
|
|
are benefits to the frontend: it need not be concerned with the
|
|
|
|
|
*meaning* of each option. It simply provides means to present and alter
|
|
|
|
|
the options defined by the backend.
|
|
|
|
|
|
|
|
|
|
Attaching to a SANE backend
|
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
The process through which a SANE frontend connects to a backend is
|
|
|
|
|
platform dependent. Several possibilities exist:
|
|
|
|
|
|
|
|
|
|
- **Static linking:** A SANE backend may be linked directly into a
|
|
|
|
|
frontend. While the simplest method of attaching to a backend, it is
|
|
|
|
|
somewhat limited in functionality since the available devices is
|
|
|
|
|
limited to the ones for which support has been linked in when the
|
|
|
|
|
frontend was built. But even so static linking can be quite useful,
|
|
|
|
|
particularly when combined with a backend that can access scanners
|
|
|
|
|
via a network. Also, it is possible to support multiple backends
|
|
|
|
|
simultaneously by implementing a meta backend that manages several
|
|
|
|
|
backends that have been compiled in such a manner that they export
|
|
|
|
|
unique function names. For example, a backend called
|
|
|
|
|
``be`` would normally export a function called
|
|
|
|
|
:func:`sane_read()`. If each backend would provide such a
|
|
|
|
|
function, static linking would fail due to multiple conflicting
|
|
|
|
|
definitions of the same symbol. This can be resolved by having
|
|
|
|
|
backend ``be`` include a header file that has lines
|
|
|
|
|
of the form:
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
#define sane_read be_sane_read
|
|
|
|
|
|
|
|
|
|
With definitions of this kind, backend ``be`` will
|
|
|
|
|
export function name ``be_sane_read()``. Thus, all
|
|
|
|
|
backends will export unique names. As long as a meta backend knows
|
|
|
|
|
about these names, it is possible to combine several backends at link
|
|
|
|
|
time and select and use them dynamically at runtime.
|
|
|
|
|
|
|
|
|
|
- **Dynamic linking:** A simpler yet more powerful way to support
|
|
|
|
|
multiple backends is to exploit dynamic linking on platforms that
|
|
|
|
|
support it. In this case, a frontend is linked against a shared
|
|
|
|
|
library that implements any SANE backend. Since each dynamically
|
|
|
|
|
linked backend exports the same set of global symbols (all starting
|
|
|
|
|
with the prefix ``sane_``), the dynamic library that
|
|
|
|
|
gets loaded at runtime does not necessarily have to be the same one
|
|
|
|
|
as one the frontend got linked against. In other words, it is
|
|
|
|
|
possible to switch the backend by installing the appropriate backend
|
|
|
|
|
dynamic library.
|
|
|
|
|
|
|
|
|
|
More importantly, dynamic linking makes it easy to implement a meta
|
|
|
|
|
backend that loads other backends *on demand*. This is a powerful
|
|
|
|
|
mechanism since it allows adding new backends merely by installing a
|
|
|
|
|
shared library and updating a configuration file.
|
|
|
|
|
|
|
|
|
|
- **Network connection:** Arguably the ultimate way to attach to a
|
|
|
|
|
scanner is by using the network to connect to a backend on a remote
|
|
|
|
|
machine. This makes it possible to scan images from any host in the
|
|
|
|
|
universe, as long as there is a network connection to that host and
|
|
|
|
|
provided the user is permitted to access that scanner.
|
|
|
|
|
|
|
|
|
|
.. figure:: figs/hierarchy.*
|
|
|
|
|
:name: fig:hierarchy
|
|
|
|
|
:scale: 100%
|
|
|
|
|
:align: center
|
|
|
|
|
|
2020-02-15 08:26:19 +00:00
|
|
|
|
Example SANE Hierarchy
|
2019-10-29 11:56:06 +00:00
|
|
|
|
|
|
|
|
|
The above discussion lists just a few ways for frontends to attach to a
|
|
|
|
|
backend. It is of course possible to combine these solutions to provide
|
|
|
|
|
an entire hierarchy of SANE backends. Such a hierarchy is depicted in
|
|
|
|
|
:numref:`fig:hierarchy`. The figure shows that machine A
|
|
|
|
|
uses a dynamic-linking based meta backend called ``dll``
|
|
|
|
|
to access the backends called ``pnm``,
|
|
|
|
|
``mustek``, and ``net``. The first two
|
|
|
|
|
are real backends, whereas the last one is a meta backend that provides
|
|
|
|
|
network transparent access to remote scanners. In the figure, machine B
|
|
|
|
|
provides non-local access to its scanners through the SANE frontend
|
|
|
|
|
called ``saned``. The ``saned`` in turn
|
|
|
|
|
has access to the ``hp`` and ``autolum``
|
|
|
|
|
backends through another instance of the ``dll``
|
|
|
|
|
backend. The ``autolum`` meta backend is used to
|
|
|
|
|
automatically adjust the luminance (brightness) of the image data
|
|
|
|
|
acquired by the camera backend called ``qcam``.
|
|
|
|
|
|
|
|
|
|
Note that a meta backend really is both a frontend and a backend at the
|
|
|
|
|
same time. It is a frontend from the viewpoint of the backends that it
|
|
|
|
|
manages and a backend from the viewpoint of the frontends that access
|
|
|
|
|
it. The name “meta backend” was chosen primarily because the SANE
|
|
|
|
|
standard describes the interface from the viewpoint of a (real)
|
|
|
|
|
frontend.
|
|
|
|
|
|
|
|
|
|
.. index:: image data format
|
|
|
|
|
.. _sec:imageformat:
|
|
|
|
|
|
|
|
|
|
Image Data Format
|
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
|
|
Arguably the most important aspect of an image acquisition system is how
|
|
|
|
|
images are represented. The SANE approach is to define a simple yet
|
|
|
|
|
powerful representation that is sufficient for vast majority of
|
|
|
|
|
applications and devices. While the representation is simple, the
|
|
|
|
|
interface has been defined carefully to allow extending it in the future
|
|
|
|
|
without breaking backwards compatibility. Thus, it will be possible to
|
|
|
|
|
accommodate future applications or devices that were not anticipated at
|
|
|
|
|
the time this standard was created.
|
|
|
|
|
|
|
|
|
|
A SANE image is a rectangular area. The rectangular area is subdivided
|
|
|
|
|
into a number of rows and columns. At the intersection of each row and
|
|
|
|
|
column is a quadratic pixel. A pixel consists of one or more sample
|
|
|
|
|
values. Each sample value represents one channel (e.g., the red
|
|
|
|
|
channel). Each sample value has a certain bit depth. The bit depth is
|
|
|
|
|
fixed for the entire image and can be as small as one bit. Valid bit
|
|
|
|
|
depths are 1, 8, or 16 bits per sample. If a device’s natural bit depth
|
|
|
|
|
is something else, it is up to the driver to scale the sample values
|
|
|
|
|
appropriately (e.g., a 4 bit sample could be scaled by a factor of four
|
|
|
|
|
to represent a sample value of depth 8).
|
|
|
|
|
|
|
|
|
|
Image Transmission
|
|
|
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
The SANE API transmits an image as a sequence of frames. Each frame
|
|
|
|
|
covers the same rectangular area as the entire image, but may contain
|
|
|
|
|
only a subset of the channels in the final image. For example, a
|
|
|
|
|
red/green/blue image could either be transmitted as a single frame that
|
|
|
|
|
contains the sample values for all three channels or it could be
|
|
|
|
|
transmitted as a sequence of three frames: the first frame containing
|
|
|
|
|
the red channel, the second the green channel, and the third the blue
|
|
|
|
|
channel.
|
|
|
|
|
|
|
|
|
|
Conceptually, each frame is transmitted a byte at a time. Each byte may
|
|
|
|
|
contain 8 sample values (for an image bit depth of 1), one full sample
|
|
|
|
|
value (for an image bit depth of 8), or a partial sample value (for an
|
|
|
|
|
image bit depth of 16 or bigger). In the latter case, the bytes of each
|
|
|
|
|
sample value are transmitted in the machine’s native byte order.
|
2019-11-30 03:47:48 +00:00
|
|
|
|
For depth 1, the leftmost pixel is stored in the most significant bit,
|
|
|
|
|
and the rightmost pixel in the least significant bit.
|
|
|
|
|
|
2019-10-29 11:56:06 +00:00
|
|
|
|
|
|
|
|
|
**Backend Implementation Note**
|
|
|
|
|
|
|
|
|
|
A network-based meta backend will have to ensure that the byte order
|
|
|
|
|
in image data is adjusted appropriately if necessary. For example,
|
|
|
|
|
when the meta backend attaches to the server proxy, the proxy may
|
|
|
|
|
inform the backend of the server’s byte order. The backend can then
|
|
|
|
|
apply the adjustment if necessary. In essence, this implements a
|
|
|
|
|
“receiver-makes-right” approach.
|
|
|
|
|
|
|
|
|
|
.. figure:: figs/xfer.*
|
|
|
|
|
:name: fig:xfer
|
|
|
|
|
:scale: 50%
|
|
|
|
|
:align: center
|
|
|
|
|
|
|
|
|
|
Transfer order of image data bytes
|
|
|
|
|
|
|
|
|
|
The order in which the sample values in a frame are transmitted is
|
|
|
|
|
illustrated in :numref:`fig:xfer`. As can be seen, the
|
|
|
|
|
values are transmitted row by row and each row is transmitted from
|
|
|
|
|
left-most to right-most column. The left-to-right, top-to-bottom
|
|
|
|
|
transmission order applies when the image is viewed in its normal
|
|
|
|
|
orientation (as it would be displayed on a screen, for example).
|
|
|
|
|
|
|
|
|
|
If a frame contains multiple channels, then the channels are transmitted
|
|
|
|
|
in an interleaved fashion. :numref:`fig:pixels`
|
|
|
|
|
illustrates this for the case where a frame contains a complete
|
|
|
|
|
red/green/blue image with a bit-depth of 8. For a bit depth of 1, each
|
|
|
|
|
byte contains 8 sample values of a *single* channel. In other words, a
|
|
|
|
|
bit depth 1 frame is transmitted in a byte interleaved fashion.
|
|
|
|
|
|
|
|
|
|
.. figure:: figs/image-data.*
|
|
|
|
|
:name: fig:pixels
|
|
|
|
|
:scale: 80%
|
|
|
|
|
:align: center
|
|
|
|
|
|
2020-02-16 03:17:48 +00:00
|
|
|
|
Bit and byte order of image data
|
2019-10-29 11:56:06 +00:00
|
|
|
|
|
|
|
|
|
When transmitting an image frame by frame, the frontend needs to know
|
|
|
|
|
what part of the image a frame represents (and how many frames it should
|
|
|
|
|
expect). For that purpose, the SANE API tags every frame with a type.
|
|
|
|
|
This version of the SANE standard supports the following frame types:
|
|
|
|
|
|
|
|
|
|
:macro:`SANE_FRAME_GRAY`:
|
|
|
|
|
The frame contains a single channel of data that represents
|
|
|
|
|
sample values from a spectral band that covers the human visual
|
|
|
|
|
range. The image consists of this frame only.
|
|
|
|
|
|
|
|
|
|
:macro:`SANE_FRAME_RGB`:
|
|
|
|
|
The frame contains three channels of data that represent sample
|
|
|
|
|
values from the red, green, and blue spectral bands. The sample
|
|
|
|
|
values are interleaved in the order red, green, and blue. The
|
|
|
|
|
image consists of this frame only.
|
|
|
|
|
|
|
|
|
|
:macro:`SANE_FRAME_RED`:
|
|
|
|
|
The frame contains one channel of data that represents sample
|
|
|
|
|
values from the red spectral band. The complete image consists
|
|
|
|
|
of three frames: :macro:`SANE_FRAME_RED`,
|
|
|
|
|
:macro:`SANE_FRAME_GREEN`, and
|
|
|
|
|
:macro:`SANE_FRAME_BLUE`. The order in which the
|
|
|
|
|
frames are transmitted chosen by the backend.
|
|
|
|
|
|
|
|
|
|
:macro:`SANE_FRAME_GREEN`:
|
|
|
|
|
The frame contains one channel of data that represents sample
|
|
|
|
|
values from the green spectral band. The complete image consists
|
|
|
|
|
of three frames: :macro:`SANE_FRAME_RED`,
|
|
|
|
|
:macro:`SANE_FRAME_GREEN`, and
|
|
|
|
|
:macro:`SANE_FRAME_BLUE`. The order in which the
|
|
|
|
|
frames are transmitted chosen by the backend.
|
|
|
|
|
|
|
|
|
|
:macro:`SANE_FRAME_BLUE`:
|
|
|
|
|
The frame contains one channel of data that represents sample
|
|
|
|
|
values from the blue spectral band. The complete image consists
|
|
|
|
|
of three frames: :macro:`SANE_FRAME_RED`,
|
|
|
|
|
:macro:`SANE_FRAME_GREEN`, and
|
|
|
|
|
:macro:`SANE_FRAME_BLUE`. The order in which the
|
|
|
|
|
frames are transmitted chosen by the backend.
|
2019-11-30 02:55:01 +00:00
|
|
|
|
|
|
|
|
|
In frames of type :macro:`SANE_FRAME_GRAY`, when the bit depth is 1 there are
|
|
|
|
|
only two sample values possible, 1 represents minimum intensity
|
|
|
|
|
(black) and 0 represents maximum intensity (white). For all other bit
|
|
|
|
|
depth and frame type combinations, a sample value of 0 represents
|
|
|
|
|
minimum intensity and larger values represent increasing intensity.
|
2019-11-30 03:47:48 +00:00
|
|
|
|
|
2020-07-12 08:30:05 +00:00
|
|
|
|
The combination of bit depth 1 and :macro:`SANE_FRAME_RGB` (or
|
2019-11-30 03:47:48 +00:00
|
|
|
|
:macro:`SANE_FRAME_RED`, :macro:`SANE_FRAME_GREEN`, :macro:`SANE_FRAME_BLUE`)
|
|
|
|
|
is rarely used and may not be supported by every frontend.
|