Go to the first, previous, next, last section, table of contents.


D.3 Epson inkjet printers

The `model_capabilities' vector in `print-escp2.c' contains one entry for each defined printer model. The `model' parameter in `printers.xml' is an index into this table.

In general, the new printers have fewer eccentricities than the older printers. That doesn't mean they're simpler, just that they're more consistent.

An escp2_printer_t is a C struct defined as follows:

Data type: escp2_printer_t
typedef struct escp2_printer
{
  model_cap_t	flags;		/* Bitmask of flags, see below */
  int 		nozzles;	/* Number of nozzles per color */
  int		nozzle_separation; /* Separation between rows, in 1/720" */
  int		black_nozzles;	/* Number of black nozzles (may be extra) */
  int		xres;		/* Normal distance between dots in */
				/* softweave mode (inverse inches) */
  int		max_paper_width; /* Maximum paper width, in points*/
  int		max_paper_height; /* Maximum paper height, in points */
  int		left_margin;	/* Left margin, points */
  int		right_margin;	/* Right margin, points */
  int		top_margin;	/* Absolute top margin, points */
  int		bottom_margin;	/* Absolute bottom margin, points */
  int		separation_rows; /* Some printers require funky spacing */
				/* arguments in microweave mode. */
  int		pseudo_separation_rows;/* Some printers require funky */
				/* spacing arguments in softweave mode */
  escp2_dot_size_t dot_sizes;	/* Vector of dot sizes for resolutions */
  escp2_densities_t densities;	/* List of densities for each printer */
  escp2_variable_inklist_t *inks; /* Choices of inks for this printer */
} escp2_printer_t;

Most of these should be self-explanatory. Some printers have more black nozzles than color nozzles, and it's possible for software to take advantage of that.

There is a convenient `INCH' macro defined to make specification of the max_paper_width and max_paper_height more legible. It multiplies 72 by the provided expression to get the appropriate number of points. For example, to specify 8.5", `INCH(17/2)' expands to `(72 * 17/2)', which is evaluated left to right, and hence generates the correct value.

Very, very few printers require (or allow) separation_rows to be anything but 1 and pseudo_separation_rows other than zero. The Stylus Color 1520, Stylus Color 800, Stylus Color 850, and (strangely enough to my mind, since it's a new printer) Stylus Color 660 seem to be the only exceptions.

The last three members of this struct are the most interesting, and require the most work. They are in order a vector of dot sizes for each printing mode, a list of base densities for each printing mode, and a pointer to a table of ink value definitions. These will be described individually.

The list of dot sizes contains values for seven printing modes: 180 DPI, 360 DPI "microweave" (which really means "not soft weave"), 360 DPI softweave, 720 DPI microweave, 720 DPI softweave, 1440 DPI microweave, and 1440 DPI softweave. The appropriate dot size is chosen from this vector at run time, and passed to the printer's set dot size command. Any value that is equal to `-1' indicates an illegal mode. For example, currently all printers have a value of `-1' for 180 DPI, because nothing really supports it properly. If someone can find a good dot size for it, some printers could do it.

Even single dot size printers can usually produce dots of different sizes; it's just illegal to actually try to switch dot size during a page. These dots are also much bigger than those used in true variable dot size printing.

Most printers support a dot size of `0' as a mode-specific default, but it's often a bigger dot than necessary. Printers usually also support some dot sizes between `1' and `3'. Usually `1' is the right dot size for 720 and 1440 dpi printing, and `3' works best at 360 dpi. Some printers claim to support `4' as a "super micro dot" for 1440 dpi printing, but it doesn't always work out that way. The Stylus Photo EX is such a printer. Setting a dot size of `4' in 360 dpi mode in fact produces smaller dots, but it's useless at such coarse resolution. However, setting a dot size of `4' in 720 or 1440 dpi mode produces the same size dot as size `0', and only size `1' produces a smaller dot.

Variable dot size printers usually support 2 or 3 sets of variable dot sizes. Older printers based on a 6 picolitre drop (the 480, 720, 740, 750, 900, and 1200) support two: mode 16 (0x10 in hexadecimal) for normal variable dots at 1440 or 720 dpi, and mode 17 (0x10) for special larger dots at 360 dpi. Newer printers based on 4 picolitre drops support three sizes: `0x10' for 4 pl base drops, `0x11' for 6 pl base drops, and `0x12' for special large drops. On these printers, `0x10' usually works best at 1440x720 and `0x11' works best at 720x720. Unfortunately, `0x10' doesn't seem to generate quite enough density at 720x720, because if it did the output would be very smooth. Perhaps it's possible to tweak things@enddots{}

The list of densities is a list of base density values for all of the above listed modes, plus 1440x1440 and 1440x2880 emulated. "Density" refers to the amount of ink deposited when a solid color (or solid black) is printed. So if the density is `.5', solid black actually prints only half the possible dots. "Base density" refers to the fact that the density value can be scaled in the GUI or on the Ghostscript command line. The density value specified is multiplied by the base density to obtain the effective density value. All other things (such as ink drop size) remaining the same, doubling the resolution requires halving the base density, which must never exceed `1'.

Tuning the density should be done on high quality paper (usually glossy photo paper). The goal is to find the lowest density value that results in solid black (no visible gaps under a fairly high power magnifying glass or loupe). If an appropriate density value is found for 720 DPI, it can be divided by 2 for 1440x720, by 4 for 1440x1440, and by 8 for 1440x2880.

However, for printers that offer a choice of dot size, this may not be the best strategy. The best choice for dot size is the smallest dot size that allows choosing a density value not greater than 1 that gives full coverage. This dot size may be different for different resolutions. Tuning variable dot size printers is more complicated; the process is described below.

The last member is a pointer to a structure containing a list of ink values for variable dot size (or 6 color) inks. We model variable dot size inks as producing a certain "value" of ink for each available dot size, where the largest dot size has a value of 1. 6-color inks are handled similarly; the light cyan and light magenta inks are treated as a fractional ink value. The combination of variable dot size and 6 color inks, of course, just creates that many more different ink choices.

This structure is actually rather complicated; it contains entries for each combination of physical printer resolution (180, 360, 720, and 1440 dpi), ink colors (4 and 6), and single and variable dot sizes (since some printer modes can't handle variable dot size inks). Since there's so much data, it's actually a somewhat deeply nested structure:

An escp2_printer_t contains a pointer (essentially, a reference rather than a copy) to an escp2_variable_inklist_t.

An escp2_variable_inklist_t contains pointers to escp2_variable_inkset_t structures. There is one such pointer for each combination of resolution, dot type, and ink colors as described above. Yes, this is rather inflexible.

An escp2_variable_inkset_t contains pointers to escp2_variable_ink_t structures. There is one such pointer for each of the four colors (C, M, Y, and K).

An escp2_variable_ink_t contains a pointer to the actual list of ink values (simple_dither_range_t), the number of ink values, and a density value to be used for computing the transitions. This density value is actually a scaling value; it is multiplied by the effective density to compute the density to be used for computing the transitions. Normally, this value is `1', but in some cases it may be possible to get smoother results with a different value (in particular, the single dot size 6-color inks work best with the effective density scaled to `.75' for this purpose). A lower density lowers the transition points, which results in more ink being deposited.

A simple_dither_range_t is a structure containing four values:

  1. The value of the particular ink
  2. The bit pattern used to represent the ink
  3. Whether the ink is light (0) or dark (1), for inks with light and dark variants
  4. The relative amount of ink actually deposited by this dot (not currently used for much; it can be used for ink reduction purposes, to reduce the amount of ink deposited on the paper).

These things are interesting as arrays. From an array of simple_dither_range_t's, the dither code computes transition values that it looks up at run time to decide what ink to print, as well as whether to print at all.

Really confused now? Yup. You'll probably find it easier to simply read the code.


Go to the first, previous, next, last section, table of contents.