This chapter describes the interface between a scanner driver and an application program.
The following major topics are discussed in this chapter:
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.
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. |
This section describes the generic scanner interface data structures.
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.
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:
| |||||||||||
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:
| |||||||||||
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). |
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.
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. |
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.
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().
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. |
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.
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.
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.
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.
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.
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().
int SCEndScanEnt(FILE *fp) |
This function frees the resources used to enumerate scanners. It returns 0 on success, -1 if there is an error.
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.
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.
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.
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.
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.
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.
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.
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.
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().
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.
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(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.
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.
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.
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.
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().
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.
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.
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.
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.
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.
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. |
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.
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.
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.
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().
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.
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. |
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.
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.