Chapter 8. Generic Scanner Interface
Prev |  | Next

## Chapter 8. Generic Scanner Interface

This chapter describes the interface between a scanner driver and an application program.

The following major topics are discussed in this chapter:

- “Coordinate System for Scanning”

- “Data Structures”

- “Data Type Conventions”

- “Functions”

## Overview

The generic interface between a scanner driver and an application program is flexible enough to accommodate a wide range of scanners and application programs. Application programs that use this interface can use any scanner that has a driver that supports this interface. Providing a driver for a particular scanner allows it to be accessed by any program written to use this interface.

The interface is implemented by a run-time library and a driver program. All drivers must provide the entry points necessary for the run-time library to provide the interface described in this document. In order to provide access to scanner-specific capabilities, scanner drivers are free to expand the interface, which is then accessed by scanner-specific programs that have standard ways of being invoked by application programs. (See Chapter 7, “Scanner-Specific Options.”)

For more details on the functions described in this chapter, see the online reference pages.

## Coordinate System for Scanning

When describing an area to be scanned, a coordinate system with the origin (0,0) in the upper left corner of the scannable area is used. The x-coordinate increases from left to right, and the y-coordinate increases from top to bottom.

Note that this is the upper left corner of the document being scanned; in the case of a flatbed scanner where the document is placed face down in the bed, this is the upper right corner or lower left corner of the bed.

When functions in the interface specify measurements along the horizontal and vertical axes of the scan area, the following units can be used to specify distance:

SC_INCHES | Specify measurements in inches.
SC_CENTIM | Specify measurements in centimeters.
SC_PIXELS | Specify measurements in pixels.

## Data Structures

This section describes the generic scanner interface data structures.

### SCANNER Data Structure

    typedef struct tag_scanner {
          ...
    } SCANNER;

The application maintains a pointer to a SCANNER data structure (obtained from `SCOpen()`) to specify the scanner to which operations should be applied.

### SCDATATYPE Data Structure

Scanners support a variety of output data types. The SCDATATYPE structure encapsulates the common output data types produced by scanners.

    typedef struct tag_scdatatype {
       unsigned int packing : 4;
       unsigned int channels : 4;
       unsigned int type : 8;
       unsigned int bpp : 8;
    } SCDATATYPE;

The structure has these four fields:

packing |  | The packing field can take on the following values:
SC_PACKPIX | All the data for each pixel is stored together; for example, a line of 24-bit color is stored as RGBRGBRGB.
SC_PACKBAND | Each line of data is decomposed into its channels; for example, a line of 24-bit color is stored as RRRGGGBBB.
SC_PACKPLANE | All the data for a channel is stored separately from other channels. A page of color data is split into three pages of data; one for red, one for blue, and one for green.
channel |  | Number of components per pixel. Legal values are 1, 3, and 4. See type below.
type |  | Type of data. This parameter indicates how the data in the various channels is to be interpreted:
SC_MONO | Monochrome: 1 channel and 1 bit per pixel.
SC_GREY | Gray-scale: 1 channel.
SC_RGB | Red, green, and blue: 3 channels.
SC_CMY | Cyan, magenta, and yellow: 3 channels.
SC_CMYK | Cyan, magenta, yellow, and black: 4 channels.
bpp |  | Bits Per Pixel (per channel). The number of bits per pixel in each channel. For monochrome data, there is 1 bit per pixel. For 24-bit RGB color, there are 8 bits per pixel (x 3 channels = 24 bits).

## Data Type Conventions

Generic scanner applications need not be written to support any particular data type. There are four basic data types that are typically used:

- Monochrome. All scanner drivers must support this monochrome format:

  - packing = SC_PACKPIX

  - channels = 1

  - type = SC_MONO

  - bpp = 1

- Eight-bit gray-scale. All scanner drivers that support any type of gray-scale or color output must support the following 8-bit gray-scale format:

  - packing = SC_PACKPIX

  - channels=1

  - type = SC_GREY

  - bpp = 8

- Planar 24-bit RGB color. The red, green, and blue channels are scanned in three separate passes; in this case, the data type format is

  - packing = SC_PACKPLANE

  - channels = 3

  - type = SC_RGB

  - bpp = 8

- Packed 24-bit RGB color. This applies to a one-pass color scanner that gets all of the data in one pass. The data type for color data from this kind of scanner is

  - packing = SC_PACKPIX

  - channels = 3

  - type = SC_RGB

  - bpp = 8

A scanning application that is prepared to deal with these four data types should be able to interact well with any well-behaved scanner driver.

## Functions

### Diagnostic Functions

Many of the functions specified here return 0 upon success and -1 in the event of a failure. If a function's return value indicates failure, the reason for the failure can be determined by examining the value of the global variable SCerrno. SCerrno will be between 0 and LASTERRNO (defined in `/usr/include/sys/errno.h`) if the failure was due to a failed system call, and between SCEBASE and SCELAST (defined in `scanner.h`) if the failure was for some other reason. #define entries for the values between SCEBASE and SCELAST can be found in `/usr/include/scanner.h`.

Table 8-1 lists the diagnostic functions.

Table 8-1. Diagnostic Functions

Function | Description
--- | ---
SCPerror() | Prints an error string.
SCErrorString() | Returns a character string containing an error message.

#### SCPerror() Function

    void SCPerror(char *ident)

This function prints the value of ident, a colon, and a string of text corresponding to the current value of SCerrno.

#### SCErrorString() Function

    char *SCErrorString(int err)

This function returns a character string containing a useful message describing the error condition represented by err. If err is not in the range 0 to LASTERRNO or SCEBASE to SCELAST, `SCErrorString()` returns a text string containing the words “Error code err,” where err is the value passed to `SCErrorString()`.

### Application/Driver Rendezvous Functions

Users refer to scanners by names given to them at install time. The installer uses `scanners(1M)`, which adds entries to a mapping from scanner names to (driver, device, options) tuples. The mapping is contained in the file `/var/scan/scanners`. The driver and device components are used to start the right driver on the device to access the scanner given by name, and options is the scanner-specific options program. `scanners` allows the specification of a default scanner.

The application/driver Rendezvous functions are listed in Table 8-2 and described below.

Table 8-2. Application/Driver Rendezvous Functions

Function | Description
--- | ---
SCOpen() | Prepares to perform operations on the scanner named by name.
SCOpenScreen() | Calls the screen scanner driver to scan from the specified screen.
SCOpenFile() | Calls the file scanner driver to scan from the specified file.
SCClose() | Breaks the connection between the application and the driver.
SCSetScanEnt() | Opens the scanner configuration file and returns a pointer.
SCGetScanEnt() | Gets a SCANENT structure for each installed scanner.
SCEndScanEnt() | Frees the resources used to enumerate scanners.
SCScannerName() | Returns the name associated with the scanner at installation.
SCScannerEnt() | Returns the SCANENT structure of an open scanner.
SCDefaultScannerName() | Gets the default scanner name, if any.

#### SCOpen() Function

    SCANNER *SCOpen(char *name)

The `SCOpen()` function prepares to perform operations on the scanner named by name by starting the appropriate driver on the appropriate device. `SCOpen()` performs the lookup in the name -> (driver, device, options) mapping. If name is NULL, the default scanner is used.

`SCOpen()` returns a pointer to a SCANNER struct if successful, or NULL if there is an error. If name is NULL and no default scanner has been set, `SCOpen()` opens the first scanner found in `/usr/lib/scan/scanners`.

#### SCOpenScreen() Function

    SCANNER *SCOpenScreen(char *screen)

This function invokes the screen scanner driver to scan from the specified screen. It returns a pointer to a SCANNER struct if successful, NULL if there is an error.

#### SCOpenFile() Function

    SCANNER *SCOpenFile(char *file)

This function invokes the file scanner driver to scan from the specified file. It returns a pointer to a SCANNER struct if successful, NULL if there is an error.

#### SCClose() Function

    int SCClose(SCANNER *s)

This function breaks the connection between the application and the driver program. It returns 0 on success, -1 if there is an error.

#### SCSetScanEnt() Function

    FILE *SCSetScanEnt(void)

This function opens the scanner configuration file. It returns a pointer to the open FILE structure on success, NULL if there is an error.

#### SCGetScanEnt() Function

    typedef struct tag_scanent {
       char *name;
       char *driver;
       char *device;
       char *options;
    } SCANENT;

    SCANENT *SCGetScanEnt(FILE *fp)

To get a SCANENT structure for each scanner installed on the system, this function should be called repeatedly until it returns NULL. The contents of the memory pointed to by the return value of `SCGetScanEnt()` are undefined after any subsequent calls to this function, so copy the return value if you need to preserve it across calls to `SCGetScanEn` t().

#### SCEndScanEnt() Function

    int SCEndScanEnt(FILE *fp)

This function frees the resources used to enumerate scanners. It returns 0 on success, -1 if there is an error.

#### SCScannerName() Function

    char *SCScannerName(SCANNER *s)

This function returns the name associated with the scanner at installation. Applications can use this to get at the name of the default scanner being used if `SCOpen()` was called with NULL. It returns a pointer to a character string on success, NULL if there is an error. The memory pointed to by the return value of `SCScannerName()` belongs to `libscan` and should not be modified or freed.

#### SCScannerEnt() Function

    SCANENT *SCScannerEnt(SCANNER *s)

This function returns a SCANENT structure describing an open scanner. The memory pointed to by the returned value of `SCScannerEnt()` belongs to `libscan` and should not be modified or freed.

#### SCDefaultScannerName() Function

    char *SCDefaultScannerName(void)

This function gets the default scanner name, if any. It returns the name of the default scanner, or NULL if no default scanner has been set. The memory pointed to by the returned value of `SCDefaultScannerName()` belongs to `libscan` and should not be modified or freed.

### Scanning Resolution Functions

Scanners typically support a range of resolutions (pixels per inch). Scanner drivers should support any resolution between the minimum and maximum resolutions supported by the scanner, decimating or replicating pixels as necessary to support the requested resolution. This gives the application the opportunity to preview the scanning area in an arbitrarily sized window.

It is not the scanner driver's responsibility to perform higher-quality scaling of the image data. `SCGetScannerRes()` can be used by the scanner application to determine which resolutions are supported directly by the scanner without decimation or replication by the driver.

#### SCGetScannerRes() Function

    int SCGetScannerRes(SCANNER *s, int metric,
        float **xres, float **yres, int *nres)

This function returns arrays of hardware-supported resolutions. The xres and yres arrays specify supported horizontal and vertical resolutions. metric should be one of SC_INCHES or SC_CENTIM. nres sets the number of resolution pairs in the xres and yres arrays. `SCGetScannerRes()` returns 0 if successful, -1 if there is an error.

#### SCGetMinMaxRes() Function

    int SCGetMinMaxRes(SCANNER *s, int metric,
        float *minx, float *miny, float *maxx, float *maxy);

This function determines the resolution bounds; that is, the minimum and maximum horizontal and vertical resolutions that the scanner supports. It is an error to call `SCGetMinMaxRes()` with metric equal to SC_PIXELS. `SCGetMinMaxRes()` returns 0 if successful, -1 if there is an error.

### Scanning Area Functions

A scan may be limited by the application to a subset of the scannable area supported by the scanner. `SCGetPageSize()` is provided so that applications can determine the size of the scannable area supported by the scanner.

#### SCGetPageSize() Function

    int SCGetPageSize(SCANNER *s, int metric, float *x, float *y,
                      float *width, float *height)

This function gets the entire scannable area. It is an error to call it with metric equal to SC_PIXELS. `SCGetPageSize()` returns 0 if successful, -1 if there is an error.

#### SCGetDataTypes() Function

    int SCGetDataTypes(SCANNER *s, SCDATATYPE **dt, int *ntypes)

This function sets *dt to point to an array of the data types supported by the scanner driver. ntypes gets the number of data types supported. The memory pointed to by *dt belongs to `libscan` and should not be modified or freed. It should also not be expected to retain its values after subsequent calls to `SCGetDataTypes()`.

### Scanning Functions

After `SCOpen()` has been called, the scanner is idle. In order to initiate a scan, the functions `SCSetup()` and `SCScan()` are called. Characteristics of the data to be scanned can be determined with `SCGetScanSize()`. A scan in progress can be aborted at any time with the function `SCAbort()`. The scanner status can be determined by calling the function `SCGetStatus()`.

Table 8-3 lists the available scanning functions.

Table 8-3. Scanning Functions

Function | Description
--- | ---
SCSetup() | Prepares the scanner for a scan.
SCGetScanSize() | Determines the width, height, and number of bytes per scan line.
SCScan() | Starts scanning.
SCGetScanLine() | Retrieves scan line data.
SCDataReady() | Determines whether any data is available.
SCGetFD() | Returns the file descriptor for scan data.
SCScanFD() | Starts scanning (alternative call).
SCAbort() | Aborts the current scan.
SCGetStatus() | Gets the status of the scanner.
SCGetStatusFD() | Returns a file descriptor for scan status.

#### SCSetup() Function

    SCSetup(SCANNER *s, int preview, SCDATATYPE *type,
          int rmetric, float xres, float yres,
          int wmetric, float x, float y, float width,
          float height)

This function is used to prepare the scanner for a scan. The type of data, the resolution, and the scanning area are specified. preview is nonzero if this is a “preview” scan; that is, when the driver is faced with a trade-off between speed and image quality, it should choose speed, because this is not the “real” scan. After calling `SCSetup()`, `SCScan()` is called to initiate scanning. `SCSetup()` returns 0 if successful, -1 if there is an error.

#### SCGetScanSize() Function

    int SCGetScanSize(SCANNER *s, int *width, int *height,
                      int *bytesPerLine)

This function is called after `SCSetup()` to determine the width, height, and number of bytes per scan line that will be returned by the driver. It returns 0 if successful, -1 if there is an error.

#### SCScan() Function

    int SCScan(SCANNER *s)

This function tells the driver to start scanning. The driver immediately starts to scan and buffer the data. `SCScan()` does not fetch any scan data (see `SCGetScanLine()`). `SCScan()` returns 0 if successful, -1 if there is an error.

#### SCGetScanLine() Function

    int SCGetScanLine(SCANNER *s, void *buf, int bytes)

This function retrieves scan line data. bytes should be set to the number of bytes in a scan line as determined by `SCGetScanSize()`.

Note that for color planar data, `SCGetScanLine()` is called once for each line in each plane of data. For 100 lines of 24-bit RGB planar data, `SCGetScanLine()` is called a total of 300 times, with the first 100 calls retrieving the red plane, the second 100 calls retrieving the green plane, and the third 100 calls retrieving the blue plane.

#### SCDataReady() Function

    int SCDataReady(SCANNER *s)

This function is used to determine whether any data is available for calls to `SCGetScanLine()`; that is, whether a call to `SCGetScanLine()` will block waiting for data to become available.

`SCDataReady()` returns 1 if data is available (`SCGetScanLine()` will not block), 0 if no data is available (`SCGetScanLine()` will block), or -1 if there is an error. It is an error to call `SCDataReady()` if scanning was started by a call to `SCScanFD()`.

#### SCGetFD() Function

    int SCGetFD(SCANNER *s)

This function returns the file descriptor over which scan data from the scanner driver comes. Checking the state of this descriptor with the `select(2)` system call is equivalent to calling `SCDataReady()`. If `SCScanFD()` was called, `SCGetFD()` returns the file descriptor that was passed to that function. `SCGetFD()` returns -1 if there is an error.

#### SCScanFD() Function

    int SCScanFD(SCANNER *s, int fd)

This function is an alternative to calling `SCScan()` to start scanning and `SCGetLine()` to fetch the data. After `SCScanFD()` is called, the driver writes the scanned data to `fd`; this is useful if the output data format of the scanner interface matches the input data type of another interface. `SCScanFD()` returns 0 if successful, -1 if there is an error.

#### SCAbort() Function

    int SCAbort(SCANNER *s)

This function aborts the current scan. Data buffered by the driver is discarded. `SCAbort()` returns 0 if successful, -1 if there is an error.

#### SCGetStatus() Function

    enum scstate { SC_READY, SC_SCANNING, SC_ERROR };
    typdef struct tag_scstatus {
        enum scstate state;      /* ready, scanning, error */
        int errno;               /* only valid if state == SC_ERROR */
        long curline;            /* current line being scanned */
        int pass;                /* current scanning pass */
    } SCSTATUS;

    int SCGetStatus(SCANNER *s, SCSTATUS *st)

This function gets the status of the scanner. It returns 0 if successful, -1 if there is an error.

#### SCGetStatusFD() Function

    int SCGetStatusFD(SCANNER *s)

This function returns a file descriptor that can be passed to the `select(2)` system call. When `select` indicates that the file descriptor is ready for reading, the scanner driver has updated the scanning status. Retrieve the status by calling `SCGetStatus()`; do NOT pass the file descriptor returned from `SCGetStatusFD()` to any other system call.

`SCGetStatusFD()` provides a mechanism whereby it is not necessary for an application to periodically call `SCGetStatus()` in a timer loop to detect changes in scanner status. `SCGetStatusFD()` returns -1 if there is an error.

### Document Feeder Functions

The scanner interface has provisions for the support of scanners that have document feeders attached. This facilitates the development of applications that can scan multiple pages without user intervention. Table 8-4 lists the document feeder functions.

Table 8-4. Document Feeder Functions

Function | Description
--- | ---
SCFeederGetFlags() | Gets the feeder flags.
SCFeederSetFlags() | Sets feeder flags.
SCFeederAdvance() | Advances the feeder to the next document.
SCFeederReady() | Checks if the feeder is ready for feeding.

#### SCFeederGetFlags() Function

    typedef unsigned int SCFEEDERFLAGS;

    #define SC_HASFEEDER 1
    #define SC_AUTOFEED  2
    #define SC_PROGFEED  4

    int SCFeederGetFlags(SCANNER *s, SCFEEDERFLAGS *flags);

This function fills in the flags variable with flags appropriate for the scanner associated with s. If SC_AUTOFEED and SC_PROGFEED are both set, `SCFeederSetFlags()` should be called before any calls to `SCScan()` to establish how the application is to interact with the feeder. The meanings of the flags are as follows:

SC_HASFEEDER | Set if there is a document feeder attached to the scanner.
SC_AUTOFEED | Set if the feeder can operate such that each call to SCScan() causes the next document to be loaded.
SC_PROGFEED | Set if the feeder can operate so that SCScan() can be called multiple times per document. It is necessary to call SCFeederAdvance() to load the next document.

`SCFeederGetFlags()` returns 0 if successful, -1 if there is an error.

#### SCFeederSetFlags() Function

    int SCFeederSetFlags(SCANNER *s, SCFEEDERFLAGS flags);

This function should be called before calling `SCScan()` for scanners in which `SCFeederGetFlags()` sets both SC_AUTOFEED and SC_PROGFEED. After calling `SCFeederSetFlags`(s, SC_AUTOFEED), the feeder advances to the next document after every call to `SCScan()`. After calling `SCFeederSetFlags`(s, SC_PROGFEED), a call to `SCFeederAdvance()` is necessary to advance to the next document. `SCFeederSetFlags()` returns 0 if successful, -1 if there is an error.

#### SCFeederAdvance() Function

    int SCFeederAdvance(SCANNER *s)

This function advances the feeder to the next document. This call is valid only if the scanner supports the SC_PROGFEED mode. For scanners that support both the SC_AUTOFEED and SC_PROGFEED modes, `SCFeederSetFlags`(s, SC_PROGFEED) must have been called previously.

`SCFeederAdvance()` returns 0 if successful, -1 if there is an error. When unloading the last document, this function returns -1 with SCerrno set to SCFEEDEREMPTY.

#### SCFeederReady() Function

    int SCFeederReady(SCANNER *s)

This function checks if the feeder is ready for feeding. `SCFeederReady()` returns 0 if the feeder is ready, -1 if not. If the feeder is empty, SCerrno is set to SCFEEDEREMPTY; if any other error conditions exist, SCerrno is set appropriately.

Note that this function needs to be called before `SCFeederAdvance()` to determine whether a document is ready to be scanned after the call to `SCFeederAdvance()`.

## Events

Scanner applications need to be aware that the configuration information about a scanner obtained from `SCGetMinMaxRes()`, `SCGetScannerRes()`, `SCGetPageSize()`, and `SCGetDataTypes()` can change. This typically happens when the user selects a new input medium using the scanner specific options panel. For example, some scanners support transparency options that have a different scanning page size than the normal scanning bed. When the user decides to scan transparencies, the driver notifies the application that it needs to call `SCGetPageSize()` by sending an event. See Table 8-5.

Table 8-5. Event Functions

Function | Description
--- | ---
SCGetEvent() | Receives an event from the scanner driver.
SCEventPending() | Tests whether an event is currently pending.
SCGetEventFD() | Obtains an event file descriptor for passing to `select`.

### SCGetEvent() Function

    typedef struct tag_infoChange {
        unsigned int pageSizeChanged : 1;
        unsigned int resolutionChanged : 1;
        unsigned int dataTypesChanged : 1;
        unsigned int feederFlagsChanged : 1;
    } SCINFOCHANGE;

    #define SCEVENT_INFOCHANGE 1

    typedef struct tag_scevent {
        unsigned int eventType;
        union {
            SCINFOCHANGE infoChange;
        } event;
    } SCEVENT;

    int SCGetEvent(SCANNER *s, SCEVENT *event)

`SCGetEvent()` is called to receive an event from the scanner driver. The event structure should be examined, and if the pageSizeChanged field is set, the application should call `SCGetPageSize()` to query the new page size; if the resolutionChanged field is set, the application should call `SCGetMinMaxRes()` and `SCGetScannerRes()` to query the new resolutions; if the dataTypesChanged field is set, the application should call `SCGetDataTypes()` to query the new data types, and if the feederFlagsChanged field is set, the application should call `SCGetFeederFlags()` to query the new feeder flags.

### SCEventPending() Function

    int SCEventPending(SCANNER *s)

`SCEventPending()` is called to test whether or not an event is currently pending. If an event is pending, the application should call `SCGetEvent()` to receive it. `SCEventPending()` returns 1 if any events are pending, and 0 if no events are pending.

### SCGetEventFD() Function

    int SCGetEventFD(SCANNER *s)

`SCGetEventFD()` returns a file descriptor that can be passed to the `select` system call. When `select` indicates that this file descriptor is ready for reading, then an event is pending and the application should call `SCGetEvent()` to retrieve it.

Prev | Table of Contents | Next
Chapter 7. Scanner-Specific Options |  | Chapter 9. Testing for Impressario Compatibility