1 #include "gdevprn.h"
2 /* Copyright (C) 1989-1994, 1998, 1999 Aladdin Enterprises.  All rights reserved.
3 
4   This file is part of Aladdin Ghostscript.
5 
6   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
7   or distributor accepts any responsibility for the consequences of using it,
8   or for whether it serves any particular purpose or works at all, unless he
9   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
10   License (the "License") for full details.
11 
12   Every copy of Aladdin Ghostscript must include a copy of the License,
13   normally in a plain ASCII text file named PUBLIC.  The License grants you
14   the right to copy, modify and redistribute Aladdin Ghostscript, but only
15   under certain conditions described in the License.  Among other things, the
16   License requires that the copyright notice and this notice be preserved on
17   all copies.
18 */
19 /*
20  * $Id: gdevlx7.c,v 1.10 1999/09/08 13:26:36 henryk Exp henryk $
21  * Lexmark 7000 ink-jet  "GDI" printer driver
22  *   * just started...
23  *
24  * Henryk Paluch paluch@bimbo.fjfi.cvut.cz
25  * http://bimbo.fjfi.cvut.cz/~paluch/l7kdriver/
26  *
27  * BIG thanks to Peter B. West that discovered and described many
28  * "funny" things of the Lexmark 5xxx protocol.
29  *
30  * THIS GHOSTSCRIPT DRIVER USES MANY THINGS FROM
31  * STEPHEN'S LEXMARK 5700 GHOSCRIPT DRIVER:
32  *
33  * Stephen Taylor  setaylor@ma.ultranet.com  staylor@cs.wpi.edu
34  * http://www.ultranet.com/~setaylor/papers.htm
35  *
36  * ALL INTRODUCED BUGS ARE PROPERTY OF HENRYK :-)
37  */
38 
39 /* our private driver constants */
40    /* Lexmark 7xxx,5xxx swipe height of Black & White cartridge */
41 #define LX7_BSW_H 208
42 
43    /* Lexmark 7xxx,5xxx swipe height of Colour cartridge */
44 #define LX7_CSW_H 192
45 
46   /* maximum data bytes per packet: 13 * 2 = 26
47    * 13 - compression bits, 2 = data words
48    */
49 #define LX7_MAX_SWBYTES 26
50  /* 13 * 2 databytes + 2 bytes for header = 28 bytes */
51 #define LX7_MAX_PACKET  28
52 #define LX7_MAX_SWWORDS 13
53 
54 /* interlaced printing for 1200dpi - vertical offset of lines */
55 /* they must be odd. The sum must be 208 */
56 /* these are for Ink Jet distance */
57 #define LXH_SKIP1   99
58 #define LXH_SKIP2   109
59 /* doubled values for real paper shift */
60 #define LXH_DSKIP1 (LXH_SKIP1*2-1)
61 #define LXH_DSKIP2 (LXH_SKIP2*2+1)
62 /* Lexmark 7000 prologue */
63 /* 1st time initialization - INIT1 is common for all modes */
64 #define LX7_INIT1 0x1b,0x2a,0x6d,0x00,0x40,0x10,0x03,0x10,0x11
65 
66 /* LX_INIT2 - for 1200dpi - currently not needed */
67 #define LX7_INIT2 0xa5,0x00,0x06,0x50,0x03,0x03,0xc0,0x0f,0x0f, \
68                   0xa5,0x00,0x03,0x50,0x04,0x05, \
69 		  0xa5,0x00,0x03,0x50,0x04,0x06, \
70 		  0xa5,0x00,0x03,0x50,0x04,0x07, \
71 		  0xa5,0x00,0x03,0x50,0x04,0x08, \
72 		  0xa5,0x00,0x04,0x50,0x04,0x0c,0x00, \
73 		  0xa5,0x00,0x04,0x50,0xe0,0x0b,0x03
74 /* LX_INIT3 - after 1200dpi prologue, or immediately after INIT1
75  * in other modes
76  */
77 #define  LX7_INIT3 0xa5,0x00,0x0b,0x50,0xe0,0x41,0x00,\
78                         0x00,0x00,0x00,0x00,0x00,0x00,0x02,\
79 		   0xa5,0x00,0x06,0x50,0x05,0x00,0x00,0x80,0x00, \
80                    0xa5,0x00,0x04,0x50,0x04,0x0c,0x00
81 /* this is used also for new page prologue ... */
82 #define LX7_INIT4 0x1b,0x2a,0x07,0x73,0x30
83 #define LX7_INIT5 0x1b,0x2a,0x07,0x63
84 /* mysterious reinitialization ???? */
85 #define LX7_INIT6 0x1b,0x2a,0x6d,0x00,0x42,0x00,0x00
86 #define LX7_INIT7 0xa5,0x00,0x05,0x40,0xe0,0x80,0x07,0x08
87 
88 static byte lx7_fullinit[]={LX7_INIT1, /*LX7_INIT2, LX7_INIT3,*/ LX7_INIT4,
89                              LX7_INIT5, LX7_INIT6};
90 static byte lx7_pageinit[]={LX7_INIT4, LX7_INIT4, LX7_INIT5, LX7_INIT6};
91 
92 #ifndef MIN
93 #define MIN(x,y) ( (x) < (y) ? (x) : (y))
94 #endif
95 #ifndef MAX
96 #define MAX(x,y) ( (x) > (y) ? (x) : (y))
97 #endif
98 
99 /* The procedure descriptors */
100 /* declare functions */
101 private dev_proc_print_page(lxmgen_print_page);
102 private dev_proc_get_params(lxm_get_params);
103 private dev_proc_put_params(lxm_put_params);
104 
105 /* set up dispatch table.  I follow gdevdjet in using gdev_prn_output_page */
106 static const gx_device_procs lxm7000m_procs =
107     prn_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
108                      lxm_get_params, lxm_put_params);
109 
110 /* The device descriptors */
111 
112 /* define a subclass with useful state in it. */
113 typedef struct lxm_device_s { /* a sub-class of gx_device_printer */
114     gx_device_common;
115     gx_prn_device_common;
116     int headSeparation;
117     byte *fullInit;
118     int  nfullInit;
119     byte *pageInit;
120     int npageInit;
121     int printertype;
122 } lxm_device;
123 
124 /* Lexmark types (faster lookup than strcmp("lex7000",...) ...
125  * stored in 'printertype' variable
126  */
127 
128 #define LXT_7000 0
129 #define LXT_5700 1
130 #define LXT_3200 2
131 #define LXT_2050 3
132 
133 /* resolution map - used by "associate" arrays - do not modify */
134 #define LXR_300  0
135 #define LXR_600  1
136 #define LXR_1200 2
137 
138 lxm_device far_data gs_lex7000_device = {
139     prn_device_std_body(lxm_device, lxm7000m_procs, "lex7000",
140 	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
141 	/* total width & height in 10x " - A4 or letter compiled in.
142 	 * may be overriden by -sPAPERSIZE=a4 of -sPAPERSIZE=letter
143 	 */
144 	600, 600,	/* x dpi, y dpi */
145 	0.0, 0.1, 0.3, 0.1,			/* margins */
146 	/* unlike most other Ink printers Lexmark is able to print at
147 	 * whole top and bottom of paper :-)
148 	 */
149 	1, lxmgen_print_page),
150 	/* 1 = bits per color, generic routines*/
151 
152     /* our extended attributes follow...*/
153     16,   /* default headSeparation value */
154     lx7_fullinit,
155     sizeof(lx7_fullinit),
156     lx7_pageinit,
157     sizeof(lx7_pageinit),
158     LXT_7000
159 };
160 
161 lxm_device far_data gs_lex5700_device = {
162     prn_device_std_body(lxm_device, lxm7000m_procs, "lex5700",
163 	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
164 	/* total width & height in 10x " - A4 or letter compiled in.
165 	 * may be overriden by -sPAPERSIZE=a4 of -sPAPERSIZE=letter
166 	 */
167 	600, 600,	/* x dpi, y dpi */
168 	0.1, 0.1, 0.1, 0.0,			/* margins */
169 	/* unlike most other Ink printers Lexmark is able to print at
170 	 * whole top and bottom of paper :-)
171 	 */
172 	1, lxmgen_print_page),
173 	/* 1 = bits per color, generic routines*/
174 
175     /* our extended attributes follow...*/
176     16,   /* default headSeparation value */
177     lx7_fullinit,
178     sizeof(lx7_fullinit),
179     lx7_pageinit,
180     sizeof(lx7_pageinit),
181     LXT_5700
182 };
183 
184 lxm_device far_data gs_lex3200_device = {
185     prn_device_std_body(lxm_device, lxm7000m_procs, "lex3200",
186 	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
187 	/* total width & height in 10x " - A4 or letter compiled in.
188 	 * may be overriden by -sPAPERSIZE=a4 of -sPAPERSIZE=letter
189 	 */
190 	600, 600,	/* x dpi, y dpi */
191 	0.1, 0.1, 0.1, 0.0,			/* margins */
192 	/* unlike most other Ink printers Lexmark is able to print at
193 	 * whole top and bottom of paper :-)
194 	 */
195 	1, lxmgen_print_page),
196 	/* 1 = bits per color, generic routines*/
197 
198     /* our extended attributes follow...*/
199     16,   /* default headSeparation value */
200     lx7_fullinit,
201     sizeof(lx7_fullinit),
202     lx7_pageinit,
203     sizeof(lx7_pageinit),
204     LXT_3200
205 };
206 
207 lxm_device far_data gs_lex2050_device = {
208     prn_device_std_body(lxm_device, lxm7000m_procs, "lex2050",
209 	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
210 	/* total width & height in 10x " - A4 or letter compiled in.
211 	 * may be overriden by -sPAPERSIZE=a4 of -sPAPERSIZE=letter
212 	 */
213 	600, 600,	/* x dpi, y dpi */
214 	0.1, 0.1, 0.1, 0.0,			/* margins */
215 	/* unlike most other Ink printers Lexmark is able to print at
216 	 * whole top and bottom of paper :-)
217 	 */
218 	1, lxmgen_print_page),
219 	/* 1 = bits per color, generic routines*/
220 
221     /* our extended attributes follow...*/
222     16,   /* default headSeparation value */
223     lx7_fullinit,
224     sizeof(lx7_fullinit),
225     lx7_pageinit,
226     sizeof(lx7_pageinit),
227     LXT_2050
228 };
229 
230 
231 
232 
233 #define get_lx_type(pdev) \
234   (((lxm_device*)pdev)->printertype)
235 
236 
237 
238 /* ------ Local Lexmark printer utilities ------*/
239 
240 #define LX_LINE_EMPTY(buf,len) \
241    (buf[0]==0 && memcmp(buf,buf+1,len-1)==0)
242 
243 private byte ofs8[8]={128,64,32,16,8,4,2,1};
244 /* Lexmark 5xxx, 7xxx page eject */
lex_eject(FILE * out)245 private void lex_eject(FILE *out)
246 {
247    byte buf[4]={0x1b,0x2a,0x7,0x65};
248 #ifdef DEBUG
249    dprintf("Sending page eject.\n");
250 #endif
251    fwrite(buf,sizeof(buf),1,out);
252 }
253 
254 /*
255  * shift paper (skip empty lines)
256  * offset is in pixels in 1200 dpi resolution, i. e.,
257  * 384 for 192 pixels or
258  * 416 for 208 pixels etc...
259  */
paper_shift(FILE * out,int offset)260 private void paper_shift(FILE *out,int offset)
261 {
262    byte buf[5]={0x1b,0x2a,0x3,0x0,0x0};
263    buf[3]=(byte)(offset >> 8);   /* just to be endian safe we don't use short */
264    buf[4]=(byte)(offset & 0xFF);
265 #ifdef DEBUG
266    dprintf3("paper_shift() %d 1200dpi = %d 600dpi = %d 300dpi pixels\n",
267 	 offset,offset/2,offset/4);
268 #endif
269    fwrite(buf,sizeof(buf),1,out);
270 }
271 
272 /* return coordinate of leftmost pixel (in pixels) */
leftmost_pixel(byte * buf,int bytelen)273 private int leftmost_pixel(byte *buf, int bytelen)
274 {
275    int i;
276    byte *r=buf;
277    byte b;
278    if (LX_LINE_EMPTY(buf,bytelen)) /* catch empty line */
279       return bytelen*8-1;
280 
281    while( *r==0 && bytelen>0)
282    {
283       r++;
284       bytelen--;
285    }
286 
287    b= *r;
288    for(i=0;i<8;i++)
289       if ( ( b & ofs8[i])!=0)
290 	 break;
291    return  (r-buf)*8+i;
292 }
293 
294 /* return coordinate of rightmost pixel (in pixels) */
rightmost_pixel(byte * buf,int bytelen)295 private int rightmost_pixel(byte *buf, int bytelen)
296 {
297    int i;
298    byte *r=buf+(bytelen-1);
299    byte b;
300    if (LX_LINE_EMPTY(buf,bytelen)) /* catch empty line */
301       return 0;
302 
303    while( *r==0 && bytelen>1)
304    {
305       r--;
306       bytelen--;
307    }
308 
309    b= *r;
310    for(i=7;i>=0;i--)
311       if ( ( b & ofs8[i])!=0)
312 	 break;
313    return  (r-buf)*8+i;
314 }
315 
316 /* find leftmost and rightmost pixel in whole pass
317  * buf        - pixel buffer
318  * bytelen    - width of line (in bytes)
319  * bufheight  - buffer height (pixels)
320  * interlaced - if even lines have different horizontal offset
321  *              than odd lines
322  * intershift - horizontal offset between even/odd lines
323  * leftmost,
324  *  rightmost - output
325  */
find_lr_pixels(byte * buf[],int bytelen,int bufheight,int interlaced,int intershift,int * leftmost,int * rightmost)326 private void find_lr_pixels(byte *buf[],int bytelen,int bufheight,
327       int interlaced, int intershift,
328       int *leftmost, int *rightmost)
329 {
330    int maxright=bytelen*8-1;
331    int left=maxright;
332    int right=0;
333    int i;
334 
335    for(i=0;i<bufheight;i++)
336    {
337       int ltmp,rtmp;
338       ltmp=leftmost_pixel(buf[i],bytelen);
339       rtmp=rightmost_pixel(buf[i],bytelen);
340 #if 0
341       dprintf3("buf[%d]: leftmost %d, rightmost %d\n",
342 	    i,ltmp,rtmp);
343 #endif
344       if (interlaced && (i & 1)==1) /* interlaced && line is odd */
345       {
346 	 ltmp=MAX((ltmp-intershift),0);
347 	 rtmp=MIN((rtmp+intershift),maxright);
348 	 if (ltmp==maxright)
349 	    ltmp--; /* print at least one pixel to avoid races ?? */
350       }
351       if (ltmp<left)
352 	 left=ltmp;
353       if (rtmp>right)
354 	 right=rtmp;
355    }
356 
357    *leftmost  = left;
358    *rightmost = right;
359    return;
360 }
361 
362 
363 /* ------ Driver procedures ------ */
364 
365 /*** THIS NEED TO BE REWORKED SOON ***/
366 private const int LEFT_MARGIN=50;
367 private const int VERTSIZE=LX7_BSW_H;
368 /* offsets to print line sequence (defined in outbuf)
369  */
370 private const int IDX_SEQLEN=5;
371 private const int IDX_HORRES=8;
372 private const int IDX_PACKETS=13;
373 private const int IDX_5700DIF=12;
374 private const int IDX_HSTART=15;
375 private const int IDX_HEND=17;
376 private const int IDX_DATA=26;
377 private const int IDX_CARTRIDGE=10;
378 
379 #define DIV8(x) ( (x) >> 3 )
380 #define MOD8(x) ( (x) & 0x7 )
381 #define DIV16(x) ( (x) >> 4 )
382 #define MOD16(x) ( (x) & 0xf )
383    /* too large buffer may hang the printer ?! */
384 #define OUT_BUF_SIZE 256000
385 /* most important print packet
386  * see lexmarkprotocol.txt for more information */
387 /*          length of complete sequence ---  vvvvvvvvv */
388 /* this is template now. Outbuf is allocated and initialized
389  * by lxmgen_print_page() to avoid large static array
390  * in gs binary
391  */
392 private byte outb[]={0x1B,0x2A,0x04,0x00,0x00,0xFF,0xFF,
393    /* number of packets ----     vvvvvvvvv */
394    0x00,0x02,0x01,0x01,0x1A,0x11,0xFF,0xFF,
395    /* horiz start, horiz end: packets = (horiz end - horiz start) +1 */
396    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x22,0x33,0x44,0x55,0x01};
397 
398 #define BITSTART12 4096
399 
print_cols(FILE * prn_stream,gx_device_printer * pdev,byte * outbuf,int left,int right,int vstart,int vend,byte * buf[],int width,int LR_SHIFT)400 private int print_cols(FILE *prn_stream,gx_device_printer *pdev,
401       byte *outbuf,
402       int left,int right,int vstart, int vend,byte *buf[],
403       int width,int LR_SHIFT)
404 {
405    unsigned char mask[8]={128,64,32,16,8,4,2,1};
406    unsigned int  mask16[16]={0x8000,0x4000,0x2000,0x1000,
407                              0x0800,0x0400,0x0200,0x0100,
408 			     0x0080,0x0040,0x0020,0x0010,
409 			     0x0008,0x0004,0x0002,0x0001};
410    int l8,r8,packets;
411    byte *p=outbuf+IDX_DATA;
412    int clen;
413    int i,k;
414    unsigned int vbuf[LX7_MAX_SWWORDS];
415    int vi;
416    unsigned char *vp,*vp2;
417    int smask,smask2;
418 
419    l8=left+LEFT_MARGIN;
420    r8=right+LEFT_MARGIN;
421 
422    packets=r8-l8+1;
423 
424 
425    outbuf[IDX_PACKETS]  =(unsigned char)(packets >> 8);
426    outbuf[IDX_PACKETS+1]=(unsigned char)(packets & 0xFF);
427    outbuf[IDX_HSTART]   =(unsigned char)(l8 >> 8);
428    outbuf[IDX_HSTART+1] =(unsigned char)(l8 & 0xFF);
429    outbuf[IDX_HEND]     =(unsigned char)(r8 >> 8);
430    outbuf[IDX_HEND+1]   =(unsigned char)(r8 & 0xFF);
431 
432    outbuf[IDX_5700DIF]= ( get_lx_type(pdev)==LXT_7000 ? 0x11 : 0x1 );
433    /* fill columns */
434    for(i=left;i<=right;i++)
435    {
436       int rle1size,rle2size;
437       int bits=0;
438       byte *tbits;
439 
440       if ( (p-outbuf)>=OUT_BUF_SIZE-28 ) /* 13*2+2 */
441       {
442 	 return -1;
443       }
444       tbits=p;
445       p+=2; /* add room for RLE packet (2 bytes) */
446 
447       /* clear buffer of vertical points */
448       memset(vbuf,0,sizeof(vbuf));
449 
450       smask=mask[MOD8(i)];
451       smask2=mask[MOD8(i+LR_SHIFT)];
452 
453       vi=vstart*2; /* vbuf index in pixels (not array index) */
454       for(k=vstart;k<vend;k++)
455       {
456 	 vp=buf[k*2]+DIV8(i);
457 	 /* vp points to current column for Left Ink */
458 	 vp2=buf[k*2+1]+DIV8(i+LR_SHIFT);
459 	 /* vp2 for right Ink jets */
460 	 if ( ( vp[0] & smask) != 0)
461 	    vbuf[DIV16(vi)] |= mask16[MOD16(vi)];
462 	 vi++;
463 	 if (i+LR_SHIFT<width*8)
464 	 {
465 	    if ( (vp2[0] & smask2) !=0 )
466 	       vbuf[DIV16(vi)] |=mask16[MOD16(vi)];
467 	 }
468 	 vi++;
469       }
470 
471       /* every packet contains 13 info bits
472        * 1 = 8x left white, 8x right white
473        * 0 = 2 data bytes follow (8 bits left, 8 bits right)
474        */
475 
476       for(k=0;k<LX7_MAX_SWWORDS;k++)
477       {
478 	 unsigned int t=vbuf[k];
479 
480 	 bits= (bits>>1);
481 	 if (t==0) /* packet is empty */
482 	 {
483 	    bits+=BITSTART12;
484 	 }
485 	 else
486 	 {
487 	    *(p++)=(t >> 8) & 0xFF;
488 	    *(p++)=(t & 0xFF);
489 	 }
490       }
491      tbits[1]=(unsigned char)( (bits) & 0xFF);
492      *tbits  =(unsigned char)( ((bits>>8) & 0x1f) | 0x20 );
493      rle1size=(p-tbits);
494 #if 0
495      dprintf1("RLE1(%d), ",rle1size);
496 #endif
497      if (rle1size>6) /* try to use RLE2 compression for larger packets */
498      {
499 	byte ob[LX7_MAX_PACKET];
500 	unsigned int lastword=0x8FFF; /* impossible value */
501 	int byts=0;
502 	byte *pp=ob+2;
503 
504 	memset(ob,0,LX7_MAX_PACKET);
505 	for(k=0;k<LX7_MAX_SWWORDS;k++)
506 	{
507 	 unsigned int t=vbuf[k];
508 
509 	 byts= (byts>>1);
510 	 if (t==lastword)
511 	 {
512 	   byts+=BITSTART12;
513 	 }
514 	 else
515 	 {
516 	    *(pp++)=(t >> 8) & 0xFF;
517 	    *(pp++)=(t & 0xFF);
518 	    lastword=t;
519 	 }
520 	}
521      ob[1]=(unsigned char)( (byts) & 0xFF);
522      ob[0]=(unsigned char)( (byts>>8) & 0x1f );
523      rle2size=(pp-ob);
524 #if 0
525      dprintf1("RLE2(%d), ",rle2size);
526 #endif
527 
528      if (rle1size>rle2size)
529      {
530 #if 0
531 	dprintf2("\n**RLE2 WIN** %d > %d \n",rle1size,rle2size);
532 	dprintf("\nUsing RLE2 compression\n");
533 #endif
534 	memcpy(tbits,ob,rle2size);
535 	p=tbits+rle2size;
536      }
537      }
538    }
539 
540 
541    /* ------------ */
542    clen=p-outbuf;
543    outbuf[IDX_SEQLEN-1]  =(unsigned char)(clen >> 16);
544    outbuf[IDX_SEQLEN]  =(unsigned char)(clen >> 8);
545    outbuf[IDX_SEQLEN+1]=(unsigned char)(clen & 0xFF);
546    fwrite(outbuf,1,clen,prn_stream);
547 #ifdef DEBUG
548    dprintf1("\nSent %d data bytes\n",clen);
549 #endif
550    return 0;
551 }
552 
553 
554 /*** THIS NEED TO BE REWORKED SOON - END ***/
555 
556 /* Send the page to the printer. */
557 /* Lexmark generic print page routine */
558 private int
lxmgen_print_page(gx_device_printer * pdev,FILE * prn_stream)559 lxmgen_print_page(gx_device_printer *pdev, FILE *prn_stream)
560 {
561    int pheight=pdev->height; /* page height (pixels) */
562 #ifdef DEBUG
563    int pwidth=pdev->width;   /* page width (pixels) */
564 #endif
565    int bwidth=gdev_mem_bytes_per_scan_line((gx_device*)pdev);
566    /* page width (bytes) */
567 
568    int prest=pheight;        /* Page Rest number of lines to remain ... */
569    int brest;                /* Buffer rest for buffer copy */
570    int skipline=208;           /* number of empty lines, e.g. skip them */
571    /* we need to move paper under cartridge..
572     * about 208 pixels... */
573    byte *pbuf;               /* printer buffer - dynamic allocation */
574    byte *ppbuf,*ppbuf2;              /* pointer returned by _prn_get_bits() */
575    byte *outbuf;             /* output buffer - used by print_cols(),
576 			      * but allocated here, to avoid unnecessary
577 			      * de & allocation
578 			      */
579    int pbufsize,rpbufsize;             /* printer buffer size */
580    int hres,vres;
581    int interlaced;
582    int lr_shift=((lxm_device*)pdev)->headSeparation;
583    byte *obp[LX7_BSW_H];    /* pointers to buffer lines */
584    int bufHeight;
585 
586    /* initiate vres mapping variable */
587    vres=LXR_600; /* default vertical resolution */
588    if (pdev->y_pixels_per_inch<301.0)
589       vres=LXR_300;
590    if (pdev->y_pixels_per_inch>=601.0)
591       vres=LXR_1200;
592 
593    bufHeight=LX7_BSW_H;
594    if (vres==LXR_300)
595    {
596       bufHeight /= 2;
597       skipline  /= 2;
598    }
599    if (vres==LXR_1200)
600    {
601       bufHeight *= 2;
602       skipline *=2;
603    }
604 
605    pbufsize = bwidth * bufHeight;
606    rpbufsize = bwidth * (bufHeight+1);
607 #ifdef DEBUG
608    dprintf1("[%s] print_page() start\n",pdev->dname);
609    dprintf1("Is first page? %d\n",gdev_prn_file_is_new(pdev));
610    dprintf1("Head Separation %d\n",((lxm_device*)pdev)->headSeparation);
611    dprintf2("Width %d pixels, %d bytes\n",pwidth,bwidth);
612    dprintf1("Height %d pixels\n",pheight);
613    dprintf1("One pass buffer size %d\n",pbufsize);
614    dprintf1("Output buffer size %d\n",OUT_BUF_SIZE);
615    dprintf2("Current resolution is %f width x %f height dpi\n",
616 	 pdev->x_pixels_per_inch, pdev->y_pixels_per_inch );
617 #endif
618    pbuf = (byte *)gs_malloc(rpbufsize, 1, "lxmgen_print_page(pbuf)");
619    if (pbuf == NULL)
620       return_error(gs_error_VMerror);
621 
622    outbuf = (byte *)gs_malloc(OUT_BUF_SIZE, 1, "lxmgen_print_page(outbuf)");
623    if (outbuf == NULL)
624    {
625       gs_free((char*)pbuf,pbufsize, 1, "lxmgen_print_page(pbuf)");
626       return_error(gs_error_VMerror);
627    }
628    /* initialize begin of outbuf ... */
629    memcpy(outbuf,outb,sizeof(outb));
630 
631    /* zero fake line (used for non-interlaced resolutions etc)...*/
632    memset(pbuf+pbufsize,0,bwidth);
633 
634 
635    /* initiate hres mapping variable */
636    hres=LXR_600; /* default horizontal resolution */
637    if (pdev->x_pixels_per_inch<301.0)
638       hres=LXR_300;
639    if (pdev->x_pixels_per_inch>=601.0)
640       hres=LXR_1200;
641    /* adjust headSeparation according to horizontal resolution */
642    if (hres==LXR_300)
643       lr_shift >>=1;
644    if (hres==LXR_1200)
645       lr_shift <<=1;
646 
647    interlaced=1; /* all resolutions except vert 300dpi are interlaced*/
648 
649    /* adjust horizontal motor speed for current resolution */
650    if (get_lx_type(pdev)==LXT_7000 || get_lx_type(pdev)==LXT_5700)
651    {
652       byte mspeed[3]={1,2,5}; /* LXR_300=0, LXR_600=1, LXR_1200=2 */
653       outbuf[IDX_HORRES]=mspeed[hres];
654    }
655 
656 #ifdef DEBUG
657    dprintf1("Choosed motor speed %d\n",(int)outbuf[IDX_HORRES]);
658 #endif
659 
660 
661    if(vres==LXR_600)
662    {
663       int i;
664       for(i=0;i<LX7_BSW_H;i++)
665 	 obp[i]=pbuf+(i*bwidth);
666    }
667 
668    if(vres==LXR_300)
669    {
670       int i;
671       for(i=0;i<LX7_BSW_H;i++)
672 	 if ( (i & 1)!=0)
673 	    obp[i]=pbuf+pbufsize; /* odd line is empty for 300dpi */
674 	 else
675 	    obp[i]=pbuf+(i/2*bwidth);
676    }
677 
678 
679 
680 
681    if(gdev_prn_file_is_new(pdev))
682       fwrite(((lxm_device*)pdev)->fullInit,
683 	    ((lxm_device*)pdev)->nfullInit,
684 	    1,prn_stream);
685    else
686       fwrite(((lxm_device*)pdev)->pageInit,
687 	    ((lxm_device*)pdev)->npageInit,
688 	    1,prn_stream);
689 
690 
691    while(prest>0)
692    {
693       int i;
694       int leftmost;  /* position of leftmost pixel */
695       int rightmost; /* position of rightmost pixel */
696       int c1200;     /* testing empty line for 1200dpi... */
697 
698       /* copy one line & test for all zeroes */
699       gdev_prn_get_bits(pdev, pheight-prest, /* current line No. */
700 	    pbuf,                /* our buffer if needed */
701 	    &ppbuf);             /* returns pointer to scanline
702 				  * either our buffer or
703 				  * gs internal data buffer
704 				  */
705       if (vres==LXR_1200 && (pheight-prest+LXH_DSKIP1<pheight))
706       {
707 	 gdev_prn_get_bits(pdev, pheight-prest+LXH_DSKIP1,
708 	                          /* current line No. */
709 	    pbuf+bwidth,                /* our buffer if needed */
710 	    &ppbuf2);
711        c1200=LX_LINE_EMPTY(ppbuf2,bwidth);
712       }
713       else
714 	 c1200=1;
715 
716       /* test for empty line (nice Stephen's trick w/ memcmp() :-) */
717       if (LX_LINE_EMPTY(ppbuf,bwidth) && c1200)
718       {  /* line empty */
719 	 prest--;
720 	 skipline++;
721 	 continue; /* Loop thgrough the while(prest>0) ... */
722       }
723 
724       /* 1pass printing for 300 & 600 dpi */
725       /* 2pass printing for 1200dpi */
726       for(i=0;i<(vres==LXR_1200 ? 2 : 1);i++)
727       {
728 	 /* skip empty lines on paper, if any */
729 	 if (skipline>0)
730 	 {
731 	    int mult[3]={4,2,1}; /* multiply: 300dpi=4, 600dpi=2, 1200dpi=1 */
732 	    paper_shift(prn_stream,skipline*mult[vres]);
733 	    skipline=0;
734 	 }
735 
736 	 /* for 1200dpi we need to setup interlaced buffer entries */
737 	 if (vres==LXR_1200)
738 	 {
739 	    int j;
740 	    for(j=0;j<LX7_BSW_H;j++)
741 	       if ( (j & 1)!=i) /* i==0 for 1st pass i==1 for 2nd pass */
742 		  obp[j]=pbuf+pbufsize; /* "odd" line is empty for 300dpi */
743 	       else
744 		  obp[j]=pbuf+(j*2*bwidth);
745 	 }
746 
747 
748 	 /* copy remaining lines to buffer */
749 	 brest=MIN(bufHeight,prest);
750 
751 #ifdef DEBUG
752 	 dprintf2("Copying %d lines to buffer, vertpos %d\n",brest,
753 	       pheight-prest);
754 #endif
755 	 gdev_prn_copy_scan_lines(pdev,pheight-prest,pbuf,pbufsize);
756 	 /* zero unused lines (on bottom of page) */
757 	 if (bufHeight-brest>0)
758 	    memset(pbuf+(brest*bwidth),0,(bufHeight-brest)*bwidth);
759 
760 	 /* look for leftmost and rightmost pixels */
761 	 find_lr_pixels(obp,bwidth,LX7_BSW_H,interlaced,
762 	       ((lxm_device*)pdev)->headSeparation,
763 	       &leftmost,&rightmost);
764 #ifdef DEBUG
765 	 dprintf2("Leftmost pixel %d, rightmost pixel %d\n",
766 	       leftmost,rightmost);
767 #endif
768 
769 	 /* print the data */
770 	 if (leftmost<rightmost)
771 	 if (print_cols(prn_stream,pdev,outbuf,leftmost,rightmost,
772 		  0,VERTSIZE/2,obp,bwidth,lr_shift)==-1)
773 	 {
774 	    print_cols(prn_stream,pdev,outbuf,leftmost,rightmost,0,
775 		  VERTSIZE/4,obp,bwidth,lr_shift);
776 
777 	    print_cols(prn_stream,pdev,outbuf,leftmost,rightmost,
778 		  VERTSIZE/4,VERTSIZE/2,
779 		  obp,bwidth,lr_shift);
780 
781 #ifdef DEBUG
782 	    dprintf("Overflow workaround used\n");
783 #endif
784 	 }
785 
786 	 if (vres!=LXR_1200)
787 	 {
788 	    skipline=brest; /* skip already printed lines */
789 	 }
790 	 else
791 	 {
792 	    skipline+=( i==0 ? LXH_DSKIP1 : LXH_DSKIP2 );
793 	 }
794          prest-=skipline; /* decrease number of remaining lines */
795 	 if (prest<=0)
796 	    break;
797       }
798    }
799 
800    /* eject page */
801    lex_eject(prn_stream);
802    gs_free((char*)pbuf,rpbufsize, 1, "lxmgen_print_page(pbuf)");
803    gs_free((char*)outbuf,OUT_BUF_SIZE, 1, "lxmgen_print_page(outbuf)");
804 
805 #ifdef DEBUG
806    dprintf1("[%s] print_page() end\n",pdev->dname);
807 #endif
808    return 0;
809 }
810 
811    private int
lxm_get_params(gx_device * pdev,gs_param_list * plist)812 lxm_get_params(gx_device *pdev, gs_param_list *plist)
813 {
814     lxm_device* const ldev = (lxm_device*)pdev;
815     int code = gdev_prn_get_params(pdev, plist);
816 
817     if ( code < 0 ) return code;
818     code = param_write_int(plist,
819 			   "HeadSeparation",
820 			   (int *)&(ldev->headSeparation));
821 
822     return code;
823 }
824 
825 /* put_params is supposed to check all the parameters before setting any. */
826 private int
lxm_put_params(gx_device * pdev,gs_param_list * plist)827 lxm_put_params(gx_device *pdev, gs_param_list *plist)
828 {
829     int ecode;
830     lxm_device* const ldev = (lxm_device*)pdev;
831     int trialHeadSeparation=ldev->headSeparation;
832     int code = param_read_int(plist, "HeadSeparation", &trialHeadSeparation);
833 
834     if ( trialHeadSeparation < 1 || trialHeadSeparation > 32 )
835 	param_signal_error(plist, "HeadSeparation", gs_error_rangecheck);
836     /* looks like param_signal_error is not expected to return */
837     ecode = gdev_prn_put_params(pdev, plist);	/* call super class put_params */
838     if ( code < 0 ) return code;
839     if (ecode < 0) return ecode;
840 
841     /* looks like everything okay; go ahead and set headSeparation */
842     ldev->headSeparation = trialHeadSeparation;
843     if ( code == 1) return ecode; /* I guess this means there is no "HeadSeparation" parameter */
844     return 0;
845 }
846 
847