summaryrefslogtreecommitdiff
path: root/doc/developer/new-printer.xml
blob: 219a435f852f7ed151afa1731c2bef357332d507 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
<chapter>
  <title>Adding a new printer</title>
  <para>
    This chapter covers adding a new ESCP/2, PCL, or Canon printer.
    Writing a new driver module is not covered.
  </para>
  <para>
    The three steps to adding a printer are:
    <orderedlist>
      <listitem>
        <para>
          Add an entry to <filename>printers.xml</filename>.
        </para>
      </listitem>
      <listitem>
        <para>
          Add the appropriate code and data to the appropriate
          driver module.
        </para>
      </listitem>
      <listitem>
        <para>
          Tune the printer.
        </para>
      </listitem>
    </orderedlist>
  </para>
  <para>
    Printer information is stored in two places: in
    <filename>printers.xml</filename> (which contains the list of
    printer models available to the the upper-level application),
    and in the appropriate driver file
    (<filename>print-escp2.c</filename>,
    <filename>print-pcl.c</filename>, or
    <filename>print-canon.c</filename>).
  </para>
  <sect1>
    <title><filename>printers.xml</filename></title>
    <para>
      <filename>printers.xml</filename> is an XML file that contains
      very simple printer definitions.  A schema may be used to
      validate the XML (<filename>src/main/gutenprint.xsd</filename>).
      This is an example definition:
    </para>
    <informalexample>
      <programlisting>&lt;printer name="EPSON Stylus Color 1500" driver="escp2-1500"&gt;
&lt;color value="true"/&gt;
&lt;model value="2"/&gt;
&lt;gamma value="0.597"/&gt;
&lt;density value="1.0"/&gt;
&lt;/printer&gt;</programlisting>
    </informalexample>
    <para>
      There are other tags that may be present.  The only ones that
      are mandatory are <literal>&lt;printer&gt;</literal>,
      <literal>&lt;color&gt;</literal> and
      <literal>&lt;model&gt;</literal>.  The other optional parameters
      (<literal>&lt;gamma&gt;</literal> and
      <literal>&lt;density&gt;</literal> in this case) can be used to
      adjust control settings.  This is probably not the right place
      for them; the printer drivers themselves should contain this
      information.  There's probably no good reason for anything but
      gamma and density to be in here.  Gamma refers to the printer's
      gamma factor; density is the desired base ink density for the
      printer.  The Epson driver contains the density information for
      each printer at each resolution internally.  An even better
      driver would adjust density and possibly even gamma for paper
      type.  All the more reason not to have that information here.
    </para>
    <para>
      If you really are curious about what tags are permitted, please
      see the schema.  These are the definitions of the tags that do
      matter:
    </para>
    <variablelist>
      <title>printdef XML elements</title>
      <varlistentry>
        <term><literal>&lt;family&gt;</literal></term>
        <listitem>
          <para>
            This defines what driver module this printer uses.  The
            attribute <literal>name</literal> is the name of the
            family driver to associate the printers with, for example
            <literal>escp2</literal>, <literal>pcl</literal>,
            <literal>canon</literal>, <literal>ps</literal> or
            <literal>raw</literal>.  This tag may only contain
            <literal>&lt;printer&gt;</literal> elements.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term><literal>&lt;printer&gt;</literal></term>
        <listitem>
          <para>
            This starts the definition of a printer.  It must contain
            the attributes <literal>name</literal> and
            <literal>driver</literal>.  <literal>name</literal> should
            be is the full name of the printer, and must be human
            readable.  <literal>driver</literal> should consist of
            alphanumerics and hyphens, and be fairly short.
            <literal>name</literal> is what will appear in the
            user-visible listing of printers, and may be translated
            into the user's language, while <literal>driver</literal>
            is what is actually used to key into the list of printers.
            It is legal to have multiple printers with the same driver
            name.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term><literal>&lt;color&gt;</literal></term>
        <listitem>
          <para>
            This tag may not contain any content, but the
            <literal>value</literal> attribute may be set to
            <literal>true</literal> or <literal>false</literal>.  This
            indicates that this printer is capable of color, or is not
            capable of color respectively.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term><literal>&lt;model&gt;</literal></term>
        <listitem>
          <para>
            This defines a model number.  This tag may not contain any
            content, but the <literal>value</literal> attribute may be
            set to a positive integer.  This is passed into the
            driver, which may do whatever it cares to with
            it&mdash;index into a table, compute on, or whatever.
            This need not be unique.
          </para>
        </listitem>
      </varlistentry>
    </variablelist>
  </sect1>
  <sect1>
    <title>The driver file</title>
    <para>
      Adding a new printer to a driver module
      <filename>print-canon.c</filename>,
      <filename>print-escp2.c</filename>,
      <filename>print-lexmark.c</filename>, or
      <filename>print-pcl.c</filename> or
      (<filename>print-ps.c</filename> is really ad hoc) requires a
      bit more planning.  Each driver is somewhat different, but they
      all generally have a vector of printer definitions, and the code
      does some special casing based on particular printer
      capabilities.  The PCL and Canon drivers are quite similar; the
      Canon driver was actually cribbed from the PCL driver, but it
      then returned the favor.
    </para>
    <para>
      The Epson driver is a little bit different.  Canon and PCL
      printers have some amount of intelligence; a lot of them have
      specific ink options, and know about specific paper sizes and
      types, and must be told the right thing.  Epson printers have
      somewhat less intelligence and will more or less do exactly what
      the host tells it to do in a fairly regular fashion.  I actually
      prefer this; it isn't materially more work for the host to
      compute things like exact paper sizes and such, it allows a lot
      more tweaking, and it may be why Epson has been more open with
      information&mdash;the communication protocol doesn't really
      contain very much IP, so they have less reason to keep it
      secret.
    </para>
    <para>
      The sections about PCL and Canon printers need completing.
    </para>
    <sect2>
      <title>Epson inkjet printers</title>
      <para>
        The <varname>model_capabilities</varname> vector in
        <filename>print-escp2.c</filename> contains one entry for each
        defined printer model.  The <literal>model</literal> parameter
        in <filename>printers.xml</filename> is an index into this
        table.
      </para>
      <para>
        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.
      </para>
      <para>
        <type>escp2_printer_t</type> is a C struct defined as follows:
      </para>
      <informalexample>
        <programlisting>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           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 */
                              /* Softweave: */
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 */
                              /* "Micro"weave: */
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 */
/*****************************************************************************/
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 microweave 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 */
/*****************************************************************************/
               /* The stylus 480 and 580 have an unusual arrangement of
                                color jets that need special handling */
const int *head_offset;
int           initial_vertical_offset;
int           black_initial_vertical_offset;

/*****************************************************************************/
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 double *lum_adjustment;
const double *hue_adjustment;
const double *sat_adjustment;
const paperlist_t *paperlist;
} escp2_printer_t;</programlisting>
      </informalexample>
      <para>
        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.
      </para>
      <para>
        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.
      </para>
      <para>
        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.
      </para>
      <para>
        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
        <varname>min_nozzles</varname> and/or
        <varname>min_black_nozzles</varname> to the same value as
        <varname>nozzles</varname> and/or
        <varname>black_nozzles</varname>.
      </para>
      <para>
        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.
      </para>
      <para>
        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 <varname>xres</varname>.
        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.
      </para>
      <para>
        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 <varname>enhanced_xres</varname> to specify the
        resolution to be used in this enhanced mode, and
        <varname>enhanced_resolution</varname> to specify the printing
        resolution above which we use the
        <varname>enhanced_xres</varname>.
      </para>
      <para>
        The <varname>resolution_scale</varname> command is used to
        specify scaling factors for the dot separation on newer
        printers.  It should always be 14400 with current printers.
      </para>
      <para>
        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.
      </para>
      <para>
        There is a convenient <function>INCH</function> macro defined
        to make specification of the
        <varname>max_paper_width</varname> and
        <varname>max_paper_height</varname> more legible.  It
        multiplies <constant>72</constant> by the provided expression
        to get the appropriate number of points.  For example, to
        specify 8.5", <literal>INCH(17/2)</literal> expands to
        <literal>(72 * 17/2)</literal>, which is evaluated left to
        right, and hence generates the correct value.
      </para>
      <para>
        The fifth section specifies some miscellaneous values that are
        required for certain printers.  For most printers, the correct
        values are <constant>1</constant> for
        <varname>separation_rows</varname> and <constant>0</constant>
        for the others.  Very, very few printers require (or allow)
        <varname>separation_rows</varname> to be anything but
        <constant>1</constant> and
        <varname>pseudo_separation_rows</varname> other than
        <constant>0</constant>.  The Stylus Color 1520, Stylus Color
        800, Stylus Color 850, and (strangely enough to my mind, since
        it's a newer printer) Stylus Color 660 seem to be the only
        exceptions.
      </para>
      <para>
        <varname>zero_margin_offset</varname> 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
        <constant>100</constant> for 1440 DPI and
        <constant>50</constant> for 2880 DPI printers.  The goal is to
        print to the edge of the page, but not over it.
      </para>
      <para>
        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.
      </para>
      <para>
        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.
      </para>
      <para>
        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
        <emphasis>Photograph</emphasis> and <emphasis>Solid
        Colors</emphasis> 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.
      </para>
      <para>
        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.
      </para>
      <para>
        The lists of dot sizes and densities contain values for 13
        printing modes: 120/180 DPI using printer weaving (single row;
        incorrectly referred to as &ldquo;microweave&rdquo;) and
        &ldquo;soft&rdquo; weaving (the driver determines the exact
        pattern of dot layout), 360 DPI microweave and softweave,
        720&times;360 DPI microweave and softweave, 720 DPI microweave
        and softweave, 1440&times;720 microweave and softweave,
        2880&times;720 microweave and softweave, and 2880&times;1440
        softweave only.  Printer weaving is referred to as
        &ldquo;microweave&rdquo; for historical reasons.
      </para>
      <para>
        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 <constant>16</constant>
        (<constant>0x10</constant>), to indicate single dot size (each
        dot is represented by 1 bit, and it's either printed or not),
        and dot sizes of <constant>16</constant> 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.
      </para>
      <para>
        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.
      </para>
      <para>
        A dot size of <constant>-1</constant> 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 <constant>-2</constant> 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.
      </para>
      <para>
        Most printers support a dot size of <constant>0</constant> as
        a mode-specific default, but it's often a bigger dot than
        necessary.  Printers usually also support some dot sizes
        between <constant>1</constant> and <constant>3</constant>.
        Usually <constant>1</constant> is the right dot size for 720
        and 1440 DPI printing, and <constant>3</constant> works best
        at 360 DPI.
      </para>
      <para>
        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: <constant>0x10</constant> for 4 pl base
        drops, <constant>0x11</constant> for 6 pl base drops, and
        <constant>0x12</constant> for special large drops.  On these
        printers, <constant>0x10</constant> usually works best at
        1440&times;720 and <constant>0x11</constant> works best at
        720&times;720.  Unfortunately, <constant>0x10</constant>
        doesn't seem to generate quite enough density at
        720&times;720, because if it did the output would be very
        smooth.  Perhaps it's possible to tweak things&hellip;
      </para>
      <para>
        The list of densities is a list of base density values for all
        of the above listed modes.  &ldquo;Density&rdquo; refers to
        the amount of ink deposited when a solid color (or solid
        black) is printed.  So if the density is
        <constant>0.5</constant>, solid black actually prints only
        half the possible dots.  &ldquo;Base density&rdquo; refers to
        the fact that the density value can be scaled in the GUI or via
	CUPS options.  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
        <constant>1</constant>, as many paper types require lower
        density than the base driver.  The driver ensures that the
        actual density never exceeds <constant>1</constant>.
      </para>
      <para>
        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 1440&times;720, by 4 for 2880&times;720, and
        by 8 for 2880&times;1440.
      </para>
      <para>
        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 <constant>1</constant> 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.
      </para>
      <para>
        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
        &ldquo;value&rdquo; of ink for each available dot size, where
        the largest dot size has a value of <constant>1</constant>.
        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.
      </para>
      <para>
        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.
      </para>
      <itemizedlist>
        <listitem>
          <para>
            An <type>escp2_printer_t</type> contains a pointer
            (essentially, a reference rather than a copy) to an
            <type>escp2_variable_inklist_t</type>.
          </para>
        </listitem>
        <listitem>
          <para>
            An <type>escp2_variable_inklist_t</type> contains pointers
            to <type>escp2_variable_inkset_t</type> structures.  There
            is one such pointer for each combination of resolution,
            dot type, and ink colors as described above.  Yes, this is
            rather inflexible.
          </para>
        </listitem>
        <listitem>
          <para>
            An <type>escp2_variable_inkset_t</type> contains pointers
            to <type>escp2_variable_ink_t</type> structures.  There is
            one such pointer for each of the four colors (C, M, Y, and
            K).
          </para>
        </listitem>
        <listitem>
          <para>
            An <type>escp2_variable_ink_t</type> contains a pointer to
            the actual list of ink values
            (<type>simple_dither_range_t</type>), 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
            <constant>1</constant>, 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
            <constant>.75</constant> for this purpose).  A lower
            density lowers the transition points, which results in
            more ink being deposited.
          </para>
        </listitem>
        <listitem>
          <para>
            A <type>simple_dither_range_t</type> is a structure containing four values:
            <itemizedlist>
              <listitem>
                <para>
                  The value of the particular ink
                </para>
              </listitem>
              <listitem>
                <para>
                  The bit pattern used to represent the ink
                </para>
              </listitem>
              <listitem>
                <para>
                  Whether the ink is light (0) or dark (1), for inks
                  with light and dark variants
                </para>
              </listitem>
              <listitem>
                <para>
                  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).
                </para>
              </listitem>
            </itemizedlist>
          </para>
          <para>
            These things are interesting as arrays.  From an array of
            <type>simple_dither_range_t</type>'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.
          </para>
        </listitem>
      </itemizedlist>
      <para>
        <emphasis>Really</emphasis> confused now?  Yup.  You'll
        probably find it easier to simply read the code.
      </para>
    </sect2>
    <sect2>
      <title>Tuning the printer</title>
      <para>
        Now, how do you use all this to tune a printer?  There are a
        number of ways to do it; this one is my personal favorite.
      </para>
      <para>
        There's a file named <filename>test/cyan-sweep.tif</filename>.
        This consists of a thin bar of cyan sweeping from white to
        almost pure cyan, and from pure cyan to black.  The first
        thing to do is to pick the appropriate
        <type>simple_dither_range_t</type> (or create a whole new
        <type>escp2_variable_inklist_t</type>) and comment out all but
        the darkest ink (this means you'll be using the largest dots
        of dark ink).  At 8.5" width (the width of a letter-size piece
        of paper), the bar will be 1/8" high.  Printing it on wider or
        narrower paper will change the height accordingly.  Print it
        width-wise across a piece of photo quality paper in line art
        mode using ordered or adaptive hybrid dither.  Do not use
        photographic mode; the colors in photographic mode vary
        non-linearly depending upon the presence of the three color
        components, while in line art mode the colors are much purer.
        Make sure that all the color adjustments are set to defaults
        (1.0).  Use the highest quality version of the print mode
        you're testing to reduce banding and other artifacts.  This is
        much easier to do with the Gimp than with CUPS.
      </para>
      <para>
        At this stage, you want to look for four things:
        <orderedlist>
          <listitem>
            <para>
              The black near the center of the line is solid, but not
              more so than that.
            </para>
          </listitem>
          <listitem>
            <para>
              The cyan immediately to the left of the black is
              <emphasis>almost</emphasis> solid.
            </para>
          </listitem>
          <listitem>
            <para>
              The dark cyan at the far right of the page is solid, but
              not more so.  You can try tuning the density so that it
              isn't quite solid, then nudging up the density until it
              is.
            </para>
          </listitem>
          <listitem>
            <para>
              Both sweeps sweep smoothly from light to dark.  In
              particular, the dark half of the bar shouldn't visibly
              change color; it should go smoothly from cyan to black.
            </para>
          </listitem>
        </orderedlist>
      </para>
      <para>
        Repeat this stage until you have everything just right.  Use
        the positioning entry boxes in the dialog to position each bar
        exactly 1/8" further down the page.  Adjacent bars will be
        touching.
      </para>
      <para>
        The next step is to uncomment out the second darkest dot size.
        If you're using variable dots, use the second largest dot size
        of the dark ink rather than the largest dot size of the light
        ink.  This will give you two inks.
      </para>
      <para>
        When you recompile the plugin, you simply need to copy the new
        executable into the correct place.  You do not need to exit
        and restart the Gimp.
      </para>
      <para>
        Print another bar adjacent to the first one.  Your goal is to
        match the bar using a single dot size as closely as possible.
        You'll find that the dark region of the bar shouldn't change
        to any great degree, but the light half probably will.  If the
        lighter part of the light half is too dark, you need to
        increase the value of the smaller dot; if it's too light, you
        need to decrease the value.  The reasoning is that if the
        value is too low, the ink isn't being given enough credit for
        its contribution to the darkness of the ink, and vice versa.
        Repeat until you have a good match.  Make sure you let the ink
        dry fully, which will take a few minutes.  Wet ink will look
        too dark.  Don't look at the paper too closely; hold it at a
        distance.  The extra graininess of the largest dot size will
        probably make it look lighter than it should; if you hold it
        far enough away so that you can't see the dots, you'll get a
        more accurate picture of what's going on.
      </para>
      <para>
        After you have what looks like a good match, print another bar
        using only the largest dot size (or dark ink, for single dot
        size 6-color printers).  You want to ensure that the bars
        touching each other look identical, or as close as possible to
        it; your eye won't give you a good reading if the bars are
        separated from each other.  You'll probably have to repeat the
        procedure.
      </para>
      <para>
        The next step is to comment out all but the largest and
        third-largest dot size, and repeat the procedure.  When they
        match, use all three dot sizes of dark ink.  Again, the goal
        is to match the single dot size.
      </para>
      <para>
        You'll probably find the match is imperfect.  Now you have to
        figure out what region isn't right, which takes some
        experimentation.  Even small adjustments can make a noticeable
        difference in what you see.  At this stage, it's very
        important to hold the page far enough from your eye; when you
        use all three dot sizes, the texture will be much more even,
        which sometimes makes it look darker and sometimes lighter.
      </para>
      <para>
        After this is calibrated, it's time to calibrate the light ink
        against the dark ink.  To do this, comment out all but the
        large dot version of the two inks, and repeat the procedure.
        This is trickier, because the hues of the inks might not be
        quite identical.  Look at the dark half of the bar as well as
        the light half to see that the hue really doesn't change as
        you sweep from cyan to black.  Sometimes it's easier to judge
        that way.  You may find that it looks blotchy, in which case
        you should switch from ordered dither to adaptive hybrid.
      </para>
      <para>
        After you have the light and dark inks calibrated against each
        other, it's time to add everything back in.  Usually you don't
        want to use the largest dot size of light ink.  These dots
        will be much larger than the small dots of dark ink, but
        they'll still be lighter.  This will cause problems when
        printing mixed colors, since you'll be depositing more ink on
        lighter regions of the page, and you'll probably get strange
        color casts that you can't get rid of in neutral tones.  I
        normally use only the smallest one or two dot sizes of light
        ink.
      </para>
      <para>
        After you've tweaked everything, print the color bar with
        saturation set to zero.  This will print neutral tones using
        color inks.  Your goal here is to look for neutral tonality.
        If you're using a 6-color printer and get a yellow cast, it
        means that the values for your light inks are too high
        (remember, that means they're getting too much credit, so
        you're not depositing enough cyan and magenta ink, and the
        yellow dominates).  If you get a bluish or bluish-purple cast,
        your light inks are too low (you're not giving them enough
        credit, so too much cyan and magenta is deposited, which
        overwhelms the yellow).  Make sure you do this on very white,
        very high grade inkjet paper that's designed for
        1440&times;720 DPI or higher; otherwise the ink will spread on
        contact and you'll get values that aren't really true for high
        grade paper.  You can, of course, calibrate for low grade
        paper if that's what you're going to use, but that shouldn't
        be put into the distribution.
      </para>
      <para>
        You can also fully desaturate this bar inside the Gimp and
        print it as monochrome (don't print the cyan as monochrome;
        the driver does funny things with luminance), for comparison.
        You'll find it very hard to get rid of all color casts.
      </para>
      <para>
        There are other ways of tuning printers, but this one works
        pretty well for me.
      </para>
    </sect2>
    <sect2>
      <title>Canon inkjet printers</title>
      <para>
        Basically, a new Canon printer can be added to
        <filename>print-canon.c</filename> in a similar way as
        described above for the epson inkjet printers. The main
        differences are noted here.
      </para>
      <para>
        In general, Canon printers have more &ldquo;built-in
        intelligence&ldquo; than Epson printers which results in the
        fact that the driver only has to tell the printing conditions
        like resolutions, dot sizes, etc. to the printer and
        afterwards transfer the raster data line by line for each
        color used.
      </para>
      <para>
        <type>canon_cap_t</type> is a C struct defined as follows:
      </para>
      <informalexample>
        <programlisting>typedef struct canon_caps {
int model;          /* model number as used in printers.xml */
int max_width;      /* maximum printable paper size */
int max_height;
int base_res;       /* base resolution - shall be 150 or 180 */
int max_xdpi;       /* maximum horizontal resolution */
int max_ydpi;       /* maximum vertical resolution */
int max_quality;
int border_left;    /* left margin, points */
int border_right;   /* right margin, points */
int border_top;     /* absolute top margin, points */
int border_bottom;  /* absolute bottom margin, points */
int inks;           /* installable cartridges (CANON_INK_*) */
int slots;          /* available paperslots */
int features;       /* special bjl settings */
canon_dot_size_t dot_sizes;   /* Vector of dot sizes for resolutions */
canon_densities_t densities;  /* List of densities for each printer */
canon_variable_inklist_t *inxs; /* Choices of inks for this printer */
} canon_cap_t;</programlisting>
      </informalexample>
      <para>
        Since there are Canon printers which print in resolutions of
        2<superscript>n</superscript> &times; 150 DPI (e.g. 300, 600,
        1200) and others which support resolutions of
        2<superscript>n</superscript> &times; 180 DPI (e.g. 360, 720,
        1440), there's a base resolution (150 or 180, respectively)
        given in the <type>canon_cap_t</type>. The structs
        <type>canon_dot_size_t</type>, <type>canon_densities_t</type>
        and <type>canon_variable_inklist_t</type> refer to resolutions
        being multiples of the base resolution.
      </para>
      <para>
        For the Canon driver, the struct <type>canon_dot_size_t</type>
        holds values for a model's capabilities at a given resolution,
        or <constant>-1</constant> if the resolution is not supported.
        <constant>0</constant> if it can be used and
        <constant>1</constant> if the resolution can be used for
        variable dot size printing.
      </para>
      <para>
        In <type>canon_densities_t</type> the base densities for each
        resolution can be specified like for an epson printer.  The
        same holds true for <type>canon_variable_inklist_t</type>.
        See the descriptions above to learn about how to adjust your
        model's output to yield nice results.
      </para>
      <para>
        There's a slight difference though in the way the Canon driver
        and the escp2 driver define their variable inklists: In the
        Canon driver, you need to define an inklist like this:
      </para>
      <informalexample>
        <programlisting>static const canon_variable_inklist_t canon_ink_myinks[] =
{
{
  1,4, /* 1bit/pixel, 4 colors */
  &amp;ci_CMYK_1, &amp;ci_CMYK_1, &amp;ci_CMYK_1,
  &amp;ci_CMYK_1, &amp;ci_CMYK_1, &amp;ci_CMYK_1,
},
{
  3,4, /* 3bit/pixel, 4 colors */
  &amp;ci_CMYK_3, &amp;ci_CMYK_3, &amp;ci_CMYK_3,
  &amp;ci_CMYK_3, &amp;ci_CMYK_3, &amp;ci_CMYK_3,
},
};</programlisting>
      </informalexample>
      <para>
        where the <literal>&amp;ci_CMYK_1</literal> and
        <literal>&amp;ci_CMYK_3</literal> entries are references to a
        previously defined const of type
        <type>canon_variable_inkset_t</type>.
      </para>
    </sect2>
  </sect1>
</chapter>