1 /*
2  * Lexmark 3200 Color Jetprinter driver
3  *
4  * version 0.4.1
5  *
6  * Copyright 2000 by Daniel Gordini (dgordin@tin.it)
7  *
8  * --------------------------------------------------------------------
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * --------------------------------------------------------------------
25  *
26  * This driver is almost 100% original code but it is based
27  * on protocol information partly discovered by Andrew Onifer III
28  * (http://www.mindspring.com/~aonifer) and Peter B. West
29  * (http://www.powerup.com.au/~pbwest) that were used as a starting
30  * base for the reverse-engineering of the protocol.
31  *
32  * Please mail me bug reports, comments and suggestions.
33  *
34  * Don't forget to read the release notes before installing !!
35  *
36  */
37 
38 #include "gdevprn.h"
39 #include "gsparams.h"
40 
41 #ifndef TRUE
42 #define TRUE  1
43 #endif
44 
45 #ifndef FALSE
46 #define FALSE 0
47 #endif
48 
49 /* Prototypes for public routines */
50 static dev_proc_map_rgb_color(lxm3200_map_rgb_color);
51 static dev_proc_map_color_rgb(lxm3200_map_color_rgb);
52 static dev_proc_print_page(lxm3200_print_page);
53 static dev_proc_get_params(lxm3200_get_params);
54 static dev_proc_put_params(lxm3200_put_params);
55 static dev_proc_open_device(lxm3200_open);
56 
57 /* Prototypes for internal routines */
58 static void freeresources(gx_device *pdev);
59 static byte calccheck8(byte *data);
60 static void outputepilogue(void);
61 static void skiplines(int skipcol, int skipin);
62 static void fillheader(int head, int numcol, int firstcol, int bytes);
63 static void finalizeheader(int vskip, int newhead);
64 static void convbuf(int head, int numcols, int firstcol);
65 static void encode_bw_buf(void);
66 static void encode_col_buf(int head);
67 static int fill_mono_buffer(int vline);
68 static int init_buffer(void);
69 static int qualify_buffer(void);
70 static int roll_buffer(void);
71 static void calclinemargins(byte *data, int mask, int *left, int *right);
72 static void calcbufmargins(int head);
73 static void print_color_page(void);
74 static void print_mono_page(void);
75 static void print_photo_page(void);
76 
77 /* Codes for the color indexes. */
78 #define WHITE        0x00  /* Pure white */
79 #define MAGENTA      0x01  /* Standard magenta */
80 #define CYAN         0x02  /* Standard cyan */
81 #define YELLOW       0x04  /* Standard yellow */
82 #define LIGHTCYAN    0x10  /* Light cyan (photo mode) */
83 #define LIGHTMAGENTA 0x20  /* Light magenta (photo mode) */
84 #define BLACK        0x40  /* Pure black */
85 
86 /* Modes for rendering: used by the common procedures to
87  * discriminate from mono to color and photo modes.
88  */
89 #define LXM3200_M  0  /* Monochrome mode */
90 #define LXM3200_C  1  /* Standard color mode */
91 #define LXM3200_P  2  /* Photo color mode */
92 
93 /* Initial horizontal position for the printheads,
94  * in 1200ths of an inch. Note that "left" and "right"
95  * head here refers to paper margin, and so looking at
96  * them from the front of printer they will appear reversed.
97  */
98 
99 /* Left head (B&W/photo) start position */
100 #define LHSTART (gendata.leftoffset+6254)
101 /* added for Lexmark Z12 28.09.2002 */
102 #define LHSTART_z12 (gendata.leftoffset+5000)
103 
104 /* Right head (color) start position. This is relative to
105  * LHSTART so we only need to change one parameter to adjust
106  * the head starting position. In the case of the Lexmark Z12
107  * we have only one cartridge: black or color, so
108  * LHSTART_Z12 = RHSTART_Z12
109  */
110 #define RHSTART (LHSTART-2120)
111 #define RHSTART_z12 (LHSTART_z12) /* added for Lexmark Z12 28.9.2002 */
112 
113 /* Difference in starting position between left-to-right
114  * and right-to-left passes, in 1200ths of an inch.
115  * Obviously only used in bidirectional mode.
116  */
117 #define LRPASSHOFS 62
118 
119 /* Initial vertical position of the printheads,
120  * in 1200ths of an inch.
121  */
122 #define BWTOPSTART  (gendata.topoffset+420)
123 #define COLTOPSTART (gendata.topoffset+476)
124 
125 /* Base alignment offset between the color cartridge
126  * and the B&W cartridge in 192 nozzles mode.
127  */
128 #define COLORVALIGN_V  8
129 #define BLACKVALIGN_V  (gendata.vertalign+30)
130 #define PHOTOVALIGN_V  (gendata.vertalign)
131 
132 /* Values used to index the vertical aligment array */
133 #define COLORVALIGN  0
134 #define BLACKVALIGN  1
135 #define PHOTOVALIGN  2
136 
137 /* Offset of color pens from first row, in 1/600ths of an inch.
138  * Pen 0 is the topmost and is the CYAN or LIGHTCYAN pen (depending
139  * on the cartridge: standard color or photo). Pen 1 is the middle
140  * one, which carries MAGENTA or LIGHTMAGENTA color. Pen 2 is the
141  * bottom one, which is YELLOW or BLACK.
142  */
143 #define PEN0OFS  0
144 #define PEN1OFS  92
145 #define PEN2OFS  184
146 
147 /* Number of nozzles in each pen type */
148 #define COLORPEN 64   /* Each color pen of a color/photo cartridge */
149 #define BWCOLPEN 192  /* Black cartridge used in color or 1200dpi modes */
150 #define BWSTDPEN 208  /* Black cartridge used in mono non-1200dpi mode */
151 
152 /* Values used by the color mapping routines */
153 #define HALFTONE (gx_max_color_value/2)
154 #define FULLTONE (gx_max_color_value)
155 #define ONETHIRD (FULLTONE/3)
156 #define TWOTHIRD ((2*FULLTONE)/3)
157 
158 /* Printer head and printing direction selectors */
159 #define LEFT   0 /* Left head (B/W or photo) or left-to-right direction */
160 #define RIGHT  1 /* Right head (colour) or right-to-left direction */
161 
162 /* Qualificators for the scan buffer */
163 #define LAST   0x01 /* The buffer is the last on the page */
164 #define LHDATA 0x02 /* The buffer contains data for the left head */
165 #define RHDATA 0x04 /* The buffer contains data for the right head */
166 
167 /* Printer's margins, in inches. The Lexmark 3200 has two settings
168  * for the side margins: one is used with A4-sized paper and one
169  * (here called conventionally "LETTER") is used for all other paper
170  * sizes. Envelopes have different margins as well, but under ghostscript
171  * it's quite hard to know, from inside a printer driver, if we are
172  * printing on envelopes or on standard paper, so we just ignore that.
173  */
174 #define LXM3200_TOP_MARGIN           0.070
175 #define LXM3200_BOTTOM_MARGIN        0.200
176 #define LXM3200_A4_LEFT_MARGIN       0.135
177 #define LXM3200_LETTER_LEFT_MARGIN   0.250
178 #define LXM3200_A4_RIGHT_MARGIN      0.135
179 #define LXM3200_LETTER_RIGHT_MARGIN  0.250
180 
181 /* Offsets for the top and bootom start of the printing frame. */
182 #define LXM3200_A4_TOPOFFSET       84
183 #define LXM3200_A4_LEFTOFFSET      162
184 #define LXM3200_LETTER_TOPOFFSET   84
185 #define LXM3200_LETTER_LEFTOFFSET  300
186 
187 /*
188  * ------ The device descriptor ------
189  */
190 
191 /* Device procedures */
192 static gx_device_procs lxm3200_procs =
193   prn_color_params_procs(lxm3200_open, gdev_prn_output_page, gdev_prn_close,
194           lxm3200_map_rgb_color, lxm3200_map_color_rgb, lxm3200_get_params,
195     lxm3200_put_params);
196 
197 /* Define an extension (subclass) of gx_device_printer. */
198 typedef struct lxm_device_s
199 {
200         gx_device_common;
201         gx_prn_device_common;
202         int rendermode;  /* Rendering mode (BW, CMYK, CcMmYK) */
203         int algnA; /* Horizontal alignment between left and right cartridges */
204         int algnB; /* Vertical alignment between left and right cartridges */
205         int algnC; /* Nozzle column separation of left cartridge */
206         int algnD; /* Nozzle column separation of right cartridge */
207         int bidir;   /* Bidirectional printing active ? */
208         int numpass; /* Number of head passes for each stripe */
209         int leftoffset; /* Offset of first column from left side of paper */
210         int topoffset;  /* Offset of first row from top of paper */
211         int model; /* Parameter to choose the model - lxm3200=0, z12=1, z31=2 */
212         int z31m; /* Alignment parameter for the Z31 */
213 } lxm_device;
214 
215 /* Device definition: Lexmark 3200 */
216 lxm_device far_data gs_lxm3200_device =
217 {
218         prn_device_body(lxm_device,
219                 lxm3200_procs,
220                 "lxm3200",
221                 DEFAULT_WIDTH_10THS,
222                 DEFAULT_HEIGHT_10THS,
223                 600, /* default x dpi */
224                 600, /* default y dpi */
225                 0.0, /* left margin, inches (filled-in later) */
226                 0.0, /* bottom margin, inches (filled-in later) */
227                 0.0, /* right margin, inches (filled-in later) */
228                 0.0, /* top margin, inches (filled-in later) */
229                 1,   /* number of color components (mono) */
230                 8,   /* bits per pixel */
231                 1,   /* number of gray levels-1: B&W only */
232                 0,   /* number of color levels-1: no color */
233                 2,   /* dither gray: maximum 2 distinct gray levels */
234                 0,   /* dither rgb: no RGB dithering in this mode */
235                 lxm3200_print_page),
236         LXM3200_C,      /* default printing mode */
237         16, 8, 16, 16,  /* default aligment parameters value */
238         0, 1,           /* default bidirectional and numpasses value */
239         0, 0,           /* left and top offsets (filled-in later) */
240         0,     /* default model = Lexmark 3200 */
241         100   /* default z31m */
242 };
243 
244 /* --------- Static data --------- */
245 
246 /* Lookup tables to speed up bitwise operations */
247 static byte bits[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
248 static byte ibits[8] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
249 
250 /* Lookup table for masking color pens in color/photo cartridges.
251  * This is used to check the raster buffer for the presence of a
252  * particular color in the pixel we are encoding.
253  * The first index is the head (LEFT or RIGHT) which is used to
254  * distinguish between photo and color cartridges. The second index
255  * is the pen number (0 is the upper pen, 1 the middle pen, 2 the
256  * lower pen) on that cartridge.
257  */
258 static byte colmask[2][3] =
259 {
260         { LIGHTCYAN, LIGHTMAGENTA, BLACK},
261         { CYAN, MAGENTA, YELLOW }
262 };
263 
264 /* Lookup table for pen position offsets of color/photo cartridges.
265  * Parameter is the pen number, as defined by the pen offsets above:
266  * pen 0 is CYAN/LIGHTCYAN, pen 1 is MAGENTA/LIGHTMAGENTA, pen 2 is
267  * YELLOW/BLACK. This is used to properly take account the position
268  * of each color pen relative to the vertical position of the
269  * color/photo cartridge.
270  */
271 static int penofs[3];
272 
273 /* Lookup table for vertical alignment of the cartridges relative to
274  * each other. Parameter is the cartridge type: 0 = color cartridge,
275  * 1 = black cartridge in color mode, 2 = photo cartridge.
276  * Black cartridge in monochromatic mode is always aligned at 0
277  * because in that mode we print with only one cartridge so there can
278  * be no alignment problems (a single cartridge is always aligned
279  * with itself, otherwise the printer tray is faulty).
280  */
281 static int valign[3];
282 
283 /* Lookup table for horizontal offsets. First parameter is the
284  * head, second parameter the printing direction.
285  */
286 static int hoffset[2][2];
287 
288 /* Initialization sequence needed at the beginning of the data stream.
289  * This is invariant and contains a reset sequence, meaning each single
290  * page in a multiple page output is sent to the printer as an independent
291  * print job.
292  */
293 static byte init_sequence[] =
294 {
295         0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
296         0x1b, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
297         0x1b, 0x30, 0x80, 0x0C, 0x02, 0x00, 0x00, 0xbe,
298         0x1b, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21
299 };
300 
301 static byte z12_init_sequence[] =
302 {
303         0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
304         0x1b, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
305         0x1b, 0x63, 0x00, 0x01, 0x40, 0x02, 0x0d, 0xb3,
306         0x1b, 0x30, 0x80, 0x0c, 0x01, 0x00, 0x00, 0xbd,
307         0x1b, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21
308 };
309 
310 /* General global data that must be accessible
311  * by all routines.
312  */
313 typedef struct pagedata_s
314 {
315         /* General invariant data */
316         int numbytes;    /* Number of bytes in a scanline of the buffer */
317         int numrbytes;   /* Width (in bytes) of one rasterized scanline */
318         int goffset;     /* Guard offset at each side of each scanline (columns) */
319         int numblines;   /* Number of lines in a buffer */
320         int numlines;    /* Number of lines in a vertical head pass */
321         int rendermode;  /* Type of rendering */
322         int numvlines;   /* Number of lines in the page */
323         int numcols;     /* Number of columns in a row */
324         int numpasses;   /* Number of passes used to print one stripe */
325         int bidirprint;  /* Bidirectional printing enabled ? */
326         int select;      /* Resolution selector */
327         int modelprint;  /* which printer? - lxm3200=0, z12=1, z31=2 */
328         int z31margin;   /* margin for the Z31 */
329 
330         /* Printing offsets */
331         int leftoffset;  /* Start printing offset from left margin */
332         int topoffset;   /* Start printing offset from top margin */
333 
334         /* Resolution settings */
335         int xres;        /* Horizontal dots per inch */
336         int yres;        /* Vertical dots per inch */
337         int xrmul;       /* Horizontal coordinate multiplier */
338         int yrmul;       /* Vertical coordinate multiplier */
339 
340         /* Pagewide status */
341         int curheadpos;  /* Current absolute printhead position */
342         int linetoeject; /* Number of lines for the eject command */
343         int direction;   /* Printing direction for next stripe */
344 
345         /* Alignment data */
346         int bwsep;     /* Nozzle columns separation in B&W/photo cartridge */
347         int colsep;    /* Nozzle columns separation in color cartridge */
348         int vertalign; /* Vertical alignment offset of the two cartridges */
349         int lrhalign;  /* Horizontal alignment between left and right cartridges */
350 
351         /* Data pointers */
352         byte *outdata;    /* Buffer to output data codes for one full stripe */
353         byte *scanbuf;    /* Buffer to contain the rasterized scanlines */
354         FILE *stream;     /* Output stream */
355         lxm_device *dev;  /* Pointer to our device */
356 
357         /* Buffer data */
358         int left, right;  /* Actual left and right margins */
359         int firstline;    /* Head of the circular scanline buffer */
360         int lastblack;    /* Line of last black pass rendered in a color print */
361         int curvline;     /* Current vertical position */
362 
363         /* Stripe related data */
364         byte header[24];  /* Stripe header data */
365         int  fullflag;    /* A stripe is ready to be output */
366         int  stripebytes; /* Number of bytes in a stripe */
367         int  ileave;      /* Interleaving pass: 0=even lines, 1=odd lines */
368 
369 } pagedata;
370 
371 static pagedata gendata;
372 
373 /* --------- Interface routines --------- */
374 
375 /* Function called by ghostscript to open the
376  * printer device. We set the margins and offsets
377  * here. Note that to guess which paper is loaded
378  * into the printer, we calculate the line width
379  * and then anything between 8.25 and 8.4 inches
380  * is considered to be A4.
381  * This routine is inspired by the omologous
382  * routine from the "gdevbj10" driver.
383  */
384 static int
lxm3200_open(gx_device * pdev)385 lxm3200_open(gx_device *pdev)
386 {
387         float linewidth;
388 
389         static const float a4_margins[4] =
390         {
391                 LXM3200_A4_LEFT_MARGIN, LXM3200_BOTTOM_MARGIN,
392                 LXM3200_A4_RIGHT_MARGIN, LXM3200_TOP_MARGIN
393         };
394 
395         static const float letter_margins[4] =
396         {
397                 LXM3200_LETTER_LEFT_MARGIN, LXM3200_BOTTOM_MARGIN,
398                 LXM3200_LETTER_RIGHT_MARGIN, LXM3200_TOP_MARGIN
399         };
400 
401         linewidth = (float)(pdev->width) / (float)(pdev->x_pixels_per_inch);
402 
403         if(linewidth >= 8.25 && linewidth <= 8.4)
404         {
405                 gx_device_set_margins(pdev, a4_margins, true);
406                 ((lxm_device *)pdev)->topoffset = LXM3200_A4_TOPOFFSET;
407                 ((lxm_device *)pdev)->leftoffset = LXM3200_A4_LEFTOFFSET;
408         }
409         else
410         {
411                 gx_device_set_margins(pdev, letter_margins, true);
412                 ((lxm_device *)pdev)->topoffset = LXM3200_LETTER_TOPOFFSET;
413                 ((lxm_device *)pdev)->leftoffset = LXM3200_LETTER_LEFTOFFSET;
414         }
415 
416         return gdev_prn_open(pdev);
417 }
418 
419 /* Function used by ghostscript to map a RGB
420  * value to the driver's internal representation
421  * of the nearest color.
422  */
423 static gx_color_index
lxm3200_map_rgb_color(gx_device * dev,const gx_color_value cv[])424 lxm3200_map_rgb_color(gx_device *dev, const gx_color_value cv[])
425 {
426         gx_color_index col;
427         gx_color_value r, g, b;
428         int c, m, y;
429         gx_color_value tmpcv[3];
430 
431         r = cv[0]; g = cv[1]; b = cv[2];
432         /* In case R, G and B values are equal, ghostscript
433          * prescribes that the color value must be turned
434          * into a gray shade. In our case this means either
435          * black or white
436          */
437         if(r == g && r == b)
438         {
439                 if(r > HALFTONE)
440                         return(WHITE);
441                 else
442                         return(BLACK);
443         }
444 
445         /* Calculate CMY values from RGB. This is *overly*
446          * simple, but it's enough to print something.
447          */
448         c = FULLTONE - r;
449         m = FULLTONE - g;
450         y = FULLTONE - b;
451 
452         /* Now encode the calculated color into the internal
453          * format. This means simply to turn on or off the
454          * bits representing each color depending on the value
455          * of the appropriate CMY component.
456          * Note that we are not doing black separation or any
457          * other fancy stuff: this is spartane code just to
458          * make the printer work.
459          */
460         col = 0;
461         if(y > HALFTONE)col |= YELLOW;
462 
463         switch(((lxm_device *)dev)->rendermode)
464         {
465                 case LXM3200_C:
466                         if(c > HALFTONE)col |= CYAN;
467                         if(m > HALFTONE)col |= MAGENTA;
468                         break;
469 
470                 case LXM3200_P:
471                         if(c > TWOTHIRD)
472                                 col |= CYAN;
473                         else
474                                 if(c > ONETHIRD)col |= LIGHTCYAN;
475 
476                         if(m > TWOTHIRD)
477                                 col |= MAGENTA;
478                         else
479                                 if(m > ONETHIRD)col |= LIGHTMAGENTA;
480                         break;
481 
482                 default:
483                         tmpcv[0] = r; tmpcv[1] = g; tmpcv[2] = b;
484                         col = gdev_prn_map_rgb_color(dev, tmpcv);
485                         break;
486         }
487 
488         return(col);
489 }
490 
491 /* Function called by ghostscript to map the
492  * internal representation of a color to a
493  * RGB value.
494  */
495 static int
lxm3200_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])496 lxm3200_map_color_rgb(gx_device *dev, gx_color_index color,
497                                                                                         gx_color_value prgb[3])
498 {
499         int c, m, y;
500 
501         if(color == WHITE)
502         {
503                 prgb[0] = FULLTONE;
504                 prgb[1] = FULLTONE;
505                 prgb[2] = FULLTONE;
506                 return(0);
507         }
508 
509         if(color & BLACK)
510         {
511                 prgb[0] = 0;
512                 prgb[1] = 0;
513                 prgb[2] = 0;
514                 return(0);
515         }
516 
517         /* Calculate back CMY components from the internal
518          * representation of the color
519          */
520         c = 0;
521         m = 0;
522         y = 0;
523 
524         switch(((lxm_device *)dev)->rendermode)
525         {
526                 case LXM3200_C:
527                         color &= (CYAN|MAGENTA|YELLOW);
528                         if(color & CYAN)c = 2;
529                         if(color & MAGENTA)m = 2;
530                         if(color & YELLOW)y = 2;
531                         break;
532 
533                 case LXM3200_P:
534                 default:
535                         color &= (CYAN|MAGENTA|YELLOW|LIGHTCYAN|LIGHTMAGENTA);
536                         if(color & LIGHTCYAN)c = 1;
537                         if(color & LIGHTMAGENTA)m = 1;
538                         if(color & YELLOW)y = 2;
539                         if(color & CYAN)c = 2;
540                         if(color & MAGENTA)m = 2;
541                         break;
542         }
543 
544         /* And now turn CMY to RGB, in the usual spartane way */
545 
546         prgb[0] = (gx_color_value)((2 - c) * HALFTONE);
547         prgb[1] = (gx_color_value)((2 - m) * HALFTONE);
548         prgb[2] = (gx_color_value)((2 - y) * HALFTONE);
549 
550         return(0);
551 }
552 
553 /* Main routine of the driver. This takes care of
554  * all parameters and static data initialization
555  * and calls the proper page printing routines
556  * depending on the selected printing mode.
557  */
558 static int
lxm3200_print_page(gx_device_printer * pdev,FILE * prn_stream)559 lxm3200_print_page(gx_device_printer *pdev, FILE *prn_stream)
560 {
561         /* Store data passed by ghostscript to the driver */
562         gendata.dev = (lxm_device *)pdev;
563         gendata.stream = prn_stream;
564         gendata.rendermode = (gendata.dev)->rendermode;
565 
566         /* Snap resolution on one of the three supported setting
567          * (300, 600, 1200 dpi) depending on the input resoution value.
568          * Horizontal and vertical resolution are treated independently.
569    */
570         gendata.xres = 600;
571         if((gendata.dev)->x_pixels_per_inch < 450)gendata.xres = 300;
572         if((gendata.dev)->x_pixels_per_inch > 900)gendata.xres = 1200;
573         gendata.xrmul = 1200 / gendata.xres;
574 
575         gendata.yres = 600;
576         if((gendata.dev)->y_pixels_per_inch < 450)gendata.yres = 300;
577         if((gendata.dev)->y_pixels_per_inch > 900)gendata.yres = 1200;
578         gendata.yrmul = 1200 / gendata.yres;
579 
580         /* Cache horizontal and vertical starting offsets */
581         gendata.topoffset = (gendata.dev)->topoffset;
582         gendata.leftoffset = (gendata.dev)->leftoffset;
583 
584         /* Build lookup table for pen offset, adjusting for
585          * vertical resolution setting
586          */
587         penofs[0] = (PEN0OFS * 2) / gendata.yrmul;
588         penofs[1] = (PEN1OFS * 2) / gendata.yrmul;
589         penofs[2] = (PEN2OFS * 2) / gendata.yrmul;
590 
591         /* Build lookup table for vertical heads alignment,
592          * adjusting for vertical resolution setting
593          */
594         valign[COLORVALIGN] = (COLORVALIGN_V * 2) / gendata.yrmul;
595         valign[BLACKVALIGN] = (BLACKVALIGN_V * 2) / gendata.yrmul;
596         valign[PHOTOVALIGN] = (PHOTOVALIGN_V * 2) / gendata.yrmul;
597 
598         /* Build lookup tables for initial horizontal offsets,
599          * adjusting for horizontal resolution setting
600          */
601          /* choose whether to use lxm3200 or Z12 settings */
602       gendata.modelprint=(gendata.dev)->model; /* which model? */
603       gendata.z31margin=(gendata.dev)->z31m; /*which additional margin for z31*/
604       switch(gendata.modelprint){
605       case 1:  /* we use the Lexmark Z12 */
606           hoffset[LEFT][LEFT] = LHSTART_z12;
607           hoffset[RIGHT][LEFT] = RHSTART_z12 + gendata.lrhalign;
608           break;
609       default: /* default (if one uses the Lexmark 3200 or the Lexmark Z31) */
610           hoffset[LEFT][LEFT] = LHSTART;
611           hoffset[RIGHT][LEFT] = RHSTART + gendata.lrhalign;
612           break;
613       }
614       hoffset[LEFT][RIGHT] = hoffset[LEFT][LEFT] - LRPASSHOFS;
615       hoffset[RIGHT][RIGHT] = hoffset[RIGHT][LEFT] - LRPASSHOFS;
616 
617         /* Initialization of general parameters */
618         gendata.outdata = NULL;
619         gendata.scanbuf = NULL;
620         gendata.curheadpos = 0;
621         gendata.left = 0;
622         gendata.right = 0;
623         gendata.lastblack = 0;
624         gendata.curvline = 0;
625         gendata.firstline = 0;
626         gendata.fullflag = FALSE;
627         gendata.direction = LEFT;
628         gendata.ileave = 0;
629 
630         gendata.bidirprint = (gendata.dev)->bidir;
631         gendata.numpasses = (gendata.dev)->numpass;
632 
633         /* Set some parameters that depend on resolution and
634          * printing mode. We calculate all at 600dpi (the native
635          * resolution) and then correct later for different
636          * resolution settings.
637          */
638         switch(gendata.rendermode)
639         {
640                 /* In monochrome mode we try to use all 208 nozzles of
641                  * the black cartridge to speed up printing. But if we
642                  * are printing at 1200 dpi horizontal, only 192 nozzles
643                  * are available anyway (it seems an hardware limitation).
644                  * We print a full buffer at every pass, so the number of
645                  * lines in the buffer is the same as the number of nozzles
646                  * of the head.
647                  */
648                 case LXM3200_M:
649                         gendata.numblines = 208;
650                         gendata.numlines = 208;
651                         gendata.select = 0x10;
652                         if(gendata.xres == 1200)
653                         {
654                                 gendata.numblines = 192;
655                                 gendata.numlines = 192;
656                                 gendata.select = 0x00;
657                         }
658                         break;
659 
660                 /* In color or photo mode we must use 192 nozzles only in
661                  * the black cartridge, to cope with the color and photo
662                  * cartridges (which have 3 color pen of 64 nozzles each,
663                  * for a total of 192 nozzles). But the color pens are
664                  * vertically spaced and misaligned with respect to the
665                  * black pen. To solve this problem, we need a buffer which
666                  * is larger than 192 lines and then we print only the
667                  * proper "windows" from it. We choose to set the buffer
668                  * height to 256, which is the smallest power of two large
669                  * enough to hold all the needed data. We use a power of
670                  * two for speed, since in this way the modulo operation
671                  * in the inner loops (needed to take care of buffer rolling)
672                  * becomes a simple and much faster bitwise AND.
673                  */
674                 case LXM3200_P:
675                 case LXM3200_C:
676                         gendata.numblines = 256;
677                         gendata.numlines = 192;
678                         gendata.select = 0x00;
679                         break;
680         }
681 
682         /* Correct the number of lines of the buffer to take care
683          * of different vertical resolution modes. Since the buffer
684          * does cover a constant vertical spacing, we must double the
685          * number of lines at 1200dpi and half it at 300dpi, to take
686          * into account the different thickness of the lines at the
687          * three different vertical resolutions.
688          */
689         gendata.numblines = (gendata.numblines * 2) / gendata.yrmul;
690 
691         /* Now correct the "select" field to adjust the horizontal
692          * motor speed depending on position. Meanwhile, if we are
693          * at 1200 dpi, double the number of horizontal passes
694          * because each stripe at 1200 dpi horizontal must be printed
695          * in two passes.
696          */
697         switch(gendata.xres)
698         {
699                 case 300:
700                         gendata.select |= 0x60;
701                         break;
702 
703                 case 1200:
704                         gendata.select |= 0x40;
705                         gendata.numpasses *= 2;
706                         break;
707         }
708 
709         /* Now store some useful info taken from the ghostscript
710          * device structure to speed up access.
711          */
712         gendata.numcols = (gendata.dev)->width;
713         gendata.numvlines = (gendata.dev)->height;
714         gendata.lrhalign = (gendata.dev)->algnA;
715         gendata.vertalign = (gendata.dev)->algnB;
716         gendata.bwsep = (gendata.dev)->algnC;
717         gendata.colsep = (gendata.dev)->algnD;
718         gendata.goffset = (max(gendata.bwsep, gendata.colsep) * 2) / gendata.xrmul;
719         gendata.numbytes = gendata.numcols + (2 * gendata.goffset);
720         gendata.numrbytes = gdev_mem_bytes_per_scan_line(gendata.dev);
721 
722         /* Calculate number of lines in the page and initialize the
723          * counter of the lines to eject. At the end of the printing,
724          * to eject the paper sheet we must send to the printer a
725          * command to move the paper forward. The amount to move is
726          * the length of paper which is still inside the printer plus
727          * two inches (the number is expressed in 1200ths of an inch,
728          * so "plus two inches" means "add 2400").
729          */
730         gendata.linetoeject = gendata.numvlines * gendata.yrmul;
731         gendata.linetoeject += 2400;
732 
733         /* Allocate memory for the buffers and
734          * verify that the allocation was done properly.
735          */
736         gendata.scanbuf = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), gendata.numbytes, gendata.numblines,
737                                                                                                                                                         "lxm3200_print_page(scanbuf)");
738 
739         gendata.outdata = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), gendata.numbytes, 30,
740                                                                                                                                                         "lxm3200_print_page(outdata)");
741 
742         if(gendata.scanbuf == NULL ||
743                  gendata.outdata == NULL)
744         {
745                 freeresources(pdev);
746                 return_error(gs_error_VMerror);
747         }
748 
749         /* Send initialization sequence to the printer */
750         if(gendata.modelprint==1) fwrite(z12_init_sequence, sizeof(z12_init_sequence), 1, prn_stream);
751         else fwrite(init_sequence, sizeof(init_sequence), 1, prn_stream);
752 
753         /* Choose the right page printing routine
754          * depending on the printing mode.
755          */
756         switch(gendata.rendermode)
757         {
758                 case LXM3200_P:
759                         print_photo_page();
760                         break;
761 
762                 case LXM3200_C:
763                         print_color_page();
764                         break;
765 
766                 case LXM3200_M:
767                 default:
768                         print_mono_page();
769                         break;
770         }
771 
772         /* Output the end-of-page epilogue */
773         outputepilogue();
774 
775         /* Free the allocated resources */
776         freeresources(pdev);
777 
778         /* Done. Bye bye, see you on next page. */
779         return(0);
780 }
781 
782 /* Function that Ghostscript calls to ask the driver
783  * the value of its parameters. This function is based
784  * on the equivalent from the HP850 driver (gdevcd8.c)
785  * by Uli Wortmann.
786  * I won't comment it because I haven't even tried
787  * to understand this code... :)
788  */
789 static int
lxm3200_get_params(gx_device * pdev,gs_param_list * plist)790 lxm3200_get_params(gx_device *pdev, gs_param_list *plist)
791 {
792   int code;
793 
794   code = gdev_prn_get_params(pdev, plist);
795 
796   if(code < 0)return(code);
797 
798         code = param_write_int(plist, "algnA", &((lxm_device *)pdev)->algnA);
799         if(code < 0)return(code);
800 
801         code = param_write_int(plist, "algnB", &((lxm_device *)pdev)->algnB);
802         if(code < 0)return(code);
803 
804         code = param_write_int(plist, "algnC", &((lxm_device *)pdev)->algnC);
805         if(code < 0)return(code);
806 
807         code = param_write_int(plist, "algnD", &((lxm_device *)pdev)->algnD);
808         if(code < 0)return(code);
809 
810         code = param_write_int(plist, "bidir", &((lxm_device *)pdev)->bidir);
811         if(code < 0)return(code);
812 
813         code = param_write_int(plist, "numpass", &((lxm_device *)pdev)->numpass);
814         if(code < 0)return(code);
815 
816         code = param_write_int(plist, "mode", &((lxm_device *)pdev)->rendermode);
817         if(code < 0)return(code);
818 
819         code = param_write_int(plist, "model", &((lxm_device *)pdev)->model);
820         if(code < 0)return(code);
821 
822         code = param_write_int(plist, "z31m", &((lxm_device *)pdev)->z31m);
823 
824   return code;
825 }
826 
827 /* Function that Ghostscript calls to let the driver
828  * set the value of its parameters. This function is
829  * based on the equivalent from the HP850 driver
830  * (gdevcd8.c) by Uli Wortmann.
831  * I won't comment it because I haven't even tried
832  * to understand this code... :)
833  */
834 static int
lxm3200_put_params(gx_device * pdev,gs_param_list * plist)835 lxm3200_put_params(gx_device *pdev, gs_param_list *plist)
836 {
837   int algnA = ((lxm_device *)pdev)->algnA;
838   int algnB = ((lxm_device *)pdev)->algnB;
839   int algnC = ((lxm_device *)pdev)->algnC;
840   int algnD = ((lxm_device *)pdev)->algnD;
841   int bidir = ((lxm_device *)pdev)->bidir;
842   int numpass = ((lxm_device *)pdev)->numpass;
843   int mode = ((lxm_device *)pdev)->rendermode;
844   int code = 0;
845   int model = ((lxm_device *)pdev)->model; /* for model selection */
846   int z31m = ((lxm_device *)pdev)->z31m; /* additional margin for the z31 */
847 
848   code = param_read_int(plist, "algnA", &algnA);
849         if(code < 0)return(code);
850         if(algnA < 0 || algnA > 30)
851                 param_signal_error(plist, "algnA", gs_error_rangecheck);
852 
853   code = param_read_int(plist, "algnB", &algnB);
854         if(code < 0)return(code);
855         if(algnB < 0 || algnB > 15)
856                 param_signal_error(plist, "algnB", gs_error_rangecheck);
857 
858   code = param_read_int(plist, "algnC", &algnC);
859         if(code < 0)return(code);
860         if(algnC < 0 || algnC > 30)
861                 param_signal_error(plist, "algnC", gs_error_rangecheck);
862 
863   code = param_read_int(plist, "algnD", &algnD);
864         if(code < 0)return(code);
865         if(algnD < 0 || algnD > 30)
866                 param_signal_error(plist, "algnD", gs_error_rangecheck);
867 
868   code = param_read_int(plist, "bidir", &bidir);
869         if(code < 0)return(code);
870         if(bidir != 0 && bidir != 1)
871                 param_signal_error(plist, "bidir", gs_error_rangecheck);
872 
873   code = param_read_int(plist, "numpass", &numpass);
874         if(code < 0)return(code);
875         if(numpass < 1 || numpass > 16)
876                 param_signal_error(plist, "numpass", gs_error_rangecheck);
877 
878   code = param_read_int(plist, "mode", &mode);
879         if(code < 0)return(code);
880         if(mode != LXM3200_M && mode != LXM3200_C && mode != LXM3200_P)
881                 param_signal_error(plist, "mode", gs_error_rangecheck);
882 
883    code = param_read_int(plist, "model", &model); /* asking for the model of printer: lxm3200 , Z12, Z31 */
884         if(code < 0)return(code);
885         if(model < 0 || model > 2 )
886                 param_signal_error(plist, "model", gs_error_rangecheck);
887 
888    code = param_read_int(plist, "z31m", &z31m); /* What additional margin for the Z31 */
889         if(code < 0)return(code);
890 
891    code = gdev_prn_put_params(pdev, plist);
892         if(code < 0)return code;
893 
894   ((lxm_device *)pdev)->algnA = algnA;
895   ((lxm_device *)pdev)->algnB = algnB;
896   ((lxm_device *)pdev)->algnC = algnC;
897   ((lxm_device *)pdev)->algnD = algnD;
898   ((lxm_device *)pdev)->bidir = bidir;
899   ((lxm_device *)pdev)->numpass = numpass;
900   ((lxm_device *)pdev)->rendermode = mode;
901   ((lxm_device *)pdev)->model = model; /* Model selection: lxm3200, Z12, Z31. */
902   ((lxm_device *)pdev)->z31m = z31m;  /* Additional margin for the Z31 */
903 
904         /* Depending on the selected rendering mode, change the
905          * driver's parameters that ghostscript needs for the
906          * dithering. We need to do it here because the "get_params"
907          * and "put_params" are the only routines in the driver that
908          * ghostscript calls before using the dithering parameters.
909          */
910         switch(mode)
911         {
912                 case LXM3200_M:
913                         pdev->color_info.num_components = 1;
914                         pdev->color_info.max_gray = 1;
915                         pdev->color_info.max_color = 0;
916                         pdev->color_info.dither_grays = 2;
917                         pdev->color_info.dither_colors = 0;
918                         break;
919 
920                 case LXM3200_C:
921                         pdev->color_info.num_components = 3;
922                         pdev->color_info.max_gray = 1;
923                         pdev->color_info.max_color = 1;
924                         pdev->color_info.dither_grays = 2;
925                         pdev->color_info.dither_colors = 2;
926                         break;
927 
928                 case LXM3200_P:
929                         pdev->color_info.num_components = 3;
930                         pdev->color_info.max_gray = 1;
931                         pdev->color_info.max_color = 2;
932                         pdev->color_info.dither_grays = 2;
933                         pdev->color_info.dither_colors = 3;
934                         break;
935         }
936 
937   return 0;
938 }
939 
940 /* --------- Internal routines --------- */
941 
942 /* Free the resources allocated by the driver */
943 static void
freeresources(gx_device * pdev)944 freeresources(gx_device *pdev)
945 {
946         if(gendata.scanbuf)
947                 gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)gendata.scanbuf, gendata.numbytes, gendata.numblines,
948                                                 "lxm3200:freeresources(scanbuf)");
949 
950         if(gendata.outdata)
951                 gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)gendata.outdata, gendata.numbytes, 30,
952                                                 "lxm3200:freeresources(outdata)");
953 }
954 
955 /* Calculate the checksum of an escape sequence.
956  * It is defined as the sum modulo 256 of the
957  * six bytes following the escape character.
958  *
959  * data: pointer to the first of the 8 characters
960  *       of an escape sequence.
961  */
962 static byte
calccheck8(byte * data)963 calccheck8(byte *data)
964 {
965         int ck, i;
966 
967         ck = 0;
968         for(i=1; i<7; i++)ck += data[i];
969 
970         return(ck);
971 }
972 
973 /* Output the page epilogue. This procedure outputs
974  * the escape sequence needed to eject the page and
975  * take the printheads to the "park" position.
976  */
977 static void
outputepilogue(void)978 outputepilogue(void)
979 {
980         byte trailer[24];
981         int pos;
982 
983         /* Page eject sequence */
984         trailer[0] = 0x1b;
985         trailer[1] = 0x22;
986         trailer[2] = 0x80;
987         trailer[3] = gendata.linetoeject >> 8;
988         trailer[4] = gendata.linetoeject & 0xff;
989         trailer[5] = 0x00;
990         trailer[6] = 0x00;
991         trailer[7] = calccheck8(trailer);
992 
993         /* Calculate the value we need to take the head back
994          * to the park position. This is the current head position
995          * if we printed the last stripe left-to-right, and the
996          * current head position minus 168 (0xa8) if we printed the
997          * last stripe right-to-left.
998          */
999         pos = gendata.curheadpos;
1000         if(gendata.bidirprint && gendata.direction == LEFT)pos -= 0xa8;
1001         if(pos < 0)pos = 0;
1002 
1003         /* Horizontal back sequence */
1004         trailer[8] = 0x1b;
1005         trailer[9] = 0x31;
1006         trailer[10] = 0x10;
1007         trailer[11] = pos >> 8;
1008         trailer[12] = pos & 0xff;
1009         trailer[13] = 0x00;
1010         trailer[14] = 0x00;
1011         trailer[15] = calccheck8(trailer+8);
1012 
1013         /* Reset sequence */
1014         trailer[16] = 0x1b;
1015         trailer[17] = 0x33;
1016         trailer[18] = 0x00;
1017         trailer[19] = 0x00;
1018         trailer[20] = 0x00;
1019         trailer[21] = 0x00;
1020         trailer[22] = 0x00;
1021         trailer[23] = 0x33;
1022 
1023         fwrite(trailer, 8, 3, gendata.stream);
1024 }
1025 
1026 /* Output a "page forward" escape sequence,
1027  * needed to move the paper forward some lines.
1028  *
1029  * skiprow: number of buffer lines to skip
1030  * vskip  : fixed offset, in 1200ths of an inch
1031  */
1032 static void
skiplines(int skiprow,int skipin)1033 skiplines(int skiprow, int skipin)
1034 {
1035         byte escape[8];
1036         int vskip;
1037 
1038         /* The vertical skip command accepts a spacing expressed in
1039          * 1200ths of an inch, so we must convert lines to 1200ths
1040          * of an inch. After the conversion we sum an offset directly
1041          * expressed in 1200ths of an inch: this way we can use this
1042          * routine to skip both a certain amount of lines (which exact
1043          * spacing value depends on the vertical resolution) and a
1044          * fixed offset that we directly know in spacing units.
1045          */
1046         vskip = skiprow*gendata.yrmul + skipin;
1047 
1048         escape[0] = 0x1b;
1049         escape[1] = 0x23;
1050         escape[2] = 0x80;
1051         escape[3] = vskip >> 8;
1052         escape[4] = vskip & 0xff;
1053         escape[5] = 0x00;
1054         escape[6] = 0x00;
1055         escape[7] = calccheck8(escape);
1056 
1057         /* Adjust the number of lines still inside the printer */
1058         gendata.linetoeject -= vskip;
1059 
1060         fwrite(escape, 8, 1, gendata.stream);
1061 }
1062 
1063 /* Fill a stripe header with data.
1064  *
1065  * head:     LEFT or RIGHT, chooses which head we are "feeding"
1066  * numcol:   number of data columns in this stripe, including blank ones
1067  * firstcol: position of the first column in the stripe (the *very first*,
1068  *           even if it's blank).
1069  * bytes:    total number of bytes in the stripe, including directories
1070  *           (but excluding the 24 bytes of the header).
1071  */
1072 static void
fillheader(int head,int numcol,int firstcol,int bytes)1073 fillheader(int head, int numcol, int firstcol, int bytes)
1074 {
1075         int len, offs1, startabs;
1076         int endabs, select, fwd;
1077         int back, nabspos, sep;
1078         byte *header;
1079 
1080         header = gendata.header;
1081 
1082         /* Correct the measures: firstcol and len need to
1083          * be in 1200ths of an inch.
1084          */
1085         firstcol *= gendata.xrmul;
1086         len = numcol * gendata.xrmul;
1087 
1088         /* Alter select to choose direction */
1089         select = gendata.select | (gendata.direction == LEFT ? 0x01 : 0x00);
1090 
1091         /* Calculate the proper horizontal offset */
1092         offs1 = hoffset[head][gendata.direction];
1093 
1094         /* Now calculate the correct separation depending on the
1095          * head type and adjust "select" to choose between left
1096          * or right head.
1097          */
1098         if(head == LEFT)
1099         {
1100                 sep = (gendata.bwsep * 2) / gendata.xrmul;
1101         }
1102         else
1103         {
1104                 sep = (gendata.colsep * 2) / gendata.xrmul;
1105                 select |= 0x80;
1106         }
1107 
1108         /* Now calculate absolute starting and ending positions
1109          * of this stripe, taking into account the printing direction
1110          */
1111         startabs = firstcol + offs1;
1112 
1113         if(gendata.direction == LEFT)
1114                 endabs = startabs + len;
1115         else
1116                 endabs = startabs - len;
1117 
1118         /* And now, basing on current head position,
1119          * transform the absolute coordinates in a
1120          * relative movement of the head.
1121          * The formulas used for this are "black magic",
1122          * since this is a part of the protocol which is
1123          * still not well known. What you see here is an
1124          * empyrical formula devised by examination and
1125          * parameter fitting on the data output by the
1126          * Windows driver.
1127          */
1128         if(gendata.direction == LEFT)
1129         {
1130                 nabspos = (((endabs - 3600) >> 3) & 0xfff0) + 9;
1131                 fwd = nabspos - gendata.curheadpos;
1132         }
1133         else
1134         {
1135                 if(endabs > 4816)
1136                         nabspos = (((endabs - 4800) >> 3) & 0xfff0) + 9;
1137                 else
1138                         nabspos = (((endabs - 3600) >> 3) & 0xfff0) + 9;
1139                 fwd = gendata.curheadpos - nabspos;
1140         }
1141 
1142         gendata.curheadpos += (gendata.direction == LEFT ? fwd : -fwd);
1143 
1144         /* If we are printing unidirectionally, calculate
1145          * the backward movement to return the printing head
1146          * at the beginning of this stripe.
1147          */
1148         back = 0;
1149         if(gendata.bidirprint == FALSE)
1150         {
1151                 if(startabs > 4816)
1152                         nabspos = ((startabs - 4800) >> 3) & 0xfff0;
1153                 else
1154                         nabspos = ((startabs - 3600) >> 3) & 0xfff0;
1155 
1156                 if(gendata.direction == LEFT)
1157                         back = gendata.curheadpos - nabspos;
1158                 else
1159                         back = nabspos - gendata.curheadpos;
1160         }
1161 
1162         gendata.curheadpos -= (gendata.direction == LEFT ? back : -back);
1163 
1164         /* First part of the header */
1165         header[0] = 0x1b;
1166         header[1] = 0x40;
1167         header[2] = select;        /* Printing type flags */
1168         header[3] = numcol >> 8;   /* MSB of the number of columns to print */
1169         header[4] = numcol & 0xff; /* LSB of the number of columns to print */
1170         header[5] = fwd >> 8;      /* MSB of the relative forward head motion */
1171         header[6] = fwd & 0xff;    /* LSB of the relative forward head motion */
1172         header[7] = calccheck8(&header[0]);
1173 
1174         /* Second part of the header */
1175         header[8] = 0x1b;
1176         header[9] = 0x42;
1177         header[10] = 0x00;
1178         if(gendata.modelprint==1) header[10] = 0x10; /* Lexmark Z12 protocol */
1179         header[11] = back >> 8;  /* MSB of the relative backward head motion */
1180         header[12] = back & 0xff;  /* LSB of the relative backward head motion */
1181         header[13] = 0x00;  /* MSB of the relative downward head motion */
1182         header[14] = 0x00;  /* LSB of the relative downward head motion */
1183         header[15] = calccheck8(&header[8]);
1184 
1185         /* Third (and last) part of the header */
1186         header[16] = 0x1b;
1187         header[17] = 0x43;
1188         header[18] = (bytes >> 16) & 0xff;
1189         header[19] = (bytes >> 8) & 0xff;
1190         header[20] = bytes & 0xff;    /* LSB of the number of bytes in this stripe */
1191         header[21] = startabs >> 8;   /* MSB of the starting column of this stripe */
1192         header[22] = startabs & 0xff; /* LSB of the starting column of this stripe */
1193         header[23] = calccheck8(&header[16]);
1194 
1195         /* Signal to other routines that the output buffer
1196          * is full and how many bytes it is long.
1197          */
1198         gendata.stripebytes = bytes;
1199         gendata.fullflag = TRUE;
1200 
1201         /* If bidirectional printing is in effect, change
1202          * the printing direction for the next stripe
1203          */
1204         if(gendata.bidirprint)
1205                 gendata.direction = (gendata.direction == LEFT ? RIGHT : LEFT);
1206 }
1207 
1208 /* Set final information in the header and output all
1209  * the data passes. This routine is needed because the
1210  * actual values of two fields of the header (final
1211  * head position and number of vertical lines to reach
1212  * the next stripe) depend on the next stripe and are
1213  * therefore unknown when "fillheader" is called.
1214  *
1215  * vskip  : number of lines to skip to reach next stripe
1216  * newhead: head used for the next stripe (LEFT or RIGHT)
1217  */
1218 static void
finalizeheader(int vskip,int newhead)1219 finalizeheader(int vskip, int newhead)
1220 {
1221         int offs2, nstartabs, back, fwd;
1222         int habs, p, dir, endabs, col;
1223         int newstart, sep;
1224         byte *header;
1225 
1226         header = gendata.header;
1227 
1228         /* Check the printing direction this stripe
1229          * was originally intended for.
1230          */
1231         dir = (header[2] & 0x01 ? LEFT : RIGHT);
1232 
1233         /* Retrieve the horizontal offset for the next stripe */
1234         offs2 = hoffset[newhead][gendata.direction];
1235 
1236         /* Calculate the separation adjust in 1200ths of an inch */
1237         if(newhead == LEFT)
1238                 sep = (gendata.bwsep * 2) / gendata.xrmul;
1239         else
1240                 sep = (gendata.colsep * 2) / gendata.xrmul;
1241 
1242         /* Now calculate the correct starting column
1243          * of the next stripe
1244          */
1245         if(gendata.direction == LEFT)
1246                 newstart = (gendata.left * gendata.xrmul) - sep;
1247         else
1248                 newstart = (gendata.right * gendata.xrmul);
1249 
1250         vskip *= gendata.yrmul;
1251 
1252         /* Calculate absolute starting position of new stripe */
1253         nstartabs = newstart + offs2;
1254 
1255         /* Calculate absolute ending position of this stripe
1256          * by summing (with proper sign) the starting position
1257          * and the width.
1258          */
1259         endabs = header[21]*256 + header[22]; /* Starting position */
1260         col = (header[3]*256 + header[4]); /* Width in columns */
1261         col *= gendata.xrmul; /* Transformed in 1200ths of an inch */
1262 
1263         if(dir == LEFT)
1264                 endabs += col; /* Printing left-to-right */
1265         else
1266                 endabs -= col; /* Printing right-to-left */
1267 
1268         /* Correct head position neutralizing the effect
1269          * of the last issued head movement commands. The
1270          * head movement for this stripe needs to be
1271          * recalculated from scratch to take into account
1272          * the correct beginning position of the next stripe.
1273          */
1274         if(dir == LEFT)
1275         {
1276                 gendata.curheadpos += header[11]*256 + header[12]; /* Back movement */
1277                 gendata.curheadpos -= header[5]*256 + header[6];   /* Forward movement */
1278         }
1279         else
1280         {
1281                 gendata.curheadpos -= header[11]*256 + header[12]; /* Back movement */
1282                 gendata.curheadpos += header[5]*256 + header[6];   /* Forward movement */
1283         }
1284 
1285         /* We use a convention of passing a negative value for
1286          * "newhead" to mean that this is the last stripe of the
1287          * sheet, so we don't need to care for the next stripe.
1288          */
1289         if(newhead < 0)
1290         {
1291                 /* Last stripe: we only need to calculate proper forward
1292                  * motion to print all the current stripe.
1293                  */
1294                 fwd = ((header[5]*256 + header[6]) & 0xfff0) + 9;
1295         }
1296         else
1297         {
1298                 /* This is not the last stripe, so we need to calculate
1299                  * the forward (in the printing direction) movement
1300                  * that will take the printing head at the end of the
1301                  * current stripe or at the beginning of the next,
1302                  * whichever is farther. Note that we are always
1303                  * talking relative to printing direction, so we must
1304                  * take into proper account if we are printing from left
1305                  * to right or from right to left.
1306                  */
1307                 if(dir == LEFT)
1308                 {
1309                         p = max(endabs, nstartabs);
1310                         habs = (((p - 3600) >> 3) & 0xfff0) + 9;
1311                         fwd = habs - gendata.curheadpos;
1312 
1313                         /* part for the Lexmark Z31!!! */
1314                         if(gendata.modelprint==2) fwd += gendata.z31margin;
1315 
1316                 }
1317                 else
1318                 {
1319                         p = min(endabs, nstartabs);
1320                         if(p > 4816)
1321                                 habs = (((p - 4800) >> 3) & 0xfff0);
1322                         else
1323                                 habs = (((p - 3600) >> 3) & 0xfff0);
1324                         fwd = gendata.curheadpos - habs;
1325                 }
1326         }
1327 
1328         /* Now update the current head position to take into
1329          * account the forward movement just computed
1330          */
1331         gendata.curheadpos += (dir == LEFT ? fwd : -fwd);
1332 
1333         /* Now calculate the value of the needed backward movement
1334          * to poisition the head correctly for the start of the
1335          * next stripe.
1336          */
1337         if(newhead < 0 || gendata.bidirprint)
1338         {
1339                 /* If this is the last stripe of the page,
1340                  * there is no need to take back the head:
1341                  * it will be done by the parking command.
1342                  * Or if we are printing bidirectionally,
1343                  * the forward command has taken the head to
1344                  * the correct position, so no need to move it.
1345                  */
1346                 back = 0;
1347         }
1348         else
1349         {
1350                 /* Calculate the right backward movement basing
1351                  * on the start of the next stripe.
1352                  */
1353                 if(nstartabs > 4856)
1354                         habs = ((nstartabs - 4840) >> 3) & 0xfff0;
1355                 else
1356                         habs = ((nstartabs - 3600) >> 3) & 0xfff0;
1357 
1358                 back = gendata.curheadpos - habs;
1359 
1360                 /* If the next stripe starts at the right
1361                  * of this one, "back" will be too small or
1362                  * negative, so correct it.
1363                  * It appears that 16 is the minimum allowable
1364                  * backward movement that does not make the 3200
1365                  * misbehave in the next stripe. This does not hold
1366                  * if we are changing printing direction (in such a
1367                  * case backward movement may be zero). This means
1368                  * we are moving the head a little more than needed,
1369                  * but it seems unavoidable.
1370                  */
1371                 if(back < 16)back = 16;
1372         }
1373 
1374   /* Lastly, update the current head position with the
1375          * backward movement just calculated.
1376          */
1377         gendata.curheadpos -= (dir == LEFT ? back : -back);
1378 
1379         /* Modify first part of the header */
1380         header[5] = fwd >> 8;
1381         header[6] = fwd & 0xff;
1382         header[7] = calccheck8(&header[0]);
1383 
1384         /* Modify second part of the header */
1385         header[8] = 0x1b;
1386         header[9] = 0x42;
1387         header[10] = 0x00;
1388         if(gendata.modelprint==1) header[10] = 0x10; /* Lexmark Z12 protocol */
1389         header[11] = back >> 8;    /* MSB of the relative backward head motion */
1390         header[12] = back & 0xff;  /* LSB of the relative backward head motion */
1391         header[13] = vskip >> 8;   /* MSB of the relative downward head motion */
1392         header[14] = vskip & 0xff; /* LSB of the relative downward head motion */
1393         header[15] = calccheck8(&header[8]);
1394 
1395         /* Now output the data, signalling that the output
1396          * buffer is now empty.
1397          */
1398         fwrite(header, 3, 8, gendata.stream);
1399         fwrite(gendata.outdata, gendata.stripebytes, 1, gendata.stream);
1400         gendata.fullflag = FALSE;
1401 }
1402 
1403 /* Convert a buffer data stream into
1404  * directory/data representation, using the
1405  * shortest coding (either direct or RLE)
1406  *
1407  * head    : head we are printing with (left or right).
1408  * numcols : number of columns in the buffer.
1409  * firstcol: first column to print.
1410  */
1411 static void
convbuf(int head,int numcols,int firstcol)1412 convbuf(int head, int numcols, int firstcol)
1413 {
1414         byte *read, *write;
1415         int x, i, c, p, q, cnt, rle, std;
1416         int nby, ofs, dts0, dtr0, dtr1;
1417         int bytes;
1418 
1419         /* Initialize the pointers. We use the same buffer
1420          * for both input and output (we can do it because
1421          * the output data is at most as long as the input).
1422          * Note that the encode routines skipped 4 bytes at
1423          * each column to make room for the directory word.
1424          */
1425         read = gendata.outdata + 4;
1426         write = gendata.outdata;
1427 
1428         /* Set the parameters that will be used to create the directory and
1429          * to access the data. These parameters define the structure of the
1430          * directory word (32 bit) and depend on the number of nozzles that
1431          * are used. Note that the directory bitfield is initialized to all
1432          * ones (but read below for further info) because it works in negative
1433          * logic (i.e. a change is marked by a zero bit).
1434          * Below, nby is the number of bytes needed in the input data to map
1435          * a column (each nozzle is 1 bit, so 208 nozzles are 26 bytes and
1436          * 192 nozzles are 24 bytes). Ofs is the number of the first bit of
1437          * the directory bitfield in the directory word (with 208 nozzles we
1438          * need 26 bits, from 6 to 31, with 192 nozzles we need 24 bits, from
1439          * 8 to 31). The other three parameters are the values needed to
1440          * initialize the directory word properly: the key is the first two
1441          * bits, which must be "10" for a directly encoded stripe and "01" for
1442          * a RLE encoded one. In the lexmark directory, each bit represents a
1443          * group of 8 nozzles: in a directly encoded stripe if the bit is "1"
1444          * it means none of the nozzles in the group are used, if it is a "0"
1445          * it means at least one is used and we need to append a data byte to
1446          * define the exact usage pattern. So, for direct encoded stripes we
1447          * start with the first two bits set to "10" and all the directory
1448          * bitfield set to "1" (we will unset to "0" only the needed bits in
1449          * the encoding loop). If we are using RLE encoding, each "0" bits
1450          * means that there is a data byte that defines a pattern for the
1451          * group of 8 nozzles associated to that bit, and an "1" means that
1452          * the pattern for the associated group of nozzles is the same as the
1453          * previous group. This means that for RLE encoded stripes we start the
1454          * directory word with two bits set to "01" and then initialize to "1"
1455          * all the directory bitfield, except the first one which must be 0
1456          * because we must have at least one data byte to define the initial
1457          * pattern that will be eventually repeated.
1458          */
1459         if(gendata.numlines == 208)
1460         {
1461                 nby = 26;
1462                 ofs = 6;
1463                 dts0 = 0x83;
1464                 dtr0 = 0x41;
1465                 dtr1 = 0xff;
1466         }
1467         else
1468         {
1469                 nby = 24;
1470                 ofs = 8;
1471                 dts0 = 0x80;
1472                 dtr0 = 0x40;
1473                 dtr1 = 0x7f;
1474         }
1475 
1476         /* The variable "bytes" will contain the total
1477          * number of output bytes in the data stripe.
1478          */
1479         bytes = 0;
1480 
1481         /* For all the columns in the stripe */
1482         for(x = 0; x < numcols; x++)
1483         {
1484                 /* Calculate which representation is smaller by counting
1485                  * the number of non zero data bytes for the direct encoding
1486                  * and the number of changes between data bytes for the RLE.
1487                  * At the end we have in "std" the length of the output data
1488                  * if encoded with standard encoding, and in "rle" the length
1489                  * of the output data if encoded with RLE.
1490                  */
1491                 rle = 1;
1492                 c = read[0];
1493                 std = (c ? 1 : 0);
1494                 for(i=1; i<nby; i++)
1495                 {
1496                         if((p = read[i]))std++;
1497                         if(p != c)
1498                         {
1499                                 rle++;
1500                                 c = read[i];
1501                         }
1502                 }
1503 
1504                 /* Now initialize the last two bytes in the directory
1505                  * word. These always belong to the directory bitfield
1506                  * and must be set to all ones.
1507                  */
1508                 write[2] = 0xff;
1509                 write[3] = 0xff;
1510 
1511                 /* And now encode the column, using the shortest encoding.
1512                  * If the two encodings are of equal length we prefer the
1513                  * standard encoding to the RLE one. No real reason for
1514                  * this: it could have been done the other way, but it
1515                  * seems the Windows driver does this way as well...
1516                  */
1517                 if(std > rle)
1518                 {
1519                         /* Run-length encoding */
1520 
1521                         write[0] = dtr0;
1522                         write[1] = dtr1;
1523 
1524                         p = read[0];
1525                         write[4] = p;
1526                         cnt = 5;
1527                         q = ofs + 1;
1528 
1529                         for(i=1; i<nby; i++)
1530                         {
1531                                 if(read[i] != p)
1532                                 {
1533                                         p = read[i];
1534                                         write[cnt] = p;
1535                                         write[q>>3] &= ibits[q & 7];
1536                                         cnt++;
1537                                 }
1538                                 q++;
1539                         }
1540                 }
1541                 else
1542                 {
1543                         /* Standard encoding */
1544 
1545                         write[0] = dts0;
1546                         write[1] = 0xff;
1547 
1548                         cnt = 4;
1549                         q = ofs;
1550 
1551                         for(i=0; i<nby; i++)
1552                         {
1553                                 p = read[i];
1554                                 if(p)
1555                                 {
1556                                         write[cnt] = p;
1557                                         write[q>>3] &= ibits[q & 7];
1558                                         cnt++;
1559                                 }
1560                                 q++;
1561                         }
1562                 }
1563 
1564                 /* Update the counters and pointers. Note that when
1565                  * we are here "cnt" is the number of bytes that we
1566                  * have actually output, including the directory word.
1567                  */
1568                 read += (nby + 4);
1569                 write += cnt;
1570                 bytes += cnt;
1571         }
1572 
1573         fillheader(head, numcols, firstcol, bytes);
1574 }
1575 
1576 /* This routine takes one full buffer of data and
1577  * prints the black part, which of course is the only
1578  * one if we are printing in monochrome mode.
1579  */
1580 static void
encode_bw_buf(void)1581 encode_bw_buf(void)
1582 {
1583         int left, right, x, y, nn, mod;
1584         int nxp, yy, numcols, incr;
1585         int dy, dy2, csep, pass, f1;
1586         int f2, start, s1, s2, yincr;
1587         int q, mask, lines;
1588         byte *scan, *data;
1589 
1590         /* Set some parameters that depend on resolution and are
1591          * used in the inner loop to select lines to print.
1592          * We basically encode all the even nozzles in a loop and
1593          * all the odd nozzles in another loop. The values of s1
1594          * and s2 are the starting offset in the line buffer for
1595          * the first and second loop, and yincr is the number of lines
1596          * in the buffer we move on at each cycle.
1597          */
1598         switch(gendata.yres)
1599         {
1600                 /* At 300 dpi we use only one nozzle column, and
1601                  * each line in the buffer is printed. So both offsets
1602                  * are zero (only one is used, actually) and yincr is 1.
1603                  * The mask is set to 127 because the buffer is 128 lines.
1604                  */
1605                 case 300:
1606                         yincr = 1;
1607                         s1 = 0;
1608                         s2 = 0;
1609                         mask = 127;
1610                         break;
1611 
1612                 /* At 600 dpi we use both nozzle columns: each row goes
1613                  * alternatively to the left or right nozzle column. So
1614                  * the even offset is zero, the odd offset is 1 and the
1615                  * increment is 2: in this way the even loop scans lines
1616                  * 0, 2, 4, ... and the odd loop lines 1, 3, 5, ...
1617                  * Here the buffer is 256 lines so mask is set to 255.
1618                  */
1619                 default:
1620                 case 600:
1621                         yincr = 2;
1622                         s1 = 0;
1623                         s2 = 1;
1624                         mask = 255;
1625                         break;
1626 
1627                 /* At 1200 dpi we are printing two interleaved passes. Each
1628                  * nozzle column sees every fourth line in the buffer (so
1629                  * yincr is 4) and the starting offset varies depending on
1630                  * which interleaved pass we are doing.
1631                  * During the first pass, even nozzles are used to print
1632                  * lines 0, 4, 8, ... and odd nozzles are used to print
1633                  * lines 2, 6, 10, ... while in the second pass the even
1634                  * nozzles print lines 1, 5, 9, ... and the odd nozzles
1635                  * print lines 3, 7, 11, ...
1636                  * The buffer is 512 lines, so mask is set to 511 */
1637                 case 1200:
1638                         yincr = 4;
1639                         s1 = (gendata.ileave ? 1 : 0);
1640                         s2 = (gendata.ileave ? 3 : 2);
1641                         mask = 511;
1642                         break;
1643         }
1644 
1645         /* Now we must calculate the offset q from the beginning of
1646          * the buffer of the first line to print in this pass, and
1647          * the total number of lines to be printed. We print as many
1648          * lines as we can in a single pass, i.e. the value of "lines"
1649          * is simply the number of lines that at the current vertical
1650          * resolution fully cover the printing pen.
1651          * Note that in case of monochrome printing we print all
1652          * buffer lines, from first to last, so we also need to set
1653          * the mask to a neutral value because we don't use wrapping.
1654          */
1655         if(gendata.rendermode == LXM3200_M)
1656         {
1657                 mask = 511;
1658                 q = 0;
1659                 lines = gendata.numblines;
1660         }
1661         else
1662         {
1663                 q = gendata.firstline + valign[BLACKVALIGN];
1664                 lines = (BWCOLPEN * 2) / gendata.yrmul;
1665         }
1666 
1667         /* Adjust the value of the nozzle column separation to the
1668          * horizontal resolution we are using now.
1669          */
1670         csep = (gendata.bwsep * 2) / gendata.xrmul;
1671 
1672         /* Here we calculate how many "real" passes we are doing.
1673          * A "real" pass is a pass where a full column is printed
1674          * and then some columns (maybe zero) are skipped before
1675          * printing another one. If we are at 1200 dpi horizontal
1676          * then we must use only one nozzle column at a time, so each
1677          * real pass comprises two subpasses, one where we print with
1678          * even nozzles only and another where we print with odd
1679          * nozzles only. So at 1200 dpi the "real" passes are half the
1680          * total number of passes. Another way of looking at it: the
1681          * "nxp" variable holds the separation, in columns, between two
1682          * dot columns printed in the same head sweep.
1683          */
1684         nxp = gendata.numpasses;
1685         if(gendata.xres == 1200)nxp /= 2;
1686 
1687         /* Now calculate the byte increments for the *output* data
1688          * buffer (i.e. the encoded buffer). The first variable,
1689          * dy, is the number of bytes taken by a single data burst
1690          * (both even and odd nozzle columns). The second variable,
1691          * dy2, tells how many bytes we must skip from one column
1692          * to the other (if we are printing multipass we skip some
1693          * columns that will be printed in subsequent passes).
1694          */
1695         dy = (gendata.numlines / 8) + 4;
1696         dy2 = dy * nxp;
1697 
1698         /* Calculate the starting and ending horizontal positions for
1699          * this head pass. There are the margins corrected to take
1700          * into account the displacement between the odd and even
1701          * nozzle columns (csep). Moreover we start "csep" pixels
1702          * before the margin to give the head a little more room to
1703          * accelerate properly (not sure if this really works, but it
1704          * doesn't cost much, so I've left it in).
1705          */
1706         if(gendata.direction == LEFT)
1707         {
1708                 left = gendata.left - 2*csep;
1709                 right = gendata.right + csep;
1710         }
1711         else
1712         {
1713                 left = gendata.left - csep;
1714                 right = gendata.right + 2*csep;
1715         }
1716 
1717         /* Number of columns in a full row */
1718         numcols = right - left;
1719 
1720         /* Calculate the last pixel of the first pass of the
1721          * stripe. If we are printing bidirectionally, this
1722          * will be the base to calculate the start of the
1723          * passes printed right-to-left.
1724          */
1725         mod = numcols - (numcols % nxp);
1726 
1727         /* f1 and f2 are two flags that define which nozzle columns
1728          * we are using in this stripe, f1 for the even nozzle column
1729          * and f2 for the odd nozzle column: if they are zero that
1730          * nozzle column is not used in this pass.
1731          */
1732         f1 = 1;
1733         f2 = 1;
1734         if(gendata.yres == 300)
1735         {
1736                 /* At 300 dpi we use only one nozzle column. As of now this
1737                  * is always the even one, but maybe it could be tried to
1738                  * alternate between columns at each pass, to improve the
1739                  * output quality.
1740                  */
1741                 f1 = 1;
1742                 f2 = 0;
1743         }
1744 
1745         /* Now start the passes to fill all the stripe */
1746         for(pass = 0; pass < gendata.numpasses; pass++)
1747         {
1748                 /* If there is data in the buffer which has not been
1749                  * sent to the printer yet, send it now.
1750                  */
1751                 if(gendata.fullflag)
1752                 {
1753                         fwrite(gendata.header, 3, 8, gendata.stream);
1754                         fwrite(gendata.outdata, gendata.stripebytes, 1, gendata.stream);
1755                         gendata.fullflag = FALSE;
1756                 }
1757 
1758                 /* Clear the output buffer to avoid problems with the bitwise
1759                  * operations we will do later on.
1760                  */
1761                 memset(gendata.outdata, 0, gendata.numbytes * 30);
1762 
1763                 /* Calculate standard increments, starting column
1764                  * and start of output data. They will be corrected
1765                  * later for 1200dpi or right-to-left printing direction.
1766                  */
1767                 incr = nxp;
1768                 start = left + pass;
1769                 data = gendata.outdata + (pass*dy) + 4;
1770 
1771                 /* It appears that at 1200dpi, in addition of not being able
1772                  * to use 208 nozzles mode for the black cartridge, the Lexmark
1773                  * 3200 cannot print at full rate with all the 192 useable nozzles.
1774                  * Maybe the reason is that the data rate of 1200dpi horizontal
1775                  * resolution exceeds the mechanical/thermal limits of the heads.
1776                  * So if we are printing at 1200dpi we need to use alternatively
1777                  * only odd or even numbered nozzles, for each printed column, to
1778                  * half the data rate towards the head.
1779                  * This obviously means that, at 1200dpi horizontal, a minimum of
1780                  * two passes are required to print each stripe. Since if we are
1781                  * printing at 1200dpi vertical we need two interlaced passes, a
1782                  * minimum grand total of 4 passes are needed to print one full
1783                  * 1200x1200 dpi stripe with the Lexmark 3200.
1784                  */
1785                 if(gendata.xres == 1200)
1786                 {
1787                         f1 = pass & 1;
1788                         f2 = 1 - f1;
1789 
1790                         start = left + (pass/2);
1791                         data = gendata.outdata + ((pass/2)*dy) + 4;
1792                 }
1793 
1794                 /* If printing right-to-left we need to present data
1795                  * to the printer in that direction, inverting the
1796                  * normal flow of data.
1797                  */
1798                 if(gendata.direction == RIGHT)
1799                 {
1800                         incr = -nxp;
1801                         start += mod;
1802                 }
1803 
1804                 /* Start column scanning */
1805                 x = start;
1806 
1807                 /* Now we split the behaviour depending on the printing
1808                  * direction. To be honest, the inner loops are almost
1809                  * identical between left-to-right and right-to-left
1810                  * directions. The only difference is where is computed
1811                  * the contribute of the nozzle columns separation ("csep"),
1812                  * but having the "if" outside the loop it's somehow better.
1813                  */
1814                 if(gendata.direction == LEFT)
1815                 {
1816                         /* For all the columns in this pass */
1817                         for(nn = 0; nn < numcols; nn += nxp)
1818                         {
1819                                 /* Encode the even numbered nozzles */
1820                                 if((x >= 0) && f1)
1821                                 {
1822                                         scan = gendata.scanbuf + x;
1823                                         yy = 0;
1824                                         for(y = s1; y < lines; y += yincr)
1825                                         {
1826                                                 if(scan[((y+q) & mask) * gendata.numbytes] & BLACK)
1827                                                         data[yy/8] |= bits[yy&7];
1828                                                 yy += 2;
1829                                         }
1830                                 }
1831 
1832                                 /* Encode the odd numbered nozzles */
1833                                 if(((x+csep) < gendata.numbytes) && f2)
1834                                 {
1835                                         scan = gendata.scanbuf + x + csep;
1836                                         yy = 1;
1837                                         for(y = s2; y < lines; y += yincr)
1838                                         {
1839                                                 if(scan[((y+q) & mask) * gendata.numbytes] & BLACK)
1840                                                         data[yy/8] |= bits[yy&7];
1841                                                 yy += 2;
1842                                         }
1843                                 }
1844 
1845                                 /* If we are in 1200dpi horizontal resolution,
1846                                  * alternate between nozzle columns to avoid
1847                                  * overstressing the printing head.
1848                                  */
1849                                 if(gendata.xres == 1200)
1850                                 {
1851                                         f1 = 1 - f1;
1852                                         f2 = 1 - f2;
1853                                 }
1854 
1855                                 /* Adjust data pointers */
1856                                 data += dy2;
1857                                 x += incr;
1858                         }
1859                 }
1860                 else /* direction == RIGHT */
1861                 {
1862                         /* For all the columns in this pass */
1863                         for(nn = 0; nn < numcols; nn += nxp)
1864                         {
1865                                 /* Encode the odd numbered nozzles */
1866                                 if((x < gendata.numbytes) && f1)
1867                                 {
1868                                         scan = gendata.scanbuf + x;
1869                                         yy = 1;
1870                                         for(y = s1; y < lines; y += yincr)
1871                                         {
1872                                                 if(scan[((y+q) & mask) * gendata.numbytes] & BLACK)
1873                                                         data[yy/8] |= bits[yy&7];
1874                                                 yy += 2;
1875                                         }
1876                                 }
1877 
1878                                 /* Encode the even numbered nozzles */
1879                                 if(((x-csep) >= 0) && f2)
1880                                 {
1881                                         scan = gendata.scanbuf + x - csep;
1882                                         yy = 0;
1883                                         for(y = s2; y < lines; y += yincr)
1884                                         {
1885                                                 if(scan[((y+q) & mask)*gendata.numbytes] & BLACK)
1886                                                         data[yy/8] |= bits[yy&7];
1887                                                 yy += 2;
1888                                         }
1889                                 }
1890 
1891                                 /* If we are in 1200dpi horizontal resolution,
1892                                  * alternate between nozzle columns to avoid
1893                                  * overstressing the printing head.
1894                                  */
1895                                 if(gendata.xres == 1200)
1896                                 {
1897                                         f1 = 1 - f1;
1898                                         f2 = 1 - f2;
1899                                 }
1900 
1901                                 /* Adjust data pointers */
1902                                 data += dy2;
1903                                 x += incr;
1904                         }
1905                 }
1906 
1907                 /* Convert the buffer to the shortest output format.
1908                  * Which is the first column of the output depends
1909                  * on the printing direction: it will be the left
1910                  * margin if we are printing left to right or the
1911                  * right margin if we are printing right to left.
1912                  */
1913                 if(gendata.direction == LEFT)
1914                         convbuf(LEFT, numcols, left);
1915                 else
1916                         convbuf(LEFT, numcols, right);
1917         }
1918 }
1919 
1920 /* This routine is the equivalent of encode_bw_buf() but
1921  * for color or photo cartridge. Since this routine is
1922  * heavily based on the B/W one, the comments here will
1923  * be somewhat less esaurient. Please have a look at
1924  * encode_bw_buf() to understand better how this routine
1925  * works: I will only pinpoint the differences between this
1926  * routine and encode_bw_buf().
1927  *
1928  * head: the head we are calculating the buffer for. It will
1929  *       be LEFT for a photo cartridge or RIGHT for a color one.
1930  */
1931 static void
encode_col_buf(int head)1932 encode_col_buf(int head)
1933 {
1934         int left, right, x, y, nn, mod;
1935         int nxp, yy, numcols, incr;
1936         int dy, dy2, csep, pass, f1;
1937         int f2, start, s1, s2, yincr;
1938         int q, mask, k, align, lines;
1939         byte *scan, *data;
1940 
1941         /* Here there are two more parameters: mask and lines, that
1942          * for color cartridges are both dependent on vertical
1943          * resolution. Since the buffer is "rolling", i.e. it is
1944          * implemented as a circular array, all the coordinates of
1945          * the buffer lines must be taken modulo the buffer length.
1946          * We choose a buffer length that is a power of two to be
1947          * able to turn the modulo operation into a bitwise AND, so
1948          * we need to set "mask" to the correct value for the AND.
1949          * Another difference is that "lines", i.e. the number of
1950          * lines to print in each pass, is based on the height of a
1951          * color pen. Since there are three color pens in each cartridge,
1952          * each color pen is treated separately to fully cover the
1953          * printing head.
1954          */
1955         switch(gendata.yres)
1956         {
1957                 case 300:
1958                         yincr = 1;
1959                         s1 = 0;
1960                         s2 = 0;
1961                         mask = 127;
1962                         lines = COLORPEN/2;
1963                         break;
1964 
1965                 default:
1966                 case 600:
1967                         yincr = 2;
1968                         s1 = 0;
1969                         s2 = 1;
1970                         mask = 255;
1971                         lines = COLORPEN;
1972                         break;
1973 
1974                 case 1200:
1975                         yincr = 4;
1976                         s1 = (gendata.ileave ? 1 : 0);
1977                         s2 = (gendata.ileave ? 3 : 2);
1978                         mask = 511;
1979                         lines = COLORPEN*2;
1980                         break;
1981         }
1982 
1983         /* Choose the vertical alignment depending on the head.
1984          * This is needed to vertically align the color cartridge
1985          * with the photo or black cartridge.
1986          */
1987         if(head == LEFT)
1988                 align = valign[PHOTOVALIGN];
1989         else
1990                 align = valign[COLORVALIGN];
1991 
1992         /* All the stuff below is exactly the same as in
1993          * encode_bw_buf(), and is therefore commented there.
1994          */
1995 
1996         csep = (gendata.bwsep * 2) / gendata.xrmul;
1997         nxp = gendata.numpasses;
1998         if(gendata.xres == 1200)nxp /= 2;
1999 
2000         dy = (gendata.numlines / 8) + 4;
2001         dy2 = dy * nxp;
2002 
2003         if(gendata.direction == LEFT)
2004         {
2005                 left = gendata.left - 2*csep;
2006                 right = gendata.right + csep;
2007         }
2008         else
2009         {
2010                 left = gendata.left - csep;
2011                 right = gendata.right + 2*csep;
2012         }
2013 
2014         numcols = right - left;
2015         mod = numcols - (numcols % nxp);
2016 
2017         f1 = 1;
2018         f2 = 1;
2019         if(gendata.yres == 300)
2020         {
2021                 f1 = 1;
2022                 f2 = 0;
2023         }
2024 
2025         /* For all passes */
2026         for(pass = 0; pass < gendata.numpasses; pass++)
2027         {
2028                 /* If there is data in the buffer which has not been
2029                  * sent to the printer yet, do it now.
2030                  */
2031                 if(gendata.fullflag)
2032                 {
2033                         fwrite(gendata.header, 3, 8, gendata.stream);
2034                         fwrite(gendata.outdata, gendata.stripebytes, 1, gendata.stream);
2035                         gendata.fullflag = FALSE;
2036                 }
2037 
2038                 /* All the stuff below is exactly the same as in
2039                  * encode_bw_buf(), and is therefore commented there.
2040                  */
2041 
2042                 memset(gendata.outdata, 0, gendata.numbytes * 30);
2043 
2044                 incr = nxp;
2045                 start = left + pass;
2046                 data = gendata.outdata + (pass*dy) + 4;
2047 
2048                 if(gendata.xres == 1200)
2049                 {
2050                         f1 = pass & 1;
2051                         f2 = 1 - f1;
2052 
2053                         start = left + (pass/2);
2054                         data = gendata.outdata + ((pass/2)*dy) + 4;
2055                 }
2056 
2057                 if(gendata.direction == RIGHT)
2058                 {
2059                         incr = -nxp;
2060                         start += mod;
2061                 }
2062 
2063                 /* Start column scanning */
2064                 x = start;
2065 
2066                 if(gendata.direction == LEFT)
2067                 {
2068                         /* For all the columns */
2069                         for(nn = 0; nn < numcols; nn += nxp)
2070                         {
2071                                 /* Encode the even numbered nozzles */
2072                                 if((x >= 0) && f1)
2073                                 {
2074                                         scan = gendata.scanbuf + x;
2075                                         yy = 0;
2076 
2077                                         /* In color printing there is one more loop to scan
2078                                          * all three color pens. We have to do exactly the
2079                                          * same things for all pens: the only differences are
2080                                          * the color encoding bit we are testing and the offset
2081                                          * from the beginning of the buffer and the offset of the
2082                                          * output data. All of this is stored into arrays. The
2083                                          * "penofs" array stores the offset of the first line of
2084                                          * each pen in the raster buffer. The array "colmask" stores
2085                                          * the encoding bits for the color of each pen, and it
2086                                          * is bidimensional because pen masks are different between
2087                                          * a color cartridge (where pens are Cyan, Magenta, Yellow)
2088                                          * and a photo cartridge (where pens are LightCyan,
2089                                          * LightMagenta and Black).
2090                                          */
2091                                         for(k=0; k<3; k++)
2092                                         {
2093                                                 q = gendata.firstline + align + penofs[k];
2094                                                 for(y = s1; y < lines; y += yincr)
2095                                                 {
2096                                                         if(scan[((y+q) & mask) * gendata.numbytes] & colmask[head][k])
2097                                                                 data[yy/8] |= bits[yy&7];
2098                                                         yy += 2;
2099                                                 }
2100                                         }
2101                                 }
2102 
2103                                 /* Encode the odd numbered nozzles */
2104                                 if(((x+csep) < gendata.numbytes) && f2)
2105                                 {
2106                                         scan = gendata.scanbuf + x + csep;
2107                                         yy = 1;
2108                                         for(k=0; k<3; k++)
2109                                         {
2110                                                 q = gendata.firstline + align + penofs[k];
2111                                                 for(y = s2; y < lines; y += yincr)
2112                                                 {
2113                                                         if(scan[((y+q) & mask) * gendata.numbytes] & colmask[head][k])
2114                                                                 data[yy/8] |= bits[yy&7];
2115                                                         yy += 2;
2116                                                 }
2117                                         }
2118                                 }
2119 
2120                                 /* If we are in 1200dpi horizontal resolution,
2121                                  * alternate between nozzle columns to avoid
2122                                  * overstressing the printing head.
2123                                  */
2124                                 if(gendata.xres == 1200)
2125                                 {
2126                                         f1 = 1 - f1;
2127                                         f2 = 1 - f2;
2128                                 }
2129 
2130                                 /* Adjust data pointers */
2131                                 data += dy2;
2132                                 x += incr;
2133                         }
2134                 }
2135                 else
2136                 {
2137                         /* For all the columns */
2138                         for(nn = 0; nn < numcols; nn += nxp)
2139                         {
2140                                 /* Encode the odd numbered nozzles */
2141                                 if((x < gendata.numbytes) && f1)
2142                                 {
2143                                         scan = gendata.scanbuf + x;
2144                                         yy = 1;
2145                                         for(k=0; k<3; k++)
2146                                         {
2147                                                 q = gendata.firstline + align + penofs[k];
2148                                                 for(y = s1; y < lines; y += yincr)
2149                                                 {
2150                                                         if(scan[((y+q) & mask) * gendata.numbytes] & colmask[head][k])
2151                                                                 data[yy/8] |= bits[yy&7];
2152                                                         yy += 2;
2153                                                 }
2154                                         }
2155                                 }
2156 
2157                                 /* Encode the even numbered nozzles */
2158                                 if(((x-csep) >= 0) && f2)
2159                                 {
2160                                         scan = gendata.scanbuf + x - csep;
2161                                         yy = 0;
2162                                         for(k=0; k<3; k++)
2163                                         {
2164                                                 q = gendata.firstline + align + penofs[k];
2165                                                 for(y = s2; y < lines; y += yincr)
2166                                                 {
2167                                                         if(scan[((y+q) & mask) * gendata.numbytes] & colmask[head][k])
2168                                                                 data[yy/8] |= bits[yy&7];
2169                                                         yy += 2;
2170                                                 }
2171                                         }
2172                                 }
2173 
2174                                 /* If we are in 1200dpi horizontal resolution,
2175                                  * alternate between nozzle columns to avoid
2176                                  * overstressing the printing head.
2177                                  */
2178                                 if(gendata.xres == 1200)
2179                                 {
2180                                         f1 = 1 - f1;
2181                                         f2 = 1 - f2;
2182                                 }
2183 
2184                                 /* Adjust data pointers */
2185                                 data += dy2;
2186                                 x += incr;
2187                         }
2188                 }
2189 
2190                 if(gendata.direction == LEFT)
2191                         convbuf(head, numcols, left);
2192                 else
2193                         convbuf(head, numcols, right);
2194         }
2195 }
2196 
2197 /* Fill monochrome buffer: this routine fills the buffer
2198  * with rasterized lines, skipping over vertical spacing
2199  * (i.e. completely blank lines). The routine is only
2200  * used in monochrome mode, where we print a full buffer
2201  * at each stripe. The color printing needs a different
2202  * routine which makes use of a circular buffer.
2203  *
2204  * vline: the line from which to start searching for data.
2205  */
2206 static int
fill_mono_buffer(int vline)2207 fill_mono_buffer(int vline)
2208 {
2209         byte *in_data, *data;
2210         int i, ret, ofs;
2211 
2212         /* Initialize the "data" pointer, that will be used to
2213          * scan all the lines in the buffer, and the "ofs" pointer
2214          * that will be used to mark the start of the "real" rasterized
2215          * data into the buffer (see below). To compensate for the offsets
2216          * caused by the horizontal spacing between nozzle columns on a
2217          * cartridge, the head must start before the horizontal margin, so
2218          * the buffer width is slightly bigger than the width of the
2219          * rasterized lines. The difference is the "guard offset", and the
2220          * variables gendata.numbytes and gendata.numrbytes hold respectively
2221          * the number of bytes in a buffer line and the number of bytes in a
2222          * rasterized scanline, while gendata.goffset contains the number of
2223          * bytes reserved to the guard offset on each side of the scanline.
2224          */
2225         data = gendata.scanbuf;
2226         ofs = gendata.goffset;
2227 
2228         /* Cycle until we have no more lines on the page */
2229         while(vline < gendata.numvlines)
2230         {
2231                 /* Ask Ghostscript for one rasterized line */
2232                 gdev_prn_get_bits((gx_device_printer *)gendata.dev,
2233                                                                                         vline, data+ofs, &in_data);
2234 
2235                 /* And check if it's all zero: if not, break out of
2236                  * the loop. This nice trick with memcpy it's by Stephen
2237                  * Taylor (if I'm not wrong...)
2238 
2239                  */
2240                 if(in_data[0] != 0 ||
2241                          memcmp(in_data, in_data+1,gendata.numrbytes-1))break;
2242                 vline++;
2243         }
2244 
2245         /* If we are here because no non-empty lines were found before
2246          * the end of the page, our work is over. Return to the caller
2247          * saying that this is the last buffer (LAST bit set) and it's
2248          * empty (no LHDATA or RHDATA bit set).
2249          */
2250         if(vline >= gendata.numvlines)return(LAST);
2251 
2252         /* This buffer contains at least one non-empty line.
2253          * Adjust the current vertical position and load the first
2254          * line into the buffer.
2255          */
2256         gendata.curvline = vline;
2257         memset(data, 0, gendata.numbytes);
2258         if(in_data != data+ofs)memcpy(data+ofs, in_data, gendata.numrbytes);
2259 
2260         vline++;
2261         data += gendata.numbytes;
2262 
2263         /* Now initialize the return value to LHDATA (since at least
2264          * one non-blank line was found, this buffer contains data, and
2265          * it is obviously left-head data because we are in monochromatic
2266          * mode and so we are printing with left head only).
2267          * After that, get as many rasterized lines as needed to fill the
2268          * buffer, checking if in the process we have reached the end of
2269          * the page.
2270          */
2271         ret = LHDATA;
2272         for(i=1; i<gendata.numblines; i++)
2273         {
2274                 memset(data, 0, gendata.numbytes);
2275                 if(vline > gendata.numvlines)
2276                 {
2277                         /* Ok, we are at the end of the page, so set the LAST bit
2278                          * in the return value but don't exit the loop because we
2279                          * need to make sure all remaining lines in the buffer will
2280                          * be blanked (exiting now would leave them untouched from
2281                          * the previous stripe). This is needed to avoid printing
2282                          * random data under the bottom margin.
2283                          */
2284                         ret = LHDATA | LAST;
2285                 }
2286                 else
2287                 {
2288                         /* If we are not at the end of the page, copy one more
2289                          * scanline into the buffer.
2290                          */
2291                         gdev_prn_get_bits((gx_device_printer *)gendata.dev,
2292                                                                                                 vline, data+ofs, &in_data);
2293                         if(in_data != data+ofs)memcpy(data+ofs, in_data, gendata.numrbytes);
2294                 }
2295 
2296                 vline++;
2297                 data += gendata.numbytes;
2298 
2299         }
2300 
2301         return(ret);
2302 }
2303 
2304 /* Fill the buffer with initial data.
2305  * This routine is used to load the first buffer at the
2306  * beginning of the page. If we are printing in monochromatic
2307  * mode, we just call fill_mono_buffer for the first line.
2308  * If we are printing in color mode, we have a problem to
2309  * solve: since the color pen are stacked vertically, we
2310  * need multiple head passes to print all colors on the
2311  * same line. So, to simplify all, we start with the paper
2312  * at a fixed vertical position, even if it's blank, and
2313  * then we go down in fixed increments, equal to the height
2314  * of a color pen. This means we check all buffers without
2315  * skipping over blank ones, but since we actually send the
2316  * printing commands to the printer only when there is something
2317  * to print, there is no speed impact.
2318  */
2319 static int
init_buffer(void)2320 init_buffer(void)
2321 {
2322         byte *in_data, *data;
2323         int i, ret, p1, p2, ofs;
2324 
2325         data = gendata.scanbuf;
2326         ofs = gendata.goffset;
2327 
2328         if(gendata.rendermode == LXM3200_M)return(fill_mono_buffer(0));
2329 
2330         /* We position the heads with the bottom color pen (the
2331          * yellow one in the color cartridge and the black one
2332          * in the photo cartridge) just covering the first lines
2333          * of the paper sheet. So the first buffer is divided in
2334          * two parts: "p1" is the number of lines above the top
2335          * border and "p2" the number of lines below.
2336          */
2337         p1 = 368 / gendata.yrmul;
2338         p2 = 144 / gendata.yrmul;
2339 
2340         /* Initialize the counters */
2341         gendata.curvline = -p1;
2342         gendata.lastblack = gendata.curvline - 1;
2343         data = gendata.scanbuf;
2344 
2345         /* Clear the lines of the buffer that correspond to
2346          * lines above the top margin: of course we don't
2347          * want to print anything on the air...
2348          */
2349         for(i=0; i<p1; i++)
2350         {
2351                 memset(data, 0, gendata.numbytes);
2352                 data += gendata.numbytes;
2353         }
2354 
2355         /* And now load the last part of the buffer.
2356          * Note that here we don't check for blank lines,
2357          * this will be cared for later.
2358          */
2359         for(i=0; i<p2; i++)
2360         {
2361                 memset(data, 0, gendata.numbytes);
2362 
2363                 if(i < gendata.numvlines)
2364                 {
2365                         gdev_prn_get_bits((gx_device_printer *)gendata.dev,
2366                                                                                                 i, data+ofs, &in_data);
2367                         if(in_data != data+ofs)memcpy(data+ofs, in_data, gendata.numrbytes);
2368                 }
2369 
2370                 data += gendata.numbytes;
2371         }
2372 
2373         gendata.firstline = 0;
2374 
2375         /* Now check the return value. If by chance we are under
2376          * the bottom margin, add the LAST bit to the return value.
2377          * Of course, since this is the first buffer of the page,
2378          * it's not likely we will reach the bottom margin in
2379          * this pass. Anyway this is code that will be executed
2380          * only once per page, so better safe than sorry.
2381          */
2382         ret = (gendata.numvlines < p2 ? LAST : 0) | qualify_buffer();
2383 
2384         return(ret);
2385 }
2386 
2387 /* This function checks if the current buffer contains
2388  * data to be printed with the left or right head.
2389  * It assumes that we are printing in color mode, and it
2390  * is useful to minimize the number of needed passes.
2391  * When we are printing in monochrome mode we directly skip
2392  * over blank lines, so this routine is not needed.
2393  */
2394 static int
qualify_buffer(void)2395 qualify_buffer(void)
2396 {
2397         int i, j, k, ret;
2398         int rmsk, q, v1;
2399         int bpsz, cpsz;
2400         byte *data;
2401 
2402         ret = 0;
2403 
2404         /* Set variables which contains the size, in rows, of
2405          * each color pen and of the black pen in color mode,
2406          * adjusting for different resolution settings.
2407          * Also set the mask used to rollover the buffer.
2408          */
2409         cpsz = (COLORPEN * 2) / gendata.yrmul;
2410         bpsz = (BWCOLPEN * 2) / gendata.yrmul;
2411         rmsk = gendata.numblines - 1;
2412 
2413         /* Check the right head data, it is always a color cartridge */
2414         for(k=0; k<3 && ret==0; k++)
2415         {
2416                 /* For each pen, scan all the bytes on each row of
2417                  * the buffer that is covered by the current pen,
2418                  * ORing together all the bits.
2419                  */
2420                 v1 = 0;
2421                 q = gendata.firstline + valign[COLORVALIGN] + penofs[k];
2422                 for(i=0; i<cpsz; i++)
2423                 {
2424                         data = gendata.scanbuf + ((q+i) & rmsk)*gendata.numbytes;
2425                         for(j=0; j<gendata.numbytes; j++)v1 |= *data++;
2426                 }
2427                 /* If the result of the OR has the proper color bit
2428                  * set, it means that this buffer contains at least
2429                  * one pixel of this pen, so we need a color pass.
2430                  * Note that we exit as soon as we find a color bit
2431                  * set, because if at least one color pen is used
2432                  * in this buffer we need to do a color pass anyway,
2433                  * so there's no need to check the other two pens.
2434                  */
2435                 if(v1 & colmask[RIGHT][k])ret |= RHDATA;
2436         }
2437 
2438         /* Check the left head data: it could be a black or
2439          * a photo cartridge, depending on the printing mode.
2440          */
2441         if(gendata.rendermode == LXM3200_C)
2442         {
2443                 /* We are in standard color mode: the left cartridge
2444                  * is a black cartridge used in 192 nozzles mode.
2445                  * This is done exactly in the same way as above, but
2446                  * without the outer loop because we have only one
2447                  * color pen on this cartridge.
2448                  */
2449                 v1 = 0;
2450                 q = gendata.firstline + valign[BLACKVALIGN];
2451                 for(i=0; i<bpsz; i++)
2452                 {
2453                         data = gendata.scanbuf + ((q+i) & rmsk)*gendata.numbytes;
2454                         for(j=0; j<gendata.numbytes; j++)v1 |= *data++;
2455                 }
2456                 if(v1 & BLACK)ret |= LHDATA;
2457         }
2458         else
2459         {
2460                 /* If we are here we need to check for a photo cartridge
2461                  * (this routine is never called in monochrome mode, so
2462                  * if we are not in color mode we must be in photo mode).
2463                  * This routine is identical to the color routine above.
2464                  */
2465                 for(k=0; k<3 && !(ret & LHDATA); k++)
2466                 {
2467                         v1 = 0;
2468                         q = gendata.firstline + valign[PHOTOVALIGN] + penofs[k];
2469                         for(i=0; i<cpsz; i++)
2470                         {
2471                                 data = gendata.scanbuf + ((q+i) & rmsk)*gendata.numbytes;
2472                                 for(j=0; j<gendata.numbytes; j++)v1 |= *data++;
2473                         }
2474                         if(v1 & colmask[LEFT][k])ret |= LHDATA;
2475                 }
2476         }
2477 
2478         return(ret);
2479 }
2480 
2481 /* This functions rolls the circular buffer by the
2482  * number of lines of one color pen, reading new
2483  * lines to refill the buffer.
2484  * In color mode we use a circular buffer because
2485  * we need to read the same lines more than once.
2486  * So when we are forwarding to the next pass we
2487  * simply read in the new lines and then update the
2488  * pointers, without actually moving data into memory.
2489  * The need to read the same data more than once arises
2490  * from the fact that the color pens are vertically
2491  * stacked, so we need to read a data line to lay down
2492  * the yellow component at the first pass. We need to
2493  * read it again at the next pass to lay down magenta,
2494  * and on the last pass we read the same line once more
2495  * to lay down the cyan component.
2496  */
2497 static int
roll_buffer(void)2498 roll_buffer(void)
2499 {
2500         int i, ret, fline, vl, ofs;
2501         int cpen, cmask, lline;
2502         byte *data, *in_data;
2503 
2504         /* Adjust the size of the color pen and the
2505          * mask to take into account the current resolution
2506          */
2507         cpen = (COLORPEN * 2) / gendata.yrmul;
2508         cmask = (gendata.numblines) - 1;
2509 
2510         /* Calculate the line number corresponding to
2511          * the last buffer we can print before being
2512          * forced to eject the page. At 600dpi this
2513          * has been experimentally determined to be
2514          * 112 lines from the bottom of the page.
2515          */
2516         lline = gendata.numvlines - (224 / gendata.yrmul);
2517 
2518         /* Roll the buffer by advancing the first line
2519          * pointer by the height of one color pen.
2520          */
2521         fline = gendata.firstline;
2522         gendata.firstline = (fline + cpen) & cmask;
2523 
2524         /* Now calculate the pointer to the first "fresh"
2525          * line on the page, i.e. the first line we must
2526          * read into the buffer at this pass.
2527          */
2528         vl = gendata.curvline + cmask + 1;
2529 
2530         /* Take into account the guard offset */
2531         ofs = gendata.goffset;
2532 
2533         /* Initialize the return value and update the
2534          * current vertical position on the page, while
2535          * checking if we have reached the last printable
2536          * buffer.
2537          */
2538         ret = 0;
2539         gendata.curvline += cpen;
2540         if(gendata.curvline >= lline)ret = LAST;
2541 
2542         /* Now read "fresh" rasterized scanlines into the
2543          * input buffer.
2544          */
2545         for(i=0; i<cpen; i++)
2546         {
2547                 data = gendata.scanbuf + ((fline + i) & cmask) * gendata.numbytes;
2548 
2549                 memset(data, 0, gendata.numbytes);
2550                 if(vl < gendata.numvlines)
2551                 {
2552                         gdev_prn_get_bits((gx_device_printer *)gendata.dev,
2553                                                                                                 vl, data+ofs, &in_data);
2554                         if(in_data != data+ofs)memcpy(data+ofs, in_data, gendata.numrbytes);
2555                 }
2556                 vl++;
2557         }
2558 
2559         /* And test for the presence of actual data to print */
2560         ret |= qualify_buffer();
2561 
2562         return(ret);
2563 }
2564 
2565 /* Calculate the margins of one line, i.e. the leftmost
2566  * and the rightmost non-blank pixel on the line.
2567  *
2568  * data:  the pointer to the data for this line
2569  * mask:  the mask with the bits to check for: if the buffer
2570  *        contains data which is not on the mask it will be
2571  *        ignored (for the purpose of calculating margins)
2572  * left:  calculated left margin (output variable)
2573  * right: calculated right margin (output variable)
2574  */
2575 static void
calclinemargins(byte * data,int mask,int * left,int * right)2576 calclinemargins(byte *data, int mask, int *left, int *right)
2577 {
2578         int l,r,num;
2579 
2580         num = gendata.numbytes - 1;
2581 
2582         l = 0;
2583         while((l <= num) && ((data[l] & mask) == 0))l++;
2584 
2585         r = num;
2586         while((r >= 0) && ((data[r] & mask) == 0))r--;
2587 
2588         *left = l;
2589         *right = r;
2590 }
2591 
2592 /* Calculate the margins of the whole buffer. The
2593  * calculation accounts separately for the data to
2594  * be printed with the left or with the right head,
2595  * so we can try to minimize the head movement even
2596  * on multiple passes.
2597  *
2598  * head: the code of the head we are calculating
2599  *       margins for (LEFT or RIGHT)
2600  */
2601 static void
calcbufmargins(int head)2602 calcbufmargins(int head)
2603 {
2604         int i, l1, r1, q, k;
2605         int mleft, mright, nl;
2606         int cpen, cmask, al;
2607         byte *scan;
2608 
2609         /* Adjust mask and pen height according to vertical resolution */
2610         cpen = (COLORPEN * 2) / gendata.yrmul;
2611         cmask = (gendata.numblines) - 1;
2612 
2613         /* Calculate margins for a color or photo cartridge */
2614         if(head == RIGHT || (gendata.rendermode == LXM3200_P))
2615         {
2616                 /* Get correct vertical aligment */
2617                 al = (head == LEFT ? PHOTOVALIGN : COLORVALIGN);
2618 
2619                 q = gendata.firstline + valign[al];
2620 
2621                 /* Calculate margins for first line, using those values
2622                  * to initialize the max and min values.
2623                  */
2624                 scan = gendata.scanbuf + ((q+penofs[0]) & cmask)*gendata.numbytes;
2625                 calclinemargins(scan, colmask[head][0], &mleft, &mright);
2626 
2627                 /* And now scan all the remaining buffer. We scan according
2628                  * to color pens, i.e. we calculate the margin on the rows
2629                  * where magenta will be laid down taking into account magenta
2630                  * pixels only, and this will be the magenta submargin. After
2631                  * having done that for cyan and yellow as well, we take as the
2632                  * global margin the smaller space that contains all the three
2633                  * submargins.
2634                  */
2635                 for(k=0; k<3; k++)
2636                 {
2637                         for(i=0; i<cpen; i++)
2638                         {
2639                                 scan = gendata.scanbuf + ((q+i+penofs[k]) & cmask)*gendata.numbytes;
2640                                 calclinemargins(scan, colmask[head][k], &l1, &r1);
2641                                 mleft = min(mleft, l1);
2642                                 mright = max(mright, r1);
2643                         }
2644                 }
2645 
2646                 gendata.left = mleft;
2647                 gendata.right = mright;
2648 
2649                 return;
2650         }
2651 
2652         /* Calculate buffer margins for a black head. This is
2653          * almost exactly the same as before, but now we do
2654          * a single pass because we have only one black pen.
2655          */
2656         if(gendata.rendermode == LXM3200_M)
2657         {
2658                 /* Monochromatic mode: we use 208 nozzles and
2659                  * all the buffer, so the initial offset is zero.
2660                  */
2661 
2662                 scan = gendata.scanbuf;
2663                 calclinemargins(scan, BLACK, &mleft, &mright);
2664 
2665                 for(i=1; i<gendata.numblines; i++)
2666                 {
2667                         scan += gendata.numbytes;
2668                         calclinemargins(scan, BLACK, &l1, &r1);
2669                         mleft = min(mleft, l1);
2670                         mright = max(mright, r1);
2671                 }
2672 
2673                 gendata.left = mleft;
2674                 gendata.right = mright;
2675 
2676                 return;
2677         }
2678 
2679         /* Standard color mode: we use 192 nozzles and must
2680          * take into account the vertical alignment.
2681          */
2682 
2683         nl = (gendata.numlines * 2) / gendata.yrmul;
2684         q = gendata.firstline + valign[BLACKVALIGN];
2685 
2686         scan = gendata.scanbuf + (q & cmask)*gendata.numbytes;
2687         calclinemargins(scan, BLACK, &mleft, &mright);
2688 
2689         for(i=1; i<nl; i++)
2690         {
2691                 scan = gendata.scanbuf + ((q+i) & cmask)*gendata.numbytes;
2692                 calclinemargins(scan, BLACK, &l1, &r1);
2693                 mleft = min(mleft, l1);
2694                 mright = max(mright, r1);
2695         }
2696         gendata.left = mleft;
2697         gendata.right = mright;
2698 }
2699 
2700 /*
2701  * This is the main routine that prints in
2702  * standard color mode.
2703  */
2704 static void
print_color_page(void)2705 print_color_page(void)
2706 {
2707         int res, lline, cmask;
2708         int i, j, nl, q, sk;
2709         byte *scan;
2710 
2711         /* Set the blackskip value depending on vertical resolution.
2712          * Since we have a black pen which is 3 times as high as
2713          * each color pen, we must print black only once every three
2714          * passes. So we take into account on which line we printed
2715          * the last black stripe and then we print another only if
2716          * the current line is at least "sk" lines after that.
2717          */
2718         sk = (BWCOLPEN * 2) / gendata.yrmul;
2719 
2720         /* Get the first buffer, and if it's empty continue
2721          * to skip forward without doing anything.
2722          */
2723         res = init_buffer();
2724         while(res == 0)res = roll_buffer();
2725 
2726         /* If this buffer happens to be the last one,
2727          * and empty as well, we had a blank page.
2728          * Just exit without ado.
2729          */
2730         if(res == LAST)return;
2731 
2732         /* This is the first non-blank line of the
2733          * page: issue a vertical skip command to
2734          * advance the paper to proper position.
2735          */
2736         skiplines(gendata.curvline, COLTOPSTART);
2737 
2738         /* "lline" holds the number of the first line of
2739          * the last buffer printed, either with left or
2740          * right head. This is needed to keep track of
2741          * how many lines we must skip from one stripe to
2742          * the next (if we encounter blank buffers we just
2743          * ignore them without moving the head, so we need
2744          * to do the proper vertical motion in one single
2745          * pass as soon as we encounter a non-blank buffer).
2746          */
2747         lline = gendata.curvline;
2748 
2749         /* Now depending on the data we have into the
2750          * buffer, print with the left head, right
2751          * head or both.
2752          * NOTE: this is the first buffer, and it needs
2753          * to be treated specially from the others.
2754          * The main difference is that we usually finalize
2755          * the buffer (issuing the print commands) at the
2756          * start of the next buffer, and not at the end of
2757          * the current one. This is because the Lexmark 3200
2758          * wants to know where to leave the printing head
2759          * at the end of each printing command, but we can't
2760          * know that until we start the next buffer so discovering
2761          * its margins and position. The solution is that we keep
2762          * "suspended" each buffer until we find another valid one.
2763          * The first buffer is special since there is no previous
2764          * buffer to finalize.
2765          * NOTE: I will comment the general case below, because
2766          * this code is simply a subset of the main loop.
2767          */
2768         switch(res)
2769         {
2770                 case LHDATA:
2771                         calcbufmargins(LEFT);
2772                         gendata.ileave = 0;
2773                         encode_bw_buf();
2774                         gendata.lastblack = gendata.curvline + sk;
2775                         lline = gendata.curvline;
2776                         if(gendata.yres == 1200)
2777                         {
2778                                 finalizeheader(1, LEFT);
2779                                 gendata.ileave = 1;
2780                                 encode_bw_buf();
2781                                 lline++;
2782                         }
2783                         break;
2784 
2785                 case RHDATA:
2786                         calcbufmargins(RIGHT);
2787                         gendata.ileave = 0;
2788                         encode_col_buf(RIGHT);
2789                         lline = gendata.curvline;
2790                         if(gendata.yres == 1200)
2791                         {
2792                                 finalizeheader(1, RIGHT);
2793                                 gendata.ileave = 1;
2794                                 encode_col_buf(RIGHT);
2795                                 lline++;
2796                         }
2797                         break;
2798 
2799                 case LHDATA|RHDATA:
2800                         calcbufmargins(LEFT);
2801                         gendata.ileave = 0;
2802                         encode_bw_buf();
2803                         gendata.lastblack = gendata.curvline + sk;
2804                         calcbufmargins(RIGHT);
2805                         finalizeheader(0, RIGHT);
2806                         encode_col_buf(RIGHT);
2807                         lline = gendata.curvline;
2808                         if(gendata.yres == 1200)
2809                         {
2810                                 calcbufmargins(LEFT);
2811                                 finalizeheader(1, LEFT);
2812                                 gendata.ileave = 1;
2813                                 encode_bw_buf();
2814                                 calcbufmargins(RIGHT);
2815                                 finalizeheader(0, RIGHT);
2816                                 encode_col_buf(RIGHT);
2817                                 lline++;
2818                         }
2819                         break;
2820         }
2821 
2822         /* Skip to next buffer */
2823         res = roll_buffer();
2824 
2825         /* Start the main loop. Here we do all the stuff required
2826          * to print buffers properly.
2827          */
2828         while(!(res & LAST))
2829         {
2830                 /* If we haven't forwarded until "lastblack", do not
2831                  * print black data because it has been printed on
2832                  * previous passes. So, if we are below gendata.lastblack
2833                  * clear the LHDATA flag to ignore left-head data.
2834                  */
2835                 if(gendata.curvline < gendata.lastblack)res &= ~LHDATA;
2836 
2837                 /* And now start examining the buffer for data */
2838                 switch(res)
2839                 {
2840                         /* We have left head data */
2841                         case LHDATA:
2842 
2843                                 /* Calculate the margins of this buffer */
2844                                 calcbufmargins(LEFT);
2845 
2846                                 /* And then finalize the previous buffer. We can't
2847                                  * do this until now, because only now we know the
2848                                  * margins and vertical position of the next buffer,
2849                                  * which are required data to calculate the final
2850                                  * head position at the end of the previous buffer.
2851                                  */
2852                                 finalizeheader(gendata.curvline - lline, LEFT);
2853 
2854                                 /* Set interleave to zero (only meaningful in 1200dpi
2855                                  * vertical mode.
2856                                  */
2857                                 gendata.ileave = 0;
2858 
2859                                 /* Encode this buffer making it the current buffer */
2860                                 encode_bw_buf();
2861 
2862                                 /* Since we are printing a black buffer, update
2863                                  * gendata.lastblack to point to the first line
2864                                  * not covered by this black pass.
2865                                  */
2866                                 gendata.lastblack = gendata.curvline + sk;
2867 
2868                                 /* And update "lline" as well */
2869                                 lline = gendata.curvline;
2870 
2871                                 /* If we are printing at 1200 dpi vertical, we must
2872                                  * do one more pass, interleaved with the one before.
2873                                  */
2874                                 if(gendata.yres == 1200)
2875                                 {
2876                                         /* Finalize previous buffer, moving down 1/1200th
2877                                          * of an inch to properly interleave the two passes.
2878                                          * This is naive: we should do something here, because
2879                                          * this way two adjacent lines are printed by the same
2880                                          * nozzle, and there is the danger of having a slight
2881                                          * banding on output (no more than 1/600th of an inch,
2882                                          * but maybe noticeable).
2883                                          */
2884                                         finalizeheader(1, LEFT);
2885 
2886                                         /* Set interleave to 1 to start an interleaved pass */
2887                                         gendata.ileave = 1;
2888 
2889                                         /* Encode the buffer, and not finalize it: we leave
2890                                          * the buffer suspended until we find another buffer
2891                                          * to print.
2892                                          */
2893                                         encode_bw_buf();
2894 
2895                                         /* And adjust "lline" because to print the interleaved
2896                                          * pass we have moved down one line, so we need to
2897                                          * skip one line less to print the next buffer.
2898                                          */
2899                                         lline++;
2900                                 }
2901                                 break;
2902 
2903                         /* Right head data. This is absolutely identical to the
2904                          * code above for left head data, with two exceptions: all
2905                          * the "LEFT" codes are changed to "RIGHT" and we don't
2906                          * update gendata.lastblack because we are printing a
2907                          * color stripe and not a black one.
2908                          */
2909                   case RHDATA:
2910                                 calcbufmargins(RIGHT);
2911                                 finalizeheader(gendata.curvline - lline, RIGHT);
2912                                 gendata.ileave = 0;
2913                                 encode_col_buf(RIGHT);
2914                                 lline = gendata.curvline;
2915                                 if(gendata.yres == 1200)
2916                                 {
2917                                         finalizeheader(1, RIGHT);
2918                                         gendata.ileave = 1;
2919                                         encode_col_buf(RIGHT);
2920                                         lline++;
2921                                 }
2922                                 break;
2923 
2924                         /* We have both left and right head data (i.e. black and
2925                          * color on the same stripe).
2926                          * The code here is identical to the code for the left data
2927                          * only and right data only cases above. But they are
2928                          * interleaved, because since we can't take back the paper
2929                          * once it's advanced, in case we are printing at 1200 dpi
2930                          * vertical (and so we need two interlaced passes) we need
2931                          * to do both the first black and the first color pass,
2932                          * advance the paper and then do the second black and the
2933                          * second color pass. Simply appendig the two code pieces
2934                          * above would not work.
2935                          */
2936                         case LHDATA|RHDATA:
2937                                 calcbufmargins(LEFT);
2938                                 finalizeheader(gendata.curvline - lline, LEFT);
2939                                 gendata.ileave = 0;
2940                                 encode_bw_buf();
2941                                 gendata.lastblack = gendata.curvline + sk;
2942                                 calcbufmargins(RIGHT);
2943                                 finalizeheader(0, RIGHT);
2944                                 encode_col_buf(RIGHT);
2945                                 lline = gendata.curvline;
2946                                 if(gendata.yres == 1200)
2947                                 {
2948                                         calcbufmargins(LEFT);
2949                                         finalizeheader(1, LEFT);
2950                                         gendata.ileave = 1;
2951                                         encode_bw_buf();
2952                                         calcbufmargins(RIGHT);
2953                                         finalizeheader(0, RIGHT);
2954                                         encode_col_buf(RIGHT);
2955                                         lline++;
2956                                 }
2957                                 break;
2958                 }
2959 
2960                 /* Get another buffer */
2961                 res = roll_buffer();
2962         }
2963 
2964         /* Last buffer. We treat this one specially as well,
2965          * because we don't have a subsequent buffer to print,
2966          * and so we need to finalize this buffers as soon as
2967          * possible.
2968          */
2969         res = qualify_buffer();
2970 
2971         /* Void the printed blacks. Since we are printing the
2972          * last buffer, it could happen that we have advanced
2973          * from the last time we printed a black stripe but
2974          * we are not yet at the point where another black
2975          * stripe would have been triggered. This would cause
2976          * an eventual black component in the last lines of
2977          * the page to be ignored.
2978          * To avoid the problem we do an unconditional black
2979          * pass, but we also must clear the black bits from the
2980          * lines we have already printed otherwise we would
2981          * print them twice.
2982          */
2983         if((res & LHDATA) && (gendata.curvline <= gendata.lastblack))
2984         {
2985                 /* Find how many black lines we have yet printed
2986                  * are still in the buffer
2987                  */
2988                 nl = gendata.lastblack - gendata.curvline;
2989 
2990                 /* And now remove the BLACK bit from them */
2991 
2992                 q = gendata.firstline + valign[BLACKVALIGN];
2993                 cmask = (gendata.numblines) - 1;
2994                 for(i=0; i<nl; i++)
2995                 {
2996                         scan = gendata.scanbuf + ((i+q) & cmask)*gendata.numbytes;
2997                         for(j=0; j<gendata.numbytes; j++)
2998                         {
2999                                 *scan &= ~BLACK;
3000                                 scan++;
3001                         }
3002                 }
3003         }
3004 
3005         /* Now we can print the last buffer as usual.
3006          * This is perfectly identical to the code
3007          * into the loop above: we are replicating it
3008          * only because we need the blanking code above
3009          * to be executed before this code.
3010          * Maybe there is a better way to do it...
3011          */
3012         switch(res)
3013         {
3014                 case LHDATA:
3015                         calcbufmargins(LEFT);
3016                         finalizeheader(gendata.curvline - lline, LEFT);
3017                         gendata.ileave = 0;
3018                         encode_bw_buf();
3019                         if(gendata.yres == 1200)
3020                         {
3021                                 finalizeheader(1, LEFT);
3022                                 gendata.ileave = 1;
3023                                 encode_bw_buf();
3024                                 lline++;
3025                         }
3026                         break;
3027 
3028                 case RHDATA:
3029                         calcbufmargins(RIGHT);
3030                         finalizeheader(gendata.curvline - lline, RIGHT);
3031                         gendata.ileave = 0;
3032                         encode_col_buf(RIGHT);
3033                         if(gendata.yres == 1200)
3034                         {
3035                                 finalizeheader(1, RIGHT);
3036                                 gendata.ileave = 1;
3037                                 encode_col_buf(RIGHT);
3038                                 lline++;
3039                         }
3040                         break;
3041 
3042                 case LHDATA|RHDATA:
3043                         calcbufmargins(LEFT);
3044                         finalizeheader(gendata.curvline - lline, LEFT);
3045                         gendata.ileave = 0;
3046                         encode_bw_buf();
3047                         calcbufmargins(RIGHT);
3048                         finalizeheader(0, RIGHT);
3049                         encode_col_buf(RIGHT);
3050                         if(gendata.yres == 1200)
3051                         {
3052                                 calcbufmargins(LEFT);
3053                                 finalizeheader(1, LEFT);
3054                                 gendata.ileave = 1;
3055                                 encode_bw_buf();
3056                                 calcbufmargins(RIGHT);
3057                                 finalizeheader(0, RIGHT);
3058                                 encode_col_buf(RIGHT);
3059                                 lline++;
3060                         }
3061                         break;
3062         }
3063 
3064         /* Now finalize the header using a value of "0" for
3065          * the vertical skip (no need to move down: the
3066          * paper is about to be ejected) and -1 for the
3067          * head (meaning: last buffer, don't care for the
3068          * final head position, it will be reset unconditionally
3069          * by the trailing sequence).
3070          */
3071         finalizeheader(0, -1);
3072 }
3073 
3074 /* This is the equivalent of print_color_page()
3075  * for monochrome output. It is almost identical,
3076  * only much simpler because now we are printing
3077  * with only one head.
3078  */
3079 static void
print_mono_page(void)3080 print_mono_page(void)
3081 {
3082         int res, lline;
3083 
3084         /* Load the first buffer, skipping over
3085          * blank lines (if any).
3086          */
3087         res = init_buffer();
3088 
3089         /* If we happen to have a buffer which is LAST
3090          * and empty, we have a blank page to print:
3091          * just say goodbye.
3092          */
3093         if(res == LAST)return;
3094 
3095         /* Skip enough lines to reach the start of
3096          * the first stripe to print.
3097          */
3098         skiplines(gendata.curvline, BWTOPSTART);
3099         lline = gendata.curvline;
3100 
3101         /* And now print the first buffer. This part of
3102          * the code is identical to the LHDATA part in
3103          * print_color_page()
3104          */
3105         calcbufmargins(LEFT);
3106         gendata.ileave = 0;
3107         encode_bw_buf();
3108         lline = gendata.curvline;
3109         if(gendata.yres == 1200)
3110         {
3111                 finalizeheader(1, LEFT);
3112                 gendata.ileave = 1;
3113                 encode_bw_buf();
3114                 lline++;
3115         }
3116 
3117         /* And now load another buffer, starting to
3118          * look for it from the first line after the
3119          * pass we have just done.
3120          */
3121         res = fill_mono_buffer(gendata.curvline + gendata.numblines);
3122 
3123         /* Now loop. Even this code is identical
3124          * to the code above: the only difference
3125          * is that here we also finalize the previous
3126          * buffer before encoding this one. No need
3127          * to check if the buffer is empty because
3128          * a buffer is reported only if it's full
3129          * or if it is the last one, so if it's not
3130          * the last it must be full.
3131          */
3132         while(!(res & LAST))
3133         {
3134                 calcbufmargins(LEFT);
3135                 finalizeheader(gendata.curvline - lline, LEFT);
3136                 gendata.ileave = 0;
3137                 encode_bw_buf();
3138                 lline = gendata.curvline;
3139                 if(gendata.yres == 1200)
3140                 {
3141                         finalizeheader(1, LEFT);
3142                         gendata.ileave = 1;
3143                         encode_bw_buf();
3144                         lline++;
3145                 }
3146 
3147                 /* Get another buffer, and so on */
3148                 res = fill_mono_buffer(gendata.curvline + gendata.numblines);
3149         }
3150 
3151         /* Last buffer. This can be either empty or full.
3152          * If it's not empty (LHDATA bit set), print it.
3153          */
3154         if(res & LHDATA)
3155         {
3156                 calcbufmargins(LEFT);
3157                 finalizeheader(gendata.curvline - lline, LEFT);
3158                 encode_bw_buf();
3159                 if(gendata.yres == 1200)
3160                 {
3161                         finalizeheader(1, LEFT);
3162                         gendata.ileave = 1;
3163                         encode_bw_buf();
3164                         lline++;
3165                 }
3166         }
3167 
3168         /* Finalize the last buffer */
3169         finalizeheader(0, -1);
3170 }
3171 
3172 /* This is the equivalent of print_color_page()
3173  * for photoquality output. They are almost identical,
3174  * the only real difference is that we now are
3175  * printing with two identical heads, so there is
3176  * no need to care for different heights of the
3177  * printing pens (i.e.: no "lastblack" tricks).
3178  */
3179 static void
print_photo_page(void)3180 print_photo_page(void)
3181 {
3182         int res, lline;
3183 
3184         res = init_buffer();
3185         while(res == 0)res = roll_buffer();
3186 
3187         if(res == LAST)return;
3188 
3189         skiplines(gendata.curvline, COLTOPSTART);
3190         lline = gendata.curvline;
3191 
3192         switch(res)
3193         {
3194                 case LHDATA:
3195                         calcbufmargins(LEFT);
3196                         gendata.ileave = 0;
3197                         encode_col_buf(LEFT);
3198                         lline = gendata.curvline;
3199                         if(gendata.yres == 1200)
3200                         {
3201                                 finalizeheader(1, LEFT);
3202                                 gendata.ileave = 1;
3203                                 encode_col_buf(LEFT);
3204                                 lline++;
3205                         }
3206                         break;
3207 
3208                 case RHDATA:
3209                         calcbufmargins(RIGHT);
3210                         gendata.ileave = 0;
3211                         encode_col_buf(RIGHT);
3212                         lline = gendata.curvline;
3213                         if(gendata.yres == 1200)
3214                         {
3215                                 finalizeheader(1, RIGHT);
3216                                 gendata.ileave = 1;
3217                                 encode_col_buf(RIGHT);
3218                                 lline++;
3219                         }
3220                         break;
3221 
3222                 case LHDATA|RHDATA:
3223                         calcbufmargins(LEFT);
3224                         gendata.ileave = 0;
3225                         encode_col_buf(LEFT);
3226                         calcbufmargins(RIGHT);
3227                         finalizeheader(0, RIGHT);
3228                         encode_col_buf(RIGHT);
3229                         lline = gendata.curvline;
3230                         if(gendata.yres == 1200)
3231                         {
3232                                 calcbufmargins(LEFT);
3233                                 finalizeheader(1, LEFT);
3234                                 gendata.ileave = 1;
3235                                 encode_col_buf(LEFT);
3236                                 calcbufmargins(RIGHT);
3237                                 finalizeheader(0, RIGHT);
3238                                 encode_col_buf(RIGHT);
3239                                 lline++;
3240                         }
3241 
3242                         break;
3243         }
3244 
3245         res = roll_buffer();
3246 
3247         while(!(res & LAST))
3248         {
3249                 switch(res)
3250                 {
3251                         case LHDATA:
3252                                 calcbufmargins(LEFT);
3253                                 finalizeheader(gendata.curvline - lline, LEFT);
3254                                 gendata.ileave = 0;
3255                                 encode_col_buf(LEFT);
3256                                 lline = gendata.curvline;
3257                                 if(gendata.yres == 1200)
3258                                 {
3259                                         finalizeheader(1, LEFT);
3260                                         gendata.ileave = 1;
3261                                         encode_col_buf(LEFT);
3262                                         lline++;
3263                                 }
3264                                 break;
3265 
3266                         case RHDATA:
3267                                 calcbufmargins(RIGHT);
3268                                 finalizeheader(gendata.curvline - lline, RIGHT);
3269                                 gendata.ileave = 0;
3270                                 encode_col_buf(RIGHT);
3271                                 lline = gendata.curvline;
3272                                 if(gendata.yres == 1200)
3273                                 {
3274                                         finalizeheader(1, RIGHT);
3275                                         gendata.ileave = 1;
3276                                         encode_col_buf(RIGHT);
3277                                         lline++;
3278                                 }
3279                                 break;
3280 
3281                         case LHDATA|RHDATA:
3282                                 calcbufmargins(LEFT);
3283                                 finalizeheader(gendata.curvline - lline, LEFT);
3284                                 gendata.ileave = 0;
3285                                 encode_col_buf(LEFT);
3286                                 calcbufmargins(RIGHT);
3287                                 finalizeheader(0, RIGHT);
3288                                 encode_col_buf(RIGHT);
3289                                 lline = gendata.curvline;
3290                                 if(gendata.yres == 1200)
3291                                 {
3292                                         calcbufmargins(LEFT);
3293                                         finalizeheader(1, LEFT);
3294                                         gendata.ileave = 1;
3295                                         encode_col_buf(LEFT);
3296                                         calcbufmargins(RIGHT);
3297                                         finalizeheader(0, RIGHT);
3298                                         encode_col_buf(RIGHT);
3299                                         lline++;
3300                                 }
3301                                 break;
3302                 }
3303 
3304                 res = roll_buffer();
3305         }
3306 
3307         switch(res)
3308         {
3309                 case LHDATA:
3310                         calcbufmargins(LEFT);
3311                         finalizeheader(gendata.curvline - lline, LEFT);
3312                         gendata.ileave = 0;
3313                         encode_col_buf(LEFT);
3314                         if(gendata.yres == 1200)
3315                         {
3316                                 finalizeheader(1, LEFT);
3317                                 gendata.ileave = 1;
3318                                 encode_col_buf(LEFT);
3319                                 lline++;
3320                         }
3321 
3322                 case RHDATA:
3323                         calcbufmargins(RIGHT);
3324                         finalizeheader(gendata.curvline - lline, RIGHT);
3325                         gendata.ileave = 0;
3326                         encode_col_buf(RIGHT);
3327                         if(gendata.yres == 1200)
3328                         {
3329                                 finalizeheader(1, RIGHT);
3330                                 gendata.ileave = 1;
3331                                 encode_col_buf(RIGHT);
3332                                 lline++;
3333                         }
3334                         break;
3335 
3336                 case LHDATA|RHDATA:
3337                         calcbufmargins(LEFT);
3338                         finalizeheader(gendata.curvline - lline, LEFT);
3339                         gendata.ileave = 0;
3340                         encode_col_buf(LEFT);
3341                         calcbufmargins(RIGHT);
3342                         finalizeheader(0, RIGHT);
3343                         encode_col_buf(RIGHT);
3344                         if(gendata.yres == 1200)
3345                         {
3346                                 calcbufmargins(LEFT);
3347                                 finalizeheader(1, LEFT);
3348                                 gendata.ileave = 1;
3349                                 encode_col_buf(LEFT);
3350                                 calcbufmargins(RIGHT);
3351                                 finalizeheader(0, RIGHT);
3352                                 encode_col_buf(RIGHT);
3353                                 lline++;
3354                         }
3355                         break;
3356         }
3357 
3358         finalizeheader(0, -1);
3359 }
3360