home *** CD-ROM | disk | FTP | other *** search
- Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
- Distributed by Free Software Foundation, Inc.
-
- This file is part of Ghostscript.
-
- Ghostscript is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- to anyone for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing. Refer
- to the Ghostscript General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- Ghostscript, but only under the conditions described in the Ghostscript
- General Public License. A copy of this license is supposed to have been
- given to you along with Ghostscript so you can know your rights and
- responsibilities. It should be in a file named COPYING. Among other
- things, the copyright notice and this notice must be preserved on all
- copies.
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- This file, drivers.doc, describes the interface between Ghostscript and
- device drivers.
-
- For an overview of Ghostscript and a list of the documentation files, see
- README.
-
- ********
- ******** Adding a driver ********
- ********
-
- To add a driver to Ghostscript, all you need to do is edit gdevs.mak in
- two places. The first is the list of devices, in the section headed
- # -------------------------------- Catalog ------------------------------- #
- Pick a name for your device, say smurf, and add smurf to the list.
- (Device names must be 1 to 8 characters, consisting of only letters,
- digits, and underscores, of which the first character must be a letter.
- Case is significant: all current device names are lower case.)
- The second is the section headed
- # ---------------------------- Device drivers ---------------------------- #
- Suppose the files containing the smurf driver are called joe and fred.
- Then you should add the following lines:
-
- # ------ The SMURF device ------ #
-
- smurf_=joe.$(OBJ) fred.$(OBJ)
- smurf.dev: $(smurf_)
- gssetdev smurf.dev $(smurf_)
-
- joe.$(OBJ): joe.c ...and whatever it depends on
-
- fred.$(OBJ): fred.c ...and whatever it depends on
-
- If joe uses platform-specific, non-ANSI-compatible features (like inline
- assembly code), then the line should read
-
- joe.$(OBJ): joe.c ...and whatever it depends on
- $(CCNA) $*
-
- ********
- ******** Driver structure ********
- ********
-
- A device is represented by a structure divided into three parts:
-
- - procedures that are shared by all instances of each device;
-
- - parameters that are present in all devices but may be different
- for each device or instance; and
-
- - device-specific parameters that may be different for each instance.
-
- Normally, the procedure structure is defined and initialized at compile
- time. A prototype of the parameter structure (including both generic and
- device-specific parameters) is defined and initialized at compile time,
- but is copied and filled in when an instance of the device is created.
-
- The gx_device_common macro defines the common structure elements, with the
- intent that devices define and export a structure along the following
- lines:
-
- typedef struct smurf_device_s {
- gx_device_common;
- ... device-specific parameters ...
- } smurf_device;
- smurf_device gs_smurf_device = {
- sizeof(smurf_device), * params_size
- { ... procedures ... }, * procs
- ... generic parameter values ...
- ... device-specific parameter values ...
- };
-
- The device structure instance *must* have the name gs_smurf_device, where
- smurf is the device name used in gdevs.mak.
-
- All the device procedures are called with the device as the first
- argument. Since each device type is actually a different structure type,
- the device procedures must be declared as taking a gx_device * as their
- first argument, and must cast it to smurf_device * internally. For
- example, in the code for the "memory" device, the first argument to all
- routines is called dev, but the routines actually use md to reference
- elements of the full structure, by virtue of the definition
-
- #define md ((gx_device_memory *)dev)
-
- (This is a cheap version of "object-oriented" programming: in C++, for
- example, the cast would be unnecessary, and in fact the procedure table
- would be constructed by the compiler.)
-
- Structure definition
- --------------------
-
- This essentially duplicates the structure definition in gxdevice.h.
-
- typedef struct gx_device_s {
- int params_size; /* size of this structure */
- gx_device_procs *procs; /* pointer to procedure structure */
- char *name; /* the device name */
- int width; /* width in pixels */
- int height; /* height in pixels */
- float x_pixels_per_inch; /* x density */
- float y_pixels_per_inch; /* y density */
- gs_rect margin_inches; /* margins around imageable area, */\
- /* in inches */\
- int has_color; /* true if device supports color */
- unsigned short max_rgb_value; /* max r, g, b value */
- int bits_per_color_pixel; /* for copy_color */
- int is_open; /* true if device has been opened */
- } gx_device;
-
- The name in the structure should be the same as the name in gdevs.mak.
-
- gx_device_common is a macro consisting of just the element definitions.
-
- If for any reason you need to change the definition of the basic device
- structure, or add procedures, you must change the following places:
-
- - This document and history.doc (if you want to keep the
- documentation up to date).
- - The definition of gx_device_common and/or the procedures
- in gxdevice.h.
- - The null device in gsdevice.c.
- - The tracing "device" in gstdev.c.
- - The "memory" devices in gdevmem.c.
- - The command list "device" in gxclist.c.
- - All the real devices in the standard Ghostscript distribution,
- as listed in gdevs.mak.
- - Any other drivers you have that aren't part of the standard
- Ghostscript distribution.
-
- You may also have to change the code for zmakedevice (in zdevice.c) and
- gs_makedevice (in gsdevice.c).
-
- ********
- ******** Types and coordinates ********
- ********
-
- Coordinate system
- -----------------
-
- Since each driver specifies the initial transformation from user to device
- coordinates, the driver can use any coordinate system it wants, as long as
- a device coordinate will fit in an int. (This is only an issue on MS-DOS
- systems, where ints are only 16 bits. User coordinates are represented as
- floats.) Typically the coordinate system will have (0,0) in the upper
- left corner, with X increasing to the right and Y increasing toward the
- bottom. This happens to be the coordinate system that all the currently
- supported devices use. However, there is supposed to be nothing in the
- rest of Ghostscript that assumes this.
-
- Drivers must check the coordinate parameters given to them: they should
- not assume the coordinates will be in bounds.
-
- Types
- -----
-
- Here is a brief explanation of the various types that appear as parameters
- or results of the drivers.
-
- gx_device (defined in gxdevice.h)
-
- This is the device structure, as explained above.
-
- gs_matrix (defined in gsmatrix.h)
-
- This is a 2-D homogenous coordinate transformation matrix, used by
- many Ghostscript operators.
-
- gs_rect (defined in gs.h)
-
- This defines a rectangle by giving the coordinates of its minimal
- and maximal corners. It is only used (perhaps misused) to define the
- margins of the imageable area.
-
- gx_color_index (defined in gxdevice.h)
-
- This is meant to be whatever the driver uses to represent a device
- color. For example, it might be an index in a color map. Ghostscript
- doesn't ever do any computations with these values: it gets them from
- map_rgb_color and hands them back as arguments to several other
- procedures. The special value gx_no_color_index (defined as
- (gx_color_index)(-1)) means "transparent" for some of the procedures. The
- type definition is simply:
-
- typedef unsigned long gx_color_index;
-
- gx_bitmap (defined in gxbitmap.h)
-
- This structure type represents a bitmap to be used as a tile for
- filling a region (rectangle or trapezoid). Here is a copy of the relevant
- part of the file:
- /*
- * Structure for describing stored bitmaps.
- * Bitmaps are stored bit-big-endian (i.e., the 2^7 bit of the first
- * byte corresponds to x=0), as a sequence of bytes (i.e., you can't
- * do word-oriented operations on them if you're on a little-endian
- * platform like the Intel 80x86 or VAX). Each scan line is normally
- * padded only to a byte boundary, although this should be of no
- * concern since the raster and width are specified separately.
- * The first scan line corresponds to y=0 in whatever coordinate
- * system is relevant.
- */
- struct gx_bitmap_s {
- byte *data;
- int raster; /* bytes per scan line */
- int width, height;
- };
-
- ********
- ******** Driver procedures ********
- ********
-
- All the procedures that return int results return 0 on success, or -1 on
- invalid arguments.
-
- Most procedures are optional. If a device doesn't supply an optional
- procedure proc, the entry in the procedure structure should be
- gx_default_proc, e.g. gx_default_tile_rectangle. The device procedure can
- also call this procedure if it doesn't implement the function for
- particular values of the arguments; alternatively, it can return -1, since
- all callers of optional procedures will call the default procedure in this
- case.
-
- Open/close/sync
- ---------------
-
- int (*open_device)(P1(struct gx_device_s *)) [OPTIONAL]
-
- Open the device: do any initialization associated with making the
- device instance valid. This must be done before any output to the device.
-
- void (*get_matrix_and_clip)(P3(struct gx_device_s *, gs_matrix *)) [OPTIONAL]
-
- Construct the initial transformation matrix mapping user
- coordinates (nominally 1/72" per unit) to device coordinates. The default
- procedure computes this from width, height, and x/y_pixels_per_inch on the
- assumption that the origin is in the upper left corner, i.e.
- xx = x_pixels_per_inch/72, xy = 0,
- yx = 0, yy = -y_pixels_per_inch/72,
- tx = 0, ty = height.
-
- int (*sync_output)(P1(struct gx_device_s *)) [OPTIONAL]
-
- Synchronize the device. If any output to the device has been
- buffered, send / write it now. Note that this may be called several times
- in the process of constructing a page, so printer drivers should NOT
- implement this by printing the page.
-
- int (*output_page)(P1(struct gx_device_s *)) [OPTIONAL]
-
- Output a fully composed page to the device. The default
- definition just calls sync_output. Printer drivers should implement this
- by printing and ejecting the page.
-
- int (*close_device)(P1(struct gx_device_s *)) [OPTIONAL]
-
- Close the device: release any associated resources. After this,
- output to the device is no longer allowed.
-
- Color mapping
- -------------
-
- Ghostscript represents colors internally as RGB values. In communicating
- with devices, however, it assumes that each device has a fixed palette of
- colors identified by integers (to be precise, elements of type
- gx_color_index), with the following properties:
-
- - The palette contains at least white and black.
-
- - If the device has gray-scale but not color capabilities, and
- max_rgb_value is less than 255, the palette consists of an arbitrary
- number of gray shades, uniformly spaced on the diagonal of the RGB color
- cube.
-
- - If the device has color capabilities, and max_rgb_value is less
- than 255, the palette consists of a color cube uniformly spaced in RGB
- space (obviously including at least the three primary colors (red, green,
- blue)).
-
- These are very strong conditions: they are required by the algorithm that
- Ghostscript uses to create spatial halftones to approximate unavailable
- colors or gray levels. In the future, we envision giving drivers much
- more control over color selection, and these conditions will disappear.
-
- gx_color_index (*map_rgb_color)(P4(struct gx_device_s *, unsigned short red,
- unsigned short green, unsigned short blue)) [OPTIONAL]
-
- Map a RGB color to a device color. The default algorithm simply
- returns the brightness, i.e. max(red, green, blue). The range of legal
- values of the RGB arguments is given by the max_rgb_value element of the
- device parameter structure. Ghostscript assumes that for devices that
- have color capability (i.e., has_color is true), map_rgb_color returns a
- color index for a gray level (as opposed to a non-gray color) iff red =
- green = blue.
-
- int (*map_color_rgb)(P3(struct gx_device_s *, gx_color_index color,
- unsigned short rgb[3])) [OPTIONAL]
-
- Map a device color code to RGB values. The default algorithm
- simply sets all three elements of the result to the color.
-
- Drawing
- -------
-
- All drawing operations use device coordinates and device color values.
-
- int (*fill_rectangle)(P6(struct gx_device_s *, int x, int y,
- int width, int height, gx_color_index color))
-
- Fill a rectangle with a color. The set of pixels filled is
- {(px,py) | x <= px < x + width and y <= py < y + height}. In other words,
- the point (x,y) is included in the rectangle, as are (x+w-1,y), (x,y+h-1),
- and (x+w-1,y+h-1), but *not* (x+w,y), (x,y+h), or (x+w,y+h). If width <=
- 0 or height <= 0, fill_rectangle should return 0 without drawing anything.
-
- int (*draw_line)(P6(struct gx_device_s *, int x0, int y0, int x1, int y1,
- gx_color_index color)) [OPTIONAL]
-
- Draw a minimum-thickness line from (x0,y0) to (x1,y1). The
- precise set of points to be filled is defined as follows. First, if y1 <
- y0, swap (x0,y0) and (x1,y1). Then the line includes the point (x0,y0)
- but not the point (x1,y1). If x0=y0 and x1=y1, draw_line should return 0
- without drawing anything.
-
- int (*fill_trapezoid)(P8(struct gx_device_s *, int x0, int y0, int width0,
- int x1, int y1, int width1, gx_color_index color)) [OPTIONAL]
-
- Fill a trapezoid whose corners are (x0,y0), (x0+width0,y0),
- (x1,y1), and (x1+width1,y1), where y0 < y1. If width0 < 0, width1 < 0,
- width0 = width1 = 0, or y0 >= y1, fill_trapezoid should return 0 without
- drawing anything; however, width0 = 0 or width1 = 0 is valid, and should
- result in a triangle being filled. As for fill_rectangle, the coordinates
- are "half-open": the points (x0+width0,y0) and (*,y1) are not included, so
- the extremal points that *are* included are
- (x0, y0) (x0 + width0 - 1, y0)
- (x1, y1 - 1) (x1 + width1 - 1, y1 - 1)
-
- Bitmap imaging
- --------------
-
- Bitmap (or pixmap) images are stored in memory in a nearly standard way.
- The first byte corresponds to (0,0) in the image coordinate system: bits
- (or polybit color values) are packed into it left-to-right. There may be
- padding at the end of each scan line: the distance from one scan line to
- the next is always passed as an explicit argument.
-
- int (*copy_mono)(P10(struct gx_device_s *, unsigned char *data, int data_x,
- int raster, int x, int y, int width, int height,
- gx_color_index color0, gx_color_index color1))
-
- Copy a monochrome image (similar to the PostScript image
- operator). Each scan line is raster bytes wide. Copying begins at
- (data_x,0) and transfers a rectangle of the given width at height to the
- device at device coordinate (x,y). (If the transfer should start at some
- non-zero y value in the data, the caller can adjust the data address by
- the appropriate multiple of the raster.) The copying operation writes
- device color color0 at each 0-bit, and color1 at each 1-bit: if color0 or
- color1 is gx_no_color_index, the device pixel is unaffected if the image
- bit is 0 or 1 respectively.
-
- This operation is the workhorse for text display in Ghostscript,
- so implementing it efficiently is very important.
-
- int (*tile_rectangle)(P10(struct gx_device_s *, gx_bitmap *tile,
- int x, int y, int width, int height,
- gx_color_index color0, gx_color_index color1,
- int phase_x, int phase_y)) [OPTIONAL]
-
- Tile a rectangle. Tiling consists of doing multiple copy_mono
- operations to fill the rectangle with copies of the tile. The tiles are
- aligned with the device coordinate system, to avoid "seams".
- Specifically, the (phase_x, phase_y) point of the tile is aligned with the
- origin of the device coordinate system. (Note that this is backwards from
- the PostScript definition of halftone phase.) phase_x and phase_y are
- guaranteed to be in the range [0..tile->width) and [0..tile->height)
- respectively.
-
- If color0 and color1 are both gx_no_color_index, then the tile is
- a color pixmap, not a bitmap: see the next section.
-
- int (*tile_trapezoid)(P12(struct gx_device_s *, gx_bitmap *tile,
- int x0, int y0, int width0, int x1, int y1, int width1,
- gx_color_index color0, gx_color_index color1,
- int phase_x, int phase_y)) [OPTIONAL]
-
- Tile a trapezoid similarly.
-
- Pixmap imaging
- --------------
-
- Pixmaps are just like bitmaps, except that each pixel occupies more than
- one bit. All the bits for each pixel are grouped together (this is
- sometimes called "chunky" or "Z" format). The number of bits per pixel is
- given by the bits_per_color_pixel parameter in the device structure: the
- legal values are 1, 2, 4, 8, 16, 24, or 32. The pixel values are device
- color codes (i.e., whatever it is that map_rgb_color returns).
-
- int (*copy_color)(P8(struct gx_device_s *, unsigned char *data, int data_x,
- int raster, int x, int y, int width, int height))
-
- Copy a color image with multiple bits per pixel. The raster is in
- bytes, but x and width are in pixels, not bits.
-
- tile_rectangle and tile_trapezoid can also take colored tiles. This is
- indicated by the color0 and color1 arguments both being gx_no_color_index.
- In this case, as for copy_color, the raster and height in the "bitmap" are
- interpreted as for real bitmaps, but the x and width are in pixels, not
- bits.
-