<html><head><title>The interface between Ghostscript and device drivers</title><!-- $Id: Drivers.htm,v 1.1 2000/03/09 08:40:39 lpd Exp $ --><!-- Originally: drivers.txt --></head> <body><!-- [1.0 begin visible header] ============================================ --> <!-- [1.1 begin headline] ================================================== --> <table width="100%" border="0"><tr><th align="center" bgcolor="#CCCC00"><font size=6>The interface between Ghostscript and device drivers</font></table> <!-- [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><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</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="#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></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] ================================================== --> <h1><a name="Adding_drivers"></a>Adding a driver</h1> <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> <h1><a name="KISS"></a>Keeping things simple</h1> <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 thecode in an existing driver as a guide. The Epson and Canon BubbleJetdrivers <b><tt>gdevepsn.c</tt></b> and <b><tt>gdevbj10.c</tt></b> are goodmodels for dot-matrix printers, which require presenting the data for manyscan lines at once; the DeskJet/LaserJet drivers in<b><tt>gdevdjet.c</tt></b> are good models for laser printers, which take asingle scan line at a time but support data compression. For colorprinters, there are unfortunately no good models: the two major colorinkjet printer drivers, <b><tt>gdevcdj.c</tt></b> and<b><tt>gdevstc.c</tt></b>, 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. <b><tt>gdevepsn.c</tt></b> and <b><tt>gdevdjet.c</tt></b>are good examples of this approach. <hr> <h1><a name="Structure"></a>Driver structure</h1> <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 parametervalues in the usual way for C structures: use the macros defined for thispurpose in <b><tt>gxdevice.h</tt></b> or, if applicable,<b><tt>gdevprn.h</tt></b>. <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.) <h2><a name="Structure_definition"></a>Structure definition</h2> <p>You should consult the definition of struct <b><tt>gx_device_s</tt></b> in<b><tt>gxdevice.h</tt></b> for the complete details of the generic devicestructure. Some of the most important members of this structure forordinary 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 <b><tt>contrib.mak</tt></b>. <h2><a name="Sophisticated"></a>For sophisticated developers only</h2> <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 <b><tt>gxdevcli.h</tt></b>.<li>Possibly, the default forwarding procedures declared in <b><tt>gxdevice.h</tt></b> and implemented in <b><tt>gdevnfwd.c</tt></b>.<li>The device procedure record completion routines in <b><tt>gdevdflt.c</tt></b>.<li>Possibly, the default device implementation in <b><tt>gdevdflt.c</tt></b>, <b><tt>gdevddrw.c</tt></b>, and <b><tt>gxcmap.c</tt></b>.<li>The bounding box device in <b><tt>gdevbbox.c</tt></b> (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 <b><tt>gdevnfwd.c</tt></b>.<li>The command list "device" in <b><tt>gxclist.c</tt></b>. This is not an actual device; it only defines procedures.<li>The "memory" devices in <b><tt>gdevmem.h</tt></b> and <b><tt>gdevm*.c</tt></b>.<li>The halftoning device in <b><tt>gdevht.c</tt></b>.</ul><li>The clip list accumulation "device" in <b><tt>gxacpath.c</tt></b>.<li>The clipping "devices" <b><tt>xclip.c</tt></b>, <b><tt>gxclip2.c</tt></b>, and <b><tt>gxclipm.c</tt></b>.<li>The pattern accumulation "device" in <b><tt>gxpcmap.c</tt></b>.<li>The hit detection "device" in <b><tt>gdevhit.c</tt></b>.<li>The generic printer device macros in <b><tt>gdevprn.h</tt></b>.<li>The generic printer device code in <b><tt>gdevprn.c</tt></b>.<li>The RasterOp source device in <b><tt>gdevmrop.c</tt></b>.</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 <b><tt>gsdparam.c</tt></b>. <p>You should not have to change any of the real devices in the standardGhostscript distribution (listed in <b><tt>devs.mak</tt></b> and<b><tt>contrib.mak</tt></b>) or any of your own devices, because all ofthem are supposed to use the macros in <b><tt>gxdevice.h</tt></b> or<b><tt>gdevprn.h</tt></b> to define and initialize their state. <hr> <h1><a name="coordinates_and_types"></a>Coordinates and types</h1> <h2><a name="Coordinate_system"></a>Coordinate system</h2> <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 parametersgiven 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<b><tt>gxdevice.h</tt></b> are very helpful in doing this. <h2><a name="Color_definition"></a>Color definition</h2> <p>Ghostscript represents colors internally as RGB or CMYK values. Incommunicating with devices, however, it assumes that each device has apalette of colors identified by integers (to be precise, elements of type<b><tt>gx_color_index</tt></b>). Drivers may provide a uniformly spacedgray ramp or color cube for halftoning, or they may do their own colorapproximation, or both. <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>typedef struct gx_device_color_info_s { int num_components; /* 1 = gray only, 3 = RGB, */ /* 4 = CMYK */ int depth; /* # of bits per pixel */ gx_color_value max_gray; /* # of distinct gray levels -1 */ gx_color_value max_rgb; /* # of distinct color levels -1 */ /* (only relevant if num_comp. > 1) */ gx_color_value dither_gray; /* size of gray ramp for halftoning */ gx_color_value dither_rgb; /* size of color cube ditto */ /* (only relevant if num_comp. > 1) */} gx_device_color_info;</pre></blockquote> <p>The following macros (in <b><tt>gxdevice.h</tt></b>) provide convenient shorthands forinitializing this structure for ordinary black-and-white or color devices: <blockquote><b><tt>#define dci_black_and_white</tt></b> ...<br><b><tt>#define dci_color(depth,maxv,dither)</tt></b> ...</blockquote> <p>The idea is that a device has a certain number of gray levels(<b><tt>max_gray</tt></b>+1) and a certain number of colors(<b><tt>max_rgb</tt></b>+1) that it can produce directly. When Ghostscriptwants to render a given RGB or CMYK color as a device color, it first testswhether the color is a gray level (if <b><tt>num_components</tt></b> is 1,it converts all colors to gray levels), and if so: <blockquote>If <b><tt>max_gray</tt></b> is large (>= 31), Ghostscript asks thedevice to approximate the gray level directly. If the device returns avalid <b><tt>gx_color_index</tt></b>, Ghostscript uses it. Otherwise,Ghostscript assumes that the device can represent<b><tt>dither_gray</tt></b> distinct gray levels, equally spaced along thediagonal of the color cube, and uses the two nearest ones to the desiredcolor for halftoning.</blockquote> <p>If the color is not a gray level: <blockquote>If <b><tt>max_rgb</tt></b> is large (>= 31), Ghostscript asks the deviceto approximate the color directly. If the device returns a valid<b><tt>gx_color_index</tt></b>, Ghostscript uses it. Otherwise,Ghostscript assumes that the device can represent <blockquote><b><tt>dither_rgb</tt></b> × <b><tt>dither_rgb</tt></b> × <b><tt>dither_rgb</tt></b></blockquote> <p>distinct colors, equally spaced throughout the color cube, and uses two ofthe nearest ones to the desired color for halftoning.</blockquote> <h2><a name="Types"></a>Types</h2> <p>Here is a brief explanation of the various types that appear as parametersor results of the drivers. <dl><dt><b><tt>gx_color_value</tt></b> (defined in <b><tt>gxdevice.h</tt></b>)<dd>This is the type used to represent RGB or CMYK color values. It iscurrently equivalent to unsigned short. However, Ghostscript may use lessthan the full range of the type to represent color values:<b><tt>gx_color_value_bits</tt></b> is the number of bits actually used,and <b><tt>gx_max_color_value</tt></b> is the maximum value, equal to(2^<small><sup><b><tt>gx_max_color_value_bits</tt></b></sup></small>)-1.</dl> <dl><dt><b><tt>gx_device</tt></b> (defined in <b><tt>gxdevice.h</tt></b>)<dd>This is the device structure, as explained above.</dl> <dl><dt><b><tt>gs_matrix</tt></b> (defined in <b><tt>gsmatrix.h</tt></b>)<dd>This is a 2-D homogeneous coordinate transformation matrix, used bymany Ghostscript operators.</dl> <dl><dt><b><tt>gx_color_index</tt></b> (defined in <b><tt>gxdevice.h</tt></b>)<dd>This is meant to be whatever the driver uses to represent a devicecolor. For example, it might be an index in a color map, or it might be R,G, and B values packed into a single integer. Ghostscript doesn't ever doany computations with <b><tt>gx_color_index</tt></b> values: it gets themfrom <b><tt>map_rgb_color</tt></b> or <b><tt>map_cmyk_color</tt></b> andhands them back as arguments to several other procedures. The specialvalue <b><tt>gx_no_color_index</tt></b> (defined as<b><tt>(gx_color_index)(-1)</tt></b> ) means "transparent" for some ofthe procedures. The type definition is simply: <blockquote><b><tt>typedef unsigned long gx_color_index;</tt></b></blockquote></dl> <dl><dt><b><tt>gs_param_list</tt></b> (defined in <b><tt>gsparam.h</tt></b>)<dd>This is a parameter list, which is used to read and set attributes in adevice. See the comments in <b><tt>gsparam.h</tt></b>, and the<a href="#Parameters">description of the <b><tt>get_params</tt></b> and<b><tt>put_params</tt></b> procedures</a> below, for more detail.</dl> <dl><dt><b><tt>gx_tile_bitmap</tt></b> (defined in <b><tt>gxbitmap.h</tt></b>)<br><b><tt>gx_strip_bitmap</tt></b> (defined in <b><tt>gxbitmap.h</tt></b>)<dd>These structure types represent bitmaps to be used as a tile forfilling a region (rectangle). <b><tt>gx_tile_bitmap</tt></b> is an oldertype lacking <b><tt>shift</tt></b> and <b><tt>rep_shift</tt></b>;Lines 1–500 of 2483. Load more
<html> <head> <title>The interface between Ghostscript and device drivers</title> <!-- $Id: Drivers.htm,v 1.1 2000/03/09 08:40:39 lpd Exp $ --> <!-- Originally: drivers.txt --> </head> <body> <!-- [1.0 begin visible header] ============================================ --> <!-- [1.1 begin headline] ================================================== --> <table width="100%" border="0"> <tr><th align="center" bgcolor="#CCCC00"><font size=6> The interface between Ghostscript and device drivers </font> </table> <!-- [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> <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</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="#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> </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] ================================================== --> <h1><a name="Adding_drivers"></a>Adding a driver</h1> <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> <h1><a name="KISS"></a>Keeping things simple</h1> <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 <b><tt>gdevepsn.c</tt></b> and <b><tt>gdevbj10.c</tt></b> are good models for dot-matrix printers, which require presenting the data for many scan lines at once; the DeskJet/LaserJet drivers in <b><tt>gdevdjet.c</tt></b> 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, <b><tt>gdevcdj.c</tt></b> and <b><tt>gdevstc.c</tt></b>, 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. <b><tt>gdevepsn.c</tt></b> and <b><tt>gdevdjet.c</tt></b> are good examples of this approach. <hr> <h1><a name="Structure"></a>Driver structure</h1> <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 <b><tt>gxdevice.h</tt></b> or, if applicable, <b><tt>gdevprn.h</tt></b>. <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.) <h2><a name="Structure_definition"></a>Structure definition</h2> <p> You should consult the definition of struct <b><tt>gx_device_s</tt></b> in <b><tt>gxdevice.h</tt></b> 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 <b><tt>contrib.mak</tt></b>. <h2><a name="Sophisticated"></a>For sophisticated developers only</h2> <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 <b><tt>gxdevcli.h</tt></b>. <li>Possibly, the default forwarding procedures declared in <b><tt>gxdevice.h</tt></b> and implemented in <b><tt>gdevnfwd.c</tt></b>. <li>The device procedure record completion routines in <b><tt>gdevdflt.c</tt></b>. <li>Possibly, the default device implementation in <b><tt>gdevdflt.c</tt></b>, <b><tt>gdevddrw.c</tt></b>, and <b><tt>gxcmap.c</tt></b>. <li>The bounding box device in <b><tt>gdevbbox.c</tt></b> (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 <b><tt>gdevnfwd.c</tt></b>. <li>The command list "device" in <b><tt>gxclist.c</tt></b>. This is not an actual device; it only defines procedures. <li>The "memory" devices in <b><tt>gdevmem.h</tt></b> and <b><tt>gdevm*.c</tt></b>. <li>The halftoning device in <b><tt>gdevht.c</tt></b>. </ul> <li>The clip list accumulation "device" in <b><tt>gxacpath.c</tt></b>. <li>The clipping "devices" <b><tt>xclip.c</tt></b>, <b><tt>gxclip2.c</tt></b>, and <b><tt>gxclipm.c</tt></b>. <li>The pattern accumulation "device" in <b><tt>gxpcmap.c</tt></b>. <li>The hit detection "device" in <b><tt>gdevhit.c</tt></b>. <li>The generic printer device macros in <b><tt>gdevprn.h</tt></b>. <li>The generic printer device code in <b><tt>gdevprn.c</tt></b>. <li>The RasterOp source device in <b><tt>gdevmrop.c</tt></b>. </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 <b><tt>gsdparam.c</tt></b>. <p> You should not have to change any of the real devices in the standard Ghostscript distribution (listed in <b><tt>devs.mak</tt></b> and <b><tt>contrib.mak</tt></b>) or any of your own devices, because all of them are supposed to use the macros in <b><tt>gxdevice.h</tt></b> or <b><tt>gdevprn.h</tt></b> to define and initialize their state. <hr> <h1><a name="coordinates_and_types"></a>Coordinates and types</h1> <h2><a name="Coordinate_system"></a>Coordinate system</h2> <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 <b><tt>gxdevice.h</tt></b> are very helpful in doing this. <h2><a name="Color_definition"></a>Color definition</h2> <p> Ghostscript represents colors internally as RGB or CMYK values. In communicating with devices, however, it assumes that each device has a palette of colors identified by integers (to be precise, elements of type <b><tt>gx_color_index</tt></b>). Drivers may provide a uniformly spaced gray ramp or color cube for halftoning, or they may do their own color approximation, or both. <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>typedef struct gx_device_color_info_s { int num_components; /* 1 = gray only, 3 = RGB, */ /* 4 = CMYK */ int depth; /* # of bits per pixel */ gx_color_value max_gray; /* # of distinct gray levels -1 */ gx_color_value max_rgb; /* # of distinct color levels -1 */ /* (only relevant if num_comp. > 1) */ gx_color_value dither_gray; /* size of gray ramp for halftoning */ gx_color_value dither_rgb; /* size of color cube ditto */ /* (only relevant if num_comp. > 1) */ } gx_device_color_info;</pre> </blockquote> <p> The following macros (in <b><tt>gxdevice.h</tt></b>) provide convenient shorthands for initializing this structure for ordinary black-and-white or color devices: <blockquote> <b><tt>#define dci_black_and_white</tt></b> ...<br> <b><tt>#define dci_color(depth,maxv,dither)</tt></b> ... </blockquote> <p> The idea is that a device has a certain number of gray levels (<b><tt>max_gray</tt></b>+1) and a certain number of colors (<b><tt>max_rgb</tt></b>+1) that it can produce directly. When Ghostscript wants to render a given RGB or CMYK color as a device color, it first tests whether the color is a gray level (if <b><tt>num_components</tt></b> is 1, it converts all colors to gray levels), and if so: <blockquote> If <b><tt>max_gray</tt></b> is large (>= 31), Ghostscript asks the device to approximate the gray level directly. If the device returns a valid <b><tt>gx_color_index</tt></b>, Ghostscript uses it. Otherwise, Ghostscript assumes that the device can represent <b><tt>dither_gray</tt></b> distinct gray levels, equally spaced along the diagonal of the color cube, and uses the two nearest ones to the desired color for halftoning. </blockquote> <p> If the color is not a gray level: <blockquote> If <b><tt>max_rgb</tt></b> is large (>= 31), Ghostscript asks the device to approximate the color directly. If the device returns a valid <b><tt>gx_color_index</tt></b>, Ghostscript uses it. Otherwise, Ghostscript assumes that the device can represent <blockquote> <b><tt>dither_rgb</tt></b> × <b><tt>dither_rgb</tt></b> × <b><tt>dither_rgb</tt></b> </blockquote> <p> distinct colors, equally spaced throughout the color cube, and uses two of the nearest ones to the desired color for halftoning. </blockquote> <h2><a name="Types"></a>Types</h2> <p> Here is a brief explanation of the various types that appear as parameters or results of the drivers. <dl> <dt><b><tt>gx_color_value</tt></b> (defined in <b><tt>gxdevice.h</tt></b>) <dd>This is the type used to represent RGB or CMYK color values. It is currently equivalent to unsigned short. However, Ghostscript may use less than the full range of the type to represent color values: <b><tt>gx_color_value_bits</tt></b> is the number of bits actually used, and <b><tt>gx_max_color_value</tt></b> is the maximum value, equal to (2^<small><sup><b><tt>gx_max_color_value_bits</tt></b></sup></small>)-1. </dl> <dl> <dt><b><tt>gx_device</tt></b> (defined in <b><tt>gxdevice.h</tt></b>) <dd>This is the device structure, as explained above. </dl> <dl> <dt><b><tt>gs_matrix</tt></b> (defined in <b><tt>gsmatrix.h</tt></b>) <dd>This is a 2-D homogeneous coordinate transformation matrix, used by many Ghostscript operators. </dl> <dl> <dt><b><tt>gx_color_index</tt></b> (defined in <b><tt>gxdevice.h</tt></b>) <dd>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, or it might be R, G, and B values packed into a single integer. Ghostscript doesn't ever do any computations with <b><tt>gx_color_index</tt></b> values: it gets them from <b><tt>map_rgb_color</tt></b> or <b><tt>map_cmyk_color</tt></b> and hands them back as arguments to several other procedures. The special value <b><tt>gx_no_color_index</tt></b> (defined as <b><tt>(gx_color_index)(-1)</tt></b> ) means "transparent" for some of the procedures. The type definition is simply: <blockquote><b><tt> typedef unsigned long gx_color_index; </tt></b></blockquote> </dl> <dl> <dt><b><tt>gs_param_list</tt></b> (defined in <b><tt>gsparam.h</tt></b>) <dd>This is a parameter list, which is used to read and set attributes in a device. See the comments in <b><tt>gsparam.h</tt></b>, and the <a href="#Parameters">description of the <b><tt>get_params</tt></b> and <b><tt>put_params</tt></b> procedures</a> below, for more detail. </dl> <dl> <dt><b><tt>gx_tile_bitmap</tt></b> (defined in <b><tt>gxbitmap.h</tt></b>) <br><b><tt>gx_strip_bitmap</tt></b> (defined in <b><tt>gxbitmap.h</tt></b>) <dd>These structure types represent bitmaps to be used as a tile for filling a region (rectangle). <b><tt>gx_tile_bitmap</tt></b> is an older type lacking <b><tt>shift</tt></b> and <b><tt>rep_shift</tt></b>;