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:
typedef struct escp2_printer { model_cap_t flags; /* Bitmask of flags, see below */ /*****************************************************************************/ int nozzles; /* Number of nozzles per color */ int min_nozzles; /* Minimum number of nozzles per color */ int nozzle_separation; /* Separation between rows, in 1/360" */ int black_nozzles; /* Number of black nozzles (may be extra) */ int min_black_nozzles; /* # of black nozzles (may be extra) */ int black_nozzle_separation; /* Separation between rows */ int fast_nozzles; /* Number of fast nozzles */ int min_fast_nozzles; /* # of fast nozzles (may be extra) */ int fast_nozzle_separation; /* Separation between rows */ /*****************************************************************************/ int xres; /* Normal distance between dots in */ /* softweave mode (inverse inches) */ int enhanced_xres; /* Distance between dots in highest */ /* quality modes */ int base_separation; /* Basic unit of row separation */ int base_resolution; /* Base hardware spacing (above this */ /* always requires multiple passes) */ int enhanced_resolution;/* Above this we use the */ /* enhanced_xres rather than xres */ int resolution_scale; /* Scaling factor for ESC(D command */ int max_black_resolution; /* Above this resolution, we */ /* must use color parameters */ /* rather than (faster) black */ /* only parameters*/ int max_hres; int max_vres; int min_hres; int min_vres; /*****************************************************************************/ int max_paper_width; /* Maximum paper width, in points */ int max_paper_height; /* Maximum paper height, in points */ int min_paper_width; /* Maximum paper width, in points */ int min_paper_height; /* Maximum paper height, in points */ /* Printer interleave: */ int m_left_margin; /* Left margin, points */ int m_right_margin; /* Right margin, points */ int m_top_margin; /* Absolute top margin, points */ int m_bottom_margin; /* Absolute bottom margin, points */ /* ROLL FEED: */ /* Softweave: */ int roll_left_margin; /* Left margin, points */ int roll_right_margin; /* Right margin, points */ int roll_top_margin; /* Absolute top margin, points */ int roll_bottom_margin; /* Absolute bottom margin, points */ /* Printer interleave: */ int m_roll_left_margin; /* Left margin, points */ int m_roll_right_margin; /* Right margin, points */ int m_roll_top_margin; /* Absolute top margin, points */ int m_roll_bottom_margin; /* Absolute bottom margin, points */ /*****************************************************************************/ int extra_feed; /* Extra distance the paper can be spaced */ /* beyond the bottom margin, in 1/360". */ /* (maximum useful value is */ /* nozzles * nozzle_separation) */ int separation_rows; /* Some printers require funky spacing */ /* arguments in interleave mode. */ int pseudo_separation_rows;/* Some printers require funky */ /* spacing arguments in softweave mode */ int zero_margin_offset; /* Offset to use to achieve */ /* zero-margin printing */ int initial_vertical_offset; int black_initial_vertical_offset; int extra_720dpi_separation; /*****************************************************************************/ const int *dot_sizes; /* Vector of dot sizes for resolutions */ const double *densities; /* List of densities for each printer */ const escp2_variable_inklist_t *inks; /* Choices of inks for this printer */ /*****************************************************************************/ const paperlist_t *paperlist; const res_t *reslist; const inklist_t *inklist; /*****************************************************************************/ const int *bits; const int *base_resolutions; const input_slot_list_t *input_slots; /*****************************************************************************/ const init_sequence_t *preinit_sequence; const init_sequence_t *postinit_remote_sequence; } escp2_printer_t;
The printer definition block is divided into 8 sections. The first section is a set of miscellaneous printer options. These are described in the code, and will not be discussed further here.
The second section describes the number of nozzles and the separation between nozzles in base units. The base unit is 1/360" for all currently supported printers, but future printers may support a smaller base unit.
Many printers have more black nozzles than nozzles of other colors, and when used in black and white mode, it's possible to use these extra nozzles, which speeds up printing. As an example, a printer that is specified to have 48 cyan, magenta, and yellow nozzles, and 144 black nozzles, can use all 144 black nozzles when printing black ink only. When printing in color, only 48 nozzles of each color (including black) can be used.
Most printers can print using either the number of nozzles available
or any smaller number. Some printers require that all of the nozzles
be used. Those printers will set min_nozzles
and/or
min_black_nozzles
to the same value as nozzles
and/or
black_nozzles
.
The third section defines basic units of measure for the printer, including the standard separation between dots, the base nozzle separation, and the minimum and maximum printing resolutions the printer supports. Most of these are fairly self-explanatory, but some are not obvious.
Most Epson printers, other than the high-end Stylus Pro models, cannot
print dots spaced more closely than 1/360" or 1/720" apart (this is
the setting for xres
. This is true even for printers that
support resolutions of 1440 or 2880 DPI. In these cases, the data
must be printed in 2, 4, or 8 passes. While the printer can position
the head to a resolution of 1/1440" or 1/2880", the head cannot
deposit ink that frequently.
Some printers can only print in their very best quality (using the
smallest dots available) printing at a lower resolution. For example,
the Stylus Photo EX can normally print with a dot spacing of 1/720".
The smallest dot size cannot be printed with a dot spacing of less
than 1/360", however. In this case, we use enhanced_xres
to specify the resolution to be used in this enhanced mode, and
enhanced_resolution
to specify the printing resolution above
which we use the enhanced_xres
.
The resolution_scale
command is used to specify scaling factors
for the dot separation on newer printers. It should always be 14400
with current printers.
The fourth section specifies the minimum and maximum paper sizes, and the margins. Some printers allow use of narrower margins when softweave is used; both sets of margins are specified.
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.
The fifth section specifies some miscellaneous values that are
required for certain printers. For most printers, the correct values
are 1 for separation_rows
and 0 for the others. 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 zero_margin_offset
is used to specify an additional
negative horizontal offset required to print to the edges of the paper
on newer Stylus Photo printers. These must be determined empirically;
good starting values are 100 for 1440 DPI and 50 for 2880 DPI
printers. The goal is to print to the edge of the page, but not over
it.
The sixth section specifies head offsets for printers that do not have the color jets aligned. Certain printers, such as the Stylus Color 480, have an unusual head arrangement whereby instead of all of the colors being aligned vertically, the nozzles are configured in groups. These printers are easy to determine; if the normal head offset of zero for each color is used, the printing will be vertically out of alignment. Most of these printers require specification of a negative offset for printing to the top edge of the paper; typically these printers do not require such an offset when printing black only.
The seventh section specifies the most difficult values to tune, the dot sizes, printing densities, and ink values (for variable dot size enabled printers). These will be described in detail below.
The last section specifies luminosity, hue, and saturation adjustment vectors for the printer, and the paper definitions. These are used to adjust the color in Photograph and Solid Colors output modes. These are each vectors of 48 (actually 49, as the first value must be duplicated) doubles that remap the luminosity, hue, and saturation respectively. The hue is calculated, and the value used to interpolate between the two closest points in each vector.
The paper definitions is a set of paper definitions. The paper definition contains the name of the paper type, special settings that are required for printers to process the paper correctly, and a set of adjustment values. These are not currently discussed here.
The lists of dot sizes and densities contain values for 13 printing modes: 120/180 DPI using printer weaving (single row; referred to as "interleave") and "soft" weaving (the driver determines the exact pattern of dot layout), 360 DPI interleave and softweave, 720x360 DPI interleave and softweave, 720 DPI interleave and softweave, 1440x720 interleave and softweave, 2880x720 interleave and softweave, and 2880x1440 softweave only.
For the dot sizes, the value for each element in the vector selects the dot size to be used when printing at this (or similar) resolution. The dot sizes are determined by consulting the programming manual for the printer and experimenting as described below. Current Epson printers always use dot sizes less than `16', or `0x10', to indicate single dot size (each dot is represented by 1 bit, and it's either printed or not), and dot sizes of `16' or greater to indicate variable dot size (each dot is represented by 2 bits, and it can either be not printed or take on 2 or 3 values, representing the relative size of the printed dot). Variable dot sizes permit the use of very small dots (which would be too small to fill the page and produce solid black) in light areas, while allowing the page to be filled with larger dots in darker areas.
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.
A dot size of `-1' indicates that this resolution is illegal for the printer in question. Any resolutions that would use this dot size will not be presented to the user. A dot size of `-2' indicates that this resolution is legal, but that the driver is not to attempt to set any dot size. Some very old printers do not support the command to set the dot size.
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.
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 normally 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. "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 (which is not made visible to the user) 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. The base density in the density vector may exceed `1', as many paper types require lower density than the base driver. The driver ensures that the actual density never exceeds 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 could be divided by 2 for 1440x720, by 4 for 2880x720, and by 8 for 2880x1440.
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, 6, and 7), 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:
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.