<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>The interface between Ghostscript and device drivers</title><!-- $Id: Drivers.htm,v 1.58 2005/10/20 19:46:23 ray Exp $ --><!-- Originally: drivers.txt --><link rel="stylesheet" type="text/css" href="gs.css" title="Ghostscript Style"></head> <body><!-- [1.0 begin visible header] ============================================ --> <!-- [1.1 begin headline] ================================================== --> <h1>The interface between Ghostscript and device drivers</h1> <!-- [1.1 end headline] ==================================================== --> <!-- [1.2 begin table of contents] ========================================= --> <h2>Table of contents</h2> <blockquote><ul><li><a href="#Adding_drivers">Adding a driver</a><li><a href="#KISS">Keeping things simple</a><li><a href="#Structure">Driver structure</a><ul><li><a href="#Structure_definition">Structure definition</a><li><a href="#Sophisticated">For sophisticated developers only</a></ul><li><a href="#coordinates_and_types">Coordinates and types</a><ul><li><a href="#Coordinate_system">Coordinate system</a><li><a href="#Color_definition">Color definition</a><ul><li><a href="#sep_and_linear_fields">Separable and linear fields</a><li><a href="#Changing_color_info_data">Changing color_info data</a> </ul><li><a href="#Types">Types</a></ul><li><a href="#Coding_conventions">Coding conventions</a><ul><li><a href="#Allocating_storage">Allocating storage</a><li><a href="#Driver_instance_allocation">Driver instance allocation</a></ul><li><a href="#Printer_drivers">Printer drivers</a><li><a href="#Driver_procedures">Driver procedures</a><ul><li><a href="#Life_cycle">Life cycle</a><li><a href="#Open_close">Open, close, sync, copy</a><li><a href="#Color_mapping">Color and alpha mapping</a><li><a href="#Pixel_level_drawing">Pixel-level drawing</a><ul><li><a href="#Bitmap_imaging">Bitmap imaging</a><li><a href="#Pixmap_imaging">Pixmap imaging</a><li><a href="#Compositing">Compositing</a> [<a href="#S_spec">S</a>, <a href="#T_spec">T</a>, <a href="#F_spec">f</a>, <a href="#Compositing_notes">Notes</a>]</ul><li><a href="#Polygon_level_drawing">Polygon-level drawing</a><li><a href="#Linear_color_drawing">Linear color drawing</a><li><a href="#High_level_drawing">High-level drawing</a><ul><li><a href="#Paths">Paths</a><li><a href="#Images">Images</a> [<a href="#Images_notes">Notes</a>]<li><a href="#Text">Text</a> [<a href="#Text_notes">Notes</a>]<li><a href="#Unicode">Unicode support for high level devices</a></ul><li><a href="#Reading_bits_back">Reading bits back</a><li><a href="#Parameters">Parameters</a><ul><li><a href="#Default_CRD_parameters">Default color rendering dictionary (CRD) parameters</a></ul><li><a href="#External_fonts">External fonts</a><li><a href="#Page_devices">Page devices</a><li><a href="#Miscellaneous">Miscellaneous</a></ul></ul></blockquote> <!-- [1.2 end table of contents] =========================================== --> <!-- [1.3 begin hint] ====================================================== --> <p>For other information, see the <a href="Readme.htm">Ghostscriptoverview</a> and the documentation on <a href="Make.htm">how to buildGhostscript</a>. <!-- [1.3 end hint] ======================================================== --> <hr> <!-- [1.0 end visible header] ============================================== --> <!-- [2.0 begin contents] ================================================== --> <h2><a name="Adding_drivers"></a>Adding a driver</h2> <p>To add a driver to Ghostscript, first pick a name for your device, say"<b><tt>smurf</tt></b>". (Device names must be 1 to 8 characters, beginwith a letter, and consist only of letters, digits, and underscores. Caseis significant: all current device names are lower case.) Then all youneed do is edit <b><tt>contrib.mak</tt></b> in two places. <ol><li>The list of devices, in the section headed "Catalog". Add<b><tt>smurf</tt></b> to the list. <li>The section headed "Device drivers". <p>Suppose the files containing the smurf driver are called"<b><tt>joe</tt></b>" and "<b><tt>fred</tt></b>". Then you should add thefollowing lines: <blockquote><pre># ------ The SMURF device ------ # smurf_=$(GLOBJ)joe.$(OBJ) $(GLOBJ)fred.$(OBJ)$(DD)smurf.dev: $(smurf_) $(SETDEV) $(DD)smurf $(smurf_) $(GLOBJ)joe.$(OBJ) : $(GLSRC)joe.c $(GLCC) $(GLO_)joe.$(OBJ) $(C_) $(GLSRC)joe.c $(GLOBJ)fred.$(OBJ) : $(GLSRC)fred.c $(GLCC) $(GLO_)fred.$(OBJ) $(C_) $(GLSRC)fred.c</pre></blockquote> <p>and whatever <b><tt>joe.c</tt></b> and <b><tt>fred.c</tt></b> depend on.If the smurf driver also needs special libraries, for instance a librarynamed "<b><tt>gorf</tt></b>", then the entry should look like this: <blockquote><pre>$(DD)smurf.dev : $(smurf_) $(SETDEV) $(DD)smurf $(smurf_) $(ADDMOD) $(DD)smurf -lib gorf</pre></blockquote> <p>If, as will usually be the case, your driver is a printer driver (as<a href="#Printer_drivers">discussed below</a>), the device entry shouldlook like this: <blockquote><pre>$(DD)smurf.dev : $(smurf_) $(GLD)page.dev $(SETPDEV) $(DD)smurf $(smurf_)</pre></blockquote> <p>or <blockquote><pre>$(DD)smurf.dev : $(smurf_) $(GLD)page.dev $(SETPDEV) $(DD)smurf $(smurf_) $(ADDMOD) $(DD)smurf -lib gorf</pre></blockquote> <p>Note that the space before the :, and the explicit compilation rules for the.c files, are required for portability,</ol> <hr> <h2><a name="KISS"></a>Keeping things simple</h2> <p>If you want to add a simple device (specifically, a monochrome printer), youprobably don't need to read the rest of this document; just use the code inan existing driver as a guide. The Epson and Canon BubbleJet drivers <ahref="../src/gdevepsn.c">gdevepsn.c</a> and <ahref="../src/gdevbj10.c">gdevbj10.c</a> are good models for dot-matrixprinters, which require presenting the data for many scan lines at once; theDeskJet/LaserJet drivers in <a href="../src/gdevdjet.c">gdevdjet.c</a> aregood models for laser printers, which take a single scan line at a time butsupport data compression. For color printers, there are unfortunately nogood models: the two major color inkjet printer drivers, <ahref="../src/gdevcdj.c">gdevcdj.c</a> and <ahref="../src/gdevstc.c">gdevstc.c</a>, are far too complex to read. <p>On the other hand, if you're writing a driver for some more esotericdevice, you probably do need at least some of the information in the restof this document. It might be a good idea for you to read it inconjunction with one of the existing drivers. <p>Duplication of code, and sheer volume of code, is a serious maintenance anddistribution problem for Ghostscript. If your device is similar to anexisting one, try to implement your driver by adding some parameterizationto an existing driver rather than by copying code to create an entirely newsource module. <a href="../src/gdevepsn.c">gdevepsn.c</a> and <ahref="../src/gdevdjet.c">gdevdjet.c</a> are good examples of this approach. <hr> <h2><a name="Structure"></a>Driver structure</h2> <p>A device is represented by a structure divided into three parts: <ul><li>procedures that are (normally) shared by all instances of each device; <li>parameters that are present in all devices but may be different foreach device or instance; and <li>device-specific parameters that may be different for each instance.</ul> <p>Normally the procedure structure is defined and initialized at compiletime. A prototype of the parameter structure (including both generic anddevice-specific parameters) is defined and initialized at compile time, butis copied and filled in when an instance of the device is created. Both ofthese structures should be declared as <b><tt>const</tt></b>, but for backwardcompatibility reasons the latter is not. <p>The <b><tt>gx_device_common</tt></b> macro defines the common structureelements, with the intent that devices define and export a structure alongthe following lines. Do not fill in the individual generic parameter valuesin the usual way for C structures: use the macros defined for this purposein <a href="../src/gxdevice.h">gxdevice.h</a> or, if applicable, <ahref="../src/gdevprn.h">gdevprn.h</a>. <blockquote><pre>typedef struct smurf_device_s { gx_device_common; <b><em>... device-specific parameters ...</em></b>} smurf_device;smurf_device gs_smurf_device = { <b><em>... macro for generic parameter values ...,</em></b> { <b><em>... procedures ...</em></b> }, /* std_procs */ <b><em>... device-specific parameter values if any ...</em></b>};</pre></blockquote><p>The device structure instance <b>must</b> have the name<b><tt>gs_smurf_device</tt></b>, where <b><tt>smurf</tt></b> is the devicename used in <b><tt>contrib.mak</tt></b>. <b><tt>gx_device_common</tt></b>is a macro consisting only of the element definitions. <p>All the device procedures are called with the device as the first argument.Since each device type is actually a different structure type, the deviceprocedures must be declared as taking a <b><tt>gx_device *</tt></b> astheir first argument, and must cast it to<b><tt>smurf_device *</tt></b> internally. For example, in the codefor the "memory" device, the first argument to all routines is called<b><tt>dev</tt></b>, but the routines actually use <b><tt>mdev</tt></b> torefer to elements of the full structure, using the following standardinitialization statement at the beginning of each procedure: <blockquote><pre>gx_memory_device *const mdev = (gx_device_memory *)dev;</pre></blockquote> <p>(This is a cheap version of "object-oriented" programming: in C++, forexample, the cast would be unnecessary, and in fact the procedure tablewould be constructed by the compiler.) <h3><a name="Structure_definition"></a>Structure definition</h3> <p>You should consult the definition of struct <b><tt>gx_device_s</tt></b> in<a href="../src/gxdevice.h">gxdevice.h</a> for the complete details of thegeneric device structure. Some of the most important members of thisstructure for ordinary drivers are: <blockquote><table cellpadding=0 cellspacing=0><tr valign=top> <td><b><tt>const char *dname;</tt></b> <td> <td>The device name<tr valign=top> <td><b><tt>bool is_open;</tt></b> <td> <td>True if device has been opened<tr valign=top> <td><b><tt>gx_device_color_info color_info;</tt></b> <td> <td>Color information<tr valign=top> <td><b><tt>int width;</tt></b> <td> <td>Width in pixels<tr valign=top> <td><b><tt>int height;</tt></b> <td> <td>Height in pixels</table></blockquote> <p>The name in the structure (<b><tt>dname</tt></b>) should be the same as thename in <a href="../src/contrib.mak">contrib.mak</a>. <h3><a name="Sophisticated"></a>For sophisticated developers only</h3> <p>If for any reason you need to change the definition of the basic devicestructure, or to add procedures, you must change the following places: <blockquote><ul><li>This document and the <a href="News.htm">news document</a> (if you want to keep the documentation up to date).<li>The definition of <b><tt>gx_device_common</tt></b> and the procedures in <a href="../src/gxdevcli.h">gxdevcli.h</a>.<li>Possibly, the default forwarding procedures declared in <a href="../src/gxdevice.h">gxdevice.h</a> and implemented in <a href="../src/gdevnfwd.c">gdevnfwd.c</a>.<li>The device procedure record completion routines in <a href="../src/gdevdflt.c">gdevdflt.c</a>.<li>Possibly, the default device implementation in <a href="../src/gdevdflt.c">gdevdflt.c</a>, <a href="../src/gdevddrw.c">gdevddrw.c</a>, and <a href="../src/gxcmap.c">gxcmap.c</a>.<li>The bounding box device in <a href="../src/gdevbbox.c">gdevbbox.c</a> (probably just adding <b><tt>NULL</tt></b> procedure entries if the new procedures don't produce output).<li>These devices that must have complete (non-defaulted) procedure vectors:<ul><li>The null device in <a href="../src/gdevnfwd.c">gdevnfwd.c</a>.<li>The command list "device" in <a href="../src/gxclist.c">gxclist.c</a>. This is not an actual device; it only defines procedures.<li>The "memory" devices in <a href="../src/gdevmem.h">gdevmem.h</a> and <b><tt>gdevm*.c</tt></b>.</ul><li>The clip list accumulation "device" in <a href="../src/gxacpath.c">gxacpath.c</a>.<li>The clipping "devices" <a href="../src/gxclip.c">gxclip.c</a>, <a href="../src/gxclip2.c">gxclip2.c</a>, and <a href="../src/gxclipm.c">gxclipm.c</a>.<li>The pattern accumulation "device" in <a href="../src/gxpcmap.c">gxpcmap.c</a>.<li>The hit detection "device" in <a href="../src/gdevhit.c">gdevhit.c</a>.<li>The generic printer device macros in <a href="../src/gdevprn.h">gdevprn.h</a>.<li>The generic printer device code in <a href="../src/gdevprn.c">gdevprn.c</a>.<li>The RasterOp source device in <a href="../src/gdevrops.c">gdevrops.c</a>.</ul></blockquote> <p>You may also have to change the code for<b><tt>gx_default_get_params</tt></b> or<b><tt>gx_default_put_params</tt></b> in <ahref="../src/gsdparam.c">gsdparam.c</a>. <p>You should not have to change any of the real devices in the standardGhostscript distribution (listed in <a href="../src/devs.mak">devs.mak</a>and <a href="../src/contrib.mak">contrib.mak</a>) or any of your owndevices, because all of them are supposed to use the macros in <ahref="../src/gxdevice.h">gxdevice.h</a> or <ahref="../src/gdevprn.h">gdevprn.h</a> to define and initialize their state. <hr> <h2><a name="coordinates_and_types"></a>Coordinates and types</h2> <h3><a name="Coordinate_system"></a>Coordinate system</h3> <p>Since each driver specifies the initial transformation from usercoordinates to device coordinates, the driver can use any coordinate systemit wants, as long as a device coordinate will fit in an<b><tt>int</tt></b>. (This is only an issue on DOS systems, where ints areonly 16 bits. User coordinates are represented as floats.) Most currentdrivers use a coordinate system with (0,0) in the upper left corner, with<b><em>X</em></b> increasing to the right and <b><em>Y</em></b> increasingtoward the bottom. However, there is supposed to be nothing in the rest ofGhostscript that assumes this, and indeed some drivers use a coordinatesystem with (0,0) in the lower left corner. <p>Drivers must check (and, if necessary, clip) the coordinate parameters givento them: they should not assume the coordinates will be in bounds. The<b><tt>fit_fill</tt></b> and <b><tt>fit_copy</tt></b> macros in <ahref="../src/gxdevice.h">gxdevice.h</a> are very helpful in doing this. <h3><a name="Color_definition"></a>Color definition</h3> <p>Between the Ghostscript graphics library and the device, colors arerepresented in three forms. Color components in a color space (Gray, RGB,DeviceN, etc.) represented as <b><tt>frac</tt></b> values. Device colorantsare represented as <b><tt>gx_color_value</tt></b> values. For manyprocedures, colors are represented in a type called<b><tt>gx_color_index</tt></b>.All three types are described in more detail in <a href="#Types">Types</a> <p>The <b><tt>color_info</tt></b> member of the device structure defines thecolor and gray-scale capabilities of the device. Its type is defined asfollows: <blockquote><pre>/* * The enlarged color model information structure: Some of the * information that was implicit in the component number in * the earlier conventions (component names, polarity, mapping * functions) are now explicitly provided. * * Also included is some information regarding the encoding of * color information into gx_color_index. Some of this information * was previously gathered indirectly from the mapping * functions in the existing code, specifically to speed up the * halftoned color rendering operator (see * gx_dc_ht_colored_fill_rectangle in gxcht.c). The information * is now provided explicitly because such optimizations are * more critical when the number of color components is large. * * Note: no pointers have been added to this structure, so there * is no requirement for a structure descriptor. */typedef struct gx_device_color_info_s { /* * max_components is the maximum number of components for all * color models supported by this device. This does not include * any alpha components. */ int max_components; /* * The number of color components. This does not include any * alpha-channel information, which may be integrated into * the gx_color_index but is otherwise passed as a separate * component. */ int num_components; /* * Polarity of the components of the color space, either * additive or subtractive. This is used to interpret transfer * functions and halftone threshold arrays. Possible values * are GX_CM_POLARITY_ADDITIVE or GX_CM_POLARITY_SUBTRACTIVE */ gx_color_polarity_t polarity; /* * The number of bits of gx_color_index actually used. * This must be <= sizeof(gx_color_index), which is usually 64. */ byte depth; /* * Index of the gray color component, if any. The max_gray and * dither_gray values apply to this component only; all other * components use the max_color and dither_color values. * * This will be GX_CINFO_COMP_NO_INDEX if there is no gray * component. */ byte gray_index; /* * max_gray and max_color are the number of distinct native * intensity levels, less 1, for the gray and all other color * components, respectively. For nearly all current devices * that support both gray and non-gray components, the two * parameters have the same value. * * dither_grays and dither_colors are the number of intensity * levels between which halftoning can occur, for the gray and * all other color components, respectively. This is * essentially redundant information: in all reasonable cases, * dither_grays = max_gray + 1 and dither_colors = max_color + 1. * These parameters are, however, extensively used in the * current code, and thus have been retained. * * Note that the non-gray values may now be relevant even if * num_components == 1. This simplifies the handling of devices * with configurable color models which may be set for a single * non-gray color model. */ gx_color_value max_gray; /* # of distinct color levels -1 */ gx_color_value max_color; gx_color_value dither_grays; gx_color_value dither_colors; /* * Information to control super-sampling of objects to support * anti-aliasing. */ gx_device_anti_alias_info anti_alias; /* * Flag to indicate if gx_color_index for this device may be divided * into individual fields for each component. This is almost always * the case for printers, and is the case for most modern displays * as well. When this is the case, halftoning may be performed * separately for each component, which greatly simplifies processing * when the number of color components is large. * * If the gx_color_index is separable in this manner, the comp_shift * array provides the location of the low-order bit for each * component. This may be filled in by the client, but need not be. * If it is not provided, it will be calculated based on the valuesLines 1–500 of 3099. Load more
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>The interface between Ghostscript and device drivers</title> <!-- $Id: Drivers.htm,v 1.58 2005/10/20 19:46:23 ray Exp $ --> <!-- Originally: drivers.txt --> <link rel="stylesheet" type="text/css" href="gs.css" title="Ghostscript Style"> </head> <body> <!-- [1.0 begin visible header] ============================================ --> <!-- [1.1 begin headline] ================================================== --> <h1>The interface between Ghostscript and device drivers</h1> <!-- [1.1 end headline] ==================================================== --> <!-- [1.2 begin table of contents] ========================================= --> <h2>Table of contents</h2> <blockquote><ul> <li><a href="#Adding_drivers">Adding a driver</a> <li><a href="#KISS">Keeping things simple</a> <li><a href="#Structure">Driver structure</a> <ul> <li><a href="#Structure_definition">Structure definition</a> <li><a href="#Sophisticated">For sophisticated developers only</a> </ul> <li><a href="#coordinates_and_types">Coordinates and types</a> <ul> <li><a href="#Coordinate_system">Coordinate system</a> <li><a href="#Color_definition">Color definition</a> <ul> <li><a href="#sep_and_linear_fields">Separable and linear fields</a> <li><a href="#Changing_color_info_data">Changing color_info data</a> </ul> <li><a href="#Types">Types</a> </ul> <li><a href="#Coding_conventions">Coding conventions</a> <ul> <li><a href="#Allocating_storage">Allocating storage</a> <li><a href="#Driver_instance_allocation">Driver instance allocation</a> </ul> <li><a href="#Printer_drivers">Printer drivers</a> <li><a href="#Driver_procedures">Driver procedures</a> <ul> <li><a href="#Life_cycle">Life cycle</a> <li><a href="#Open_close">Open, close, sync, copy</a> <li><a href="#Color_mapping">Color and alpha mapping</a> <li><a href="#Pixel_level_drawing">Pixel-level drawing</a> <ul> <li><a href="#Bitmap_imaging">Bitmap imaging</a> <li><a href="#Pixmap_imaging">Pixmap imaging</a> <li><a href="#Compositing">Compositing</a> [<a href="#S_spec">S</a>, <a href="#T_spec">T</a>, <a href="#F_spec">f</a>, <a href="#Compositing_notes">Notes</a>] </ul> <li><a href="#Polygon_level_drawing">Polygon-level drawing</a> <li><a href="#Linear_color_drawing">Linear color drawing</a> <li><a href="#High_level_drawing">High-level drawing</a> <ul> <li><a href="#Paths">Paths</a> <li><a href="#Images">Images</a> [<a href="#Images_notes">Notes</a>] <li><a href="#Text">Text</a> [<a href="#Text_notes">Notes</a>] <li><a href="#Unicode">Unicode support for high level devices</a> </ul> <li><a href="#Reading_bits_back">Reading bits back</a> <li><a href="#Parameters">Parameters</a> <ul> <li><a href="#Default_CRD_parameters">Default color rendering dictionary (CRD) parameters</a> </ul> <li><a href="#External_fonts">External fonts</a> <li><a href="#Page_devices">Page devices</a> <li><a href="#Miscellaneous">Miscellaneous</a> </ul> </ul></blockquote> <!-- [1.2 end table of contents] =========================================== --> <!-- [1.3 begin hint] ====================================================== --> <p>For other information, see the <a href="Readme.htm">Ghostscript overview</a> and the documentation on <a href="Make.htm">how to build Ghostscript</a>. <!-- [1.3 end hint] ======================================================== --> <hr> <!-- [1.0 end visible header] ============================================== --> <!-- [2.0 begin contents] ================================================== --> <h2><a name="Adding_drivers"></a>Adding a driver</h2> <p> To add a driver to Ghostscript, first pick a name for your device, say "<b><tt>smurf</tt></b>". (Device names must be 1 to 8 characters, begin with a letter, and consist only of letters, digits, and underscores. Case is significant: all current device names are lower case.) Then all you need do is edit <b><tt>contrib.mak</tt></b> in two places. <ol> <li>The list of devices, in the section headed "Catalog". Add <b><tt>smurf</tt></b> to the list. <li>The section headed "Device drivers". <p> Suppose the files containing the smurf driver are called "<b><tt>joe</tt></b>" and "<b><tt>fred</tt></b>". Then you should add the following lines: <blockquote> <pre># ------ The SMURF device ------ # smurf_=$(GLOBJ)joe.$(OBJ) $(GLOBJ)fred.$(OBJ) $(DD)smurf.dev: $(smurf_) $(SETDEV) $(DD)smurf $(smurf_) $(GLOBJ)joe.$(OBJ) : $(GLSRC)joe.c $(GLCC) $(GLO_)joe.$(OBJ) $(C_) $(GLSRC)joe.c $(GLOBJ)fred.$(OBJ) : $(GLSRC)fred.c $(GLCC) $(GLO_)fred.$(OBJ) $(C_) $(GLSRC)fred.c</pre> </blockquote> <p> and whatever <b><tt>joe.c</tt></b> and <b><tt>fred.c</tt></b> depend on. If the smurf driver also needs special libraries, for instance a library named "<b><tt>gorf</tt></b>", then the entry should look like this: <blockquote> <pre>$(DD)smurf.dev : $(smurf_) $(SETDEV) $(DD)smurf $(smurf_) $(ADDMOD) $(DD)smurf -lib gorf</pre> </blockquote> <p> If, as will usually be the case, your driver is a printer driver (as <a href="#Printer_drivers">discussed below</a>), the device entry should look like this: <blockquote> <pre>$(DD)smurf.dev : $(smurf_) $(GLD)page.dev $(SETPDEV) $(DD)smurf $(smurf_)</pre> </blockquote> <p> or <blockquote> <pre>$(DD)smurf.dev : $(smurf_) $(GLD)page.dev $(SETPDEV) $(DD)smurf $(smurf_) $(ADDMOD) $(DD)smurf -lib gorf</pre> </blockquote> <p> Note that the space before the :, and the explicit compilation rules for the .c files, are required for portability, </ol> <hr> <h2><a name="KISS"></a>Keeping things simple</h2> <p> If you want to add a simple device (specifically, a monochrome printer), you probably don't need to read the rest of this document; just use the code in an existing driver as a guide. The Epson and Canon BubbleJet drivers <a href="../src/gdevepsn.c">gdevepsn.c</a> and <a href="../src/gdevbj10.c">gdevbj10.c</a> are good models for dot-matrix printers, which require presenting the data for many scan lines at once; the DeskJet/LaserJet drivers in <a href="../src/gdevdjet.c">gdevdjet.c</a> are good models for laser printers, which take a single scan line at a time but support data compression. For color printers, there are unfortunately no good models: the two major color inkjet printer drivers, <a href="../src/gdevcdj.c">gdevcdj.c</a> and <a href="../src/gdevstc.c">gdevstc.c</a>, are far too complex to read. <p> On the other hand, if you're writing a driver for some more esoteric device, you probably do need at least some of the information in the rest of this document. It might be a good idea for you to read it in conjunction with one of the existing drivers. <p> Duplication of code, and sheer volume of code, is a serious maintenance and distribution problem for Ghostscript. If your device is similar to an existing one, try to implement your driver by adding some parameterization to an existing driver rather than by copying code to create an entirely new source module. <a href="../src/gdevepsn.c">gdevepsn.c</a> and <a href="../src/gdevdjet.c">gdevdjet.c</a> are good examples of this approach. <hr> <h2><a name="Structure"></a>Driver structure</h2> <p> A device is represented by a structure divided into three parts: <ul> <li>procedures that are (normally) shared by all instances of each device; <li>parameters that are present in all devices but may be different for each device or instance; and <li>device-specific parameters that may be different for each instance. </ul> <p> 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. Both of these structures should be declared as <b><tt>const</tt></b>, but for backward compatibility reasons the latter is not. <p> The <b><tt>gx_device_common</tt></b> macro defines the common structure elements, with the intent that devices define and export a structure along the following lines. Do not fill in the individual generic parameter values in the usual way for C structures: use the macros defined for this purpose in <a href="../src/gxdevice.h">gxdevice.h</a> or, if applicable, <a href="../src/gdevprn.h">gdevprn.h</a>. <blockquote> <pre>typedef struct smurf_device_s { gx_device_common; <b><em>... device-specific parameters ...</em></b> } smurf_device; smurf_device gs_smurf_device = { <b><em>... macro for generic parameter values ...,</em></b> { <b><em>... procedures ...</em></b> }, /* std_procs */ <b><em>... device-specific parameter values if any ...</em></b> };</pre> </blockquote> <p> The device structure instance <b>must</b> have the name <b><tt>gs_smurf_device</tt></b>, where <b><tt>smurf</tt></b> is the device name used in <b><tt>contrib.mak</tt></b>. <b><tt>gx_device_common</tt></b> is a macro consisting only of the element definitions. <p> 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 <b><tt>gx_device *</tt></b> as their first argument, and must cast it to <b><tt>smurf_device *</tt></b> internally. For example, in the code for the "memory" device, the first argument to all routines is called <b><tt>dev</tt></b>, but the routines actually use <b><tt>mdev</tt></b> to refer to elements of the full structure, using the following standard initialization statement at the beginning of each procedure: <blockquote> <pre>gx_memory_device *const mdev = (gx_device_memory *)dev;</pre> </blockquote> <p> (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.) <h3><a name="Structure_definition"></a>Structure definition</h3> <p> You should consult the definition of struct <b><tt>gx_device_s</tt></b> in <a href="../src/gxdevice.h">gxdevice.h</a> for the complete details of the generic device structure. Some of the most important members of this structure for ordinary drivers are: <blockquote><table cellpadding=0 cellspacing=0> <tr valign=top> <td><b><tt>const char *dname;</tt></b> <td> <td>The device name <tr valign=top> <td><b><tt>bool is_open;</tt></b> <td> <td>True if device has been opened <tr valign=top> <td><b><tt>gx_device_color_info color_info;</tt></b> <td> <td>Color information <tr valign=top> <td><b><tt>int width;</tt></b> <td> <td>Width in pixels <tr valign=top> <td><b><tt>int height;</tt></b> <td> <td>Height in pixels </table></blockquote> <p> The name in the structure (<b><tt>dname</tt></b>) should be the same as the name in <a href="../src/contrib.mak">contrib.mak</a>. <h3><a name="Sophisticated"></a>For sophisticated developers only</h3> <p> If for any reason you need to change the definition of the basic device structure, or to add procedures, you must change the following places: <blockquote><ul> <li>This document and the <a href="News.htm">news document</a> (if you want to keep the documentation up to date). <li>The definition of <b><tt>gx_device_common</tt></b> and the procedures in <a href="../src/gxdevcli.h">gxdevcli.h</a>. <li>Possibly, the default forwarding procedures declared in <a href="../src/gxdevice.h">gxdevice.h</a> and implemented in <a href="../src/gdevnfwd.c">gdevnfwd.c</a>. <li>The device procedure record completion routines in <a href="../src/gdevdflt.c">gdevdflt.c</a>. <li>Possibly, the default device implementation in <a href="../src/gdevdflt.c">gdevdflt.c</a>, <a href="../src/gdevddrw.c">gdevddrw.c</a>, and <a href="../src/gxcmap.c">gxcmap.c</a>. <li>The bounding box device in <a href="../src/gdevbbox.c">gdevbbox.c</a> (probably just adding <b><tt>NULL</tt></b> procedure entries if the new procedures don't produce output). <li>These devices that must have complete (non-defaulted) procedure vectors: <ul> <li>The null device in <a href="../src/gdevnfwd.c">gdevnfwd.c</a>. <li>The command list "device" in <a href="../src/gxclist.c">gxclist.c</a>. This is not an actual device; it only defines procedures. <li>The "memory" devices in <a href="../src/gdevmem.h">gdevmem.h</a> and <b><tt>gdevm*.c</tt></b>. </ul> <li>The clip list accumulation "device" in <a href="../src/gxacpath.c">gxacpath.c</a>. <li>The clipping "devices" <a href="../src/gxclip.c">gxclip.c</a>, <a href="../src/gxclip2.c">gxclip2.c</a>, and <a href="../src/gxclipm.c">gxclipm.c</a>. <li>The pattern accumulation "device" in <a href="../src/gxpcmap.c">gxpcmap.c</a>. <li>The hit detection "device" in <a href="../src/gdevhit.c">gdevhit.c</a>. <li>The generic printer device macros in <a href="../src/gdevprn.h">gdevprn.h</a>. <li>The generic printer device code in <a href="../src/gdevprn.c">gdevprn.c</a>. <li>The RasterOp source device in <a href="../src/gdevrops.c">gdevrops.c</a>. </ul></blockquote> <p> You may also have to change the code for <b><tt>gx_default_get_params</tt></b> or <b><tt>gx_default_put_params</tt></b> in <a href="../src/gsdparam.c">gsdparam.c</a>. <p> You should not have to change any of the real devices in the standard Ghostscript distribution (listed in <a href="../src/devs.mak">devs.mak</a> and <a href="../src/contrib.mak">contrib.mak</a>) or any of your own devices, because all of them are supposed to use the macros in <a href="../src/gxdevice.h">gxdevice.h</a> or <a href="../src/gdevprn.h">gdevprn.h</a> to define and initialize their state. <hr> <h2><a name="coordinates_and_types"></a>Coordinates and types</h2> <h3><a name="Coordinate_system"></a>Coordinate system</h3> <p> Since each driver specifies the initial transformation from user coordinates to device coordinates, the driver can use any coordinate system it wants, as long as a device coordinate will fit in an <b><tt>int</tt></b>. (This is only an issue on DOS systems, where ints are only 16 bits. User coordinates are represented as floats.) Most current drivers use a coordinate system with (0,0) in the upper left corner, with <b><em>X</em></b> increasing to the right and <b><em>Y</em></b> increasing toward the bottom. However, there is supposed to be nothing in the rest of Ghostscript that assumes this, and indeed some drivers use a coordinate system with (0,0) in the lower left corner. <p> Drivers must check (and, if necessary, clip) the coordinate parameters given to them: they should not assume the coordinates will be in bounds. The <b><tt>fit_fill</tt></b> and <b><tt>fit_copy</tt></b> macros in <a href="../src/gxdevice.h">gxdevice.h</a> are very helpful in doing this. <h3><a name="Color_definition"></a>Color definition</h3> <p> Between the Ghostscript graphics library and the device, colors are represented in three forms. Color components in a color space (Gray, RGB, DeviceN, etc.) represented as <b><tt>frac</tt></b> values. Device colorants are represented as <b><tt>gx_color_value</tt></b> values. For many procedures, colors are represented in a type called <b><tt>gx_color_index</tt></b>. All three types are described in more detail in <a href="#Types">Types</a> <p> The <b><tt>color_info</tt></b> member of the device structure defines the color and gray-scale capabilities of the device. Its type is defined as follows: <blockquote> <pre> /* * The enlarged color model information structure: Some of the * information that was implicit in the component number in * the earlier conventions (component names, polarity, mapping * functions) are now explicitly provided. * * Also included is some information regarding the encoding of * color information into gx_color_index. Some of this information * was previously gathered indirectly from the mapping * functions in the existing code, specifically to speed up the * halftoned color rendering operator (see * gx_dc_ht_colored_fill_rectangle in gxcht.c). The information * is now provided explicitly because such optimizations are * more critical when the number of color components is large. * * Note: no pointers have been added to this structure, so there * is no requirement for a structure descriptor. */ typedef struct gx_device_color_info_s { /* * max_components is the maximum number of components for all * color models supported by this device. This does not include * any alpha components. */ int max_components; /* * The number of color components. This does not include any * alpha-channel information, which may be integrated into * the gx_color_index but is otherwise passed as a separate * component. */ int num_components; /* * Polarity of the components of the color space, either * additive or subtractive. This is used to interpret transfer * functions and halftone threshold arrays. Possible values * are GX_CM_POLARITY_ADDITIVE or GX_CM_POLARITY_SUBTRACTIVE */ gx_color_polarity_t polarity; /* * The number of bits of gx_color_index actually used. * This must be <= sizeof(gx_color_index), which is usually 64. */ byte depth; /* * Index of the gray color component, if any. The max_gray and * dither_gray values apply to this component only; all other * components use the max_color and dither_color values. * * This will be GX_CINFO_COMP_NO_INDEX if there is no gray * component. */ byte gray_index; /* * max_gray and max_color are the number of distinct native * intensity levels, less 1, for the gray and all other color * components, respectively. For nearly all current devices * that support both gray and non-gray components, the two * parameters have the same value. * * dither_grays and dither_colors are the number of intensity * levels between which halftoning can occur, for the gray and * all other color components, respectively. This is * essentially redundant information: in all reasonable cases, * dither_grays = max_gray + 1 and dither_colors = max_color + 1. * These parameters are, however, extensively used in the * current code, and thus have been retained. * * Note that the non-gray values may now be relevant even if * num_components == 1. This simplifies the handling of devices * with configurable color models which may be set for a single * non-gray color model. */ gx_color_value max_gray; /* # of distinct color levels -1 */ gx_color_value max_color; gx_color_value dither_grays; gx_color_value dither_colors; /* * Information to control super-sampling of objects to support * anti-aliasing. */ gx_device_anti_alias_info anti_alias; /* * Flag to indicate if gx_color_index for this device may be divided * into individual fields for each component. This is almost always * the case for printers, and is the case for most modern displays * as well. When this is the case, halftoning may be performed * separately for each component, which greatly simplifies processing * when the number of color components is large. * * If the gx_color_index is separable in this manner, the comp_shift * array provides the location of the low-order bit for each * component. This may be filled in by the client, but need not be. * If it is not provided, it will be calculated based on the values