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:

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 SCGetScanEnt().

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.