1 /*
2
3 Copyright (C) 1999,2000 Peter B. West <pbwest@netscape.net>
4 Portions Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 U.S.A.
19
20 This program may also be distributed as part of Aladdin Ghostscript,
21 under the terms of the Aladdin Free Public License (the "License").
22
23 Every copy of Aladdin Ghostscript must include a copy of the
24 License, normally in a plain ASCII text file named PUBLIC. The
25 License grants you the right to copy, modify and redistribute
26 Aladdin Ghostscript, but only under certain conditions described in
27 the License. Among other things, the License requires that the
28 copyright notice and this notice be preserved on all copies.
29
30 The author, Peter B. West, may be contacted via e-mail as
31 pbwest@netscape.net
32 or by post at
33 1/32 Bent Street
34 Toowong, Brisbane,
35 QLD, AUSTRALIA. 4066
36
37 http://www.powerup.com.au/~pbwest
38
39 Based on the driver for the Lexmark 5700, pioneered by
40 Stephen Taylor setaylor@ma.ultranet.com staylor@cs.wpi.edu
41 and on other pioneering work on the Lexmark 7000 by
42 Henryk Paluch <paluch@bimbo.fjfi.cvut.cz>
43
44 My heartfelt thanks to these blokes (i.e. guys, fellows).
45
46 I should also like to thank Marija Svilans, through whom I discovered the
47 work of Stephen and Henryk.
48
49 My deepest praise and thanksgiving is reserved for the Author of all that
50 is Good, Beautiful and True; my Lord and my God, Jesus Christ.
51 "...all things were made through Him, and without Him was not anything
52 made that was made." John 1:3
53
54 Peter B. West pbwest@netscape.net
55 (First release: Friday, 8th October, 1999.)
56
57 */
58
59 /*$Id: gdevlx50.c,v 1.41 2000-04-18 14:35:41+10 pbw Exp pbw $*/
60 /*
61 * Lexmark 5000 ink-jet printer driver for Ghostscript
62 *
63 * Black and colour cartridges supported - NO PHOTO CARTRIDGE support yet.
64 *
65 * defines the lx5000 device for printing in black-and-white and colour
66 * at 600x600 (default), 1200x600 & 300x600 dpi, unidirectional.
67 *
68 * I use the command
69 * gs -sOutputFile=/dev/lp0 -sDEVICE=lx5000 file.ps
70 *
71 * For black-only printing, use
72 * gs -sOutputFile=/dev/lp0 -sDEVICE=lx5000 -dBitsPerPixel=1 file.ps
73 * For compatibility with earlier versions of the code, the following
74 * equivalent command is still supported.
75 * gs -sOutputFile=/dev/lp0 -sDEVICE=lx5000 -dCMYK=false file.ps
76 *
77 * For 1200x600 printing, add the argument
78 * -r1200x600
79 * For 300x600 printing, add the argument
80 * -r300x600
81 *
82 * A number of integer valued options are available.
83 * These options are accessed as arguments of the form
84 * -doptionname=optionvalue
85 * Optionname Optionvalue range
86 * BitsPerPixel 1 or 4
87 * HeadSeparation 1 - 30
88 * AlignA 0 - 30
89 * AlignB 0 - 15
90 * DryingTime 0 - 60
91 *
92 * BitsPerPixel currently only defines Black-only (1) or CMYK (4).
93 * -dBitsPerPixel=4 is the default, and is eauivalent to the older form
94 * -dCMYK=true
95 * [ HeadSeparation varies from print-cartridge to print-cartridge and
96 * 16 (the default) usually works fine. Stephen Taylor]
97 *
98 * AlignA is the horizontal alignment adjustment between the colour and
99 * the black pens. This distance will vary with each pair of cartridges.
100 *
101 * AlignB is the vertical alignment distance between the colour and black
102 * pens, and will also vary with each pair of cartridges.
103 *
104 * These values can be determined by running the alignment test; i.e,
105 * by writing the printer data file blckalgn.out to the device.
106 *
107 * cat blckalgn.out >/dev/lp0
108 *
109 * This file is now part of the distribution for the driver.
110 *
111 * DryingTime is used to include a delay after printing a page, to allow the
112 * page to dry to some extent before a subsequent page is printed and fed on
113 * top of it. The range of values is 0-60.
114 *
115 * Ancilliary files:
116 *
117 * blckalgn.out As mentioned above,this is a file of printer commands
118 * which will print the allignment page for the 5000.
119 * Usage: cat blckalgn.out >/dev/lp0 (or appropriate printer device)
120 *
121 * blckhcln.out This is a file of printer commands to print the head
122 * cleaning sequences.
123 * Usage: cat blckhcln.out >/dev/lp0
124 *
125 * showcarts.out This is a file with the printer command to move the
126 * printer cartridges into position for changing a
127 * cartridge.
128 * Usage: cat showcarts.out >/dev/lp0
129 *
130 * parkcarts.out This is a file with the printer command to move the
131 * printer cartridges back to a parked position.
132 * Usage: cat parkcarts.out >/dev/lp0
133 *
134 ================== K N O W N P R O B L E M S =======================
135
136 PROBLEMS WITH 1200dpi horizontally
137
138 This release was delayed by a bug in the production of black output
139 (including black pixels in colour output) at 1200 Xdpi which
140 manifested as the truncation of black swipes. In the RedHat test
141 page, for example, the black background to the hat in the RedHat
142 logo would abruptly halt, and no more of the black swipe would be
143 printed. This was difficult to track down, because of the sheer
144 size of the otuput file produced, and I ran out of time to find and
145 fix it, although I was beginning to suspect a problem with the
146 parallel driver. (It is always tempting to blame someone else.)
147
148 When I recently returned to this problem, and tried the test print
149 again on the unchanged binary, the bug had disappeared. In the
150 meantime, I had added more physical memory to the system, and
151 upgraded my 6.0 system to the 6.1 kernel (2.2.12), the 6.1 glibc
152 version (2.1.2-11) and miscellaneous other 6.1 rpms.
153
154 All was not lost, however. When I tested black-only printing at
155 1200dpi, the problem re-appeared. I have come to the conclusion
156 that the 5000 simply cannot print at 1200dpi. I have tested this by
157 printing solid bars of black at 600 and 1200 dpi. The 600dpi bar
158 (all nozzles on for most of the width of the paper) produces the
159 expected bar. Doing the same thing at 1200dpi produces movement of
160 the printhead, but only the beginnings of a bar. Reducing the
161 demand by printing from only every second nozzle get an intermediate
162 result; the printing of the bar starts, but the nozzle lines trail
163 off and dry up at various points in the traversal of the
164 page. leaving an effect somthing like a tattered flag.
165
166 How does the Windows driver do it? When printing a high density
167 black-only page, the driver prints repeated overlays offset by half
168 the height of the print swathe. Although I have not analysed these
169 swathes in detail, I suspect that the function of this "halving" is
170 simply to halve the printed pixel density, and thereby eliminate the
171 problem discussed above.
172
173 I have taken the "half-height" printing method for granted ever
174 since I read a passing reference to it in the H-P Jounal articles on
175 PPA, but I misunderstood it. I had thought that it was a way of
176 performing a pseudo-doubling of the VERTICAL print density by
177 overprinting adjacent pairs of lines. I was originally unaware that
178 the 5000 supported native 1200x600 resolution. The problem, as far
179 as I can determine, is that the 5000 does NOT support such printing.
180 And if the printer is not going to support 1200dpi horizontally,
181 neither am I.
182
183 PROBLEMS WITH PRINTER DATA "JAMMING"
184
185 I am experiencing an annoying problem with my 5000 on my AST Bravo
186 P100 (yes, really) system under RedHat linux (6.0 with kernel
187 2.2.12-20 and glibc 2.1.2-11). The printer frequently fails to
188 respond between print jobs, and sometimes between pages of the same
189 print job. The only way to wake it up is to power cycle the
190 printer. I have no idea why this is, of whether it is a general
191 problem. I would appreciate all feedback on this problem.
192
193 I have received feedback on this from Bob Clark
194 <rlc@c317689-a.scllg1.pa.home.com>. He realised that the printer
195 was queueing status data to be read from the same device. When this
196 queue (which appears to be 64 bytes long) fills up, the printer
197 stalls until it is reset (by a power cycle or by some as yet
198 undiscovered escape sequence), or until the status data is read.
199 That's the problem, but I do not have a clean solution yet.
200
201 *=================================================
202 Other requirements for compiling this driver:-
203 =================================================
204 The Ghostscript 6.0 source distribution, available from
205 http://www.cs.wisc.edu/~ghost/aladdin/get600.html
206
207 This includes reasonable html documentation on compiling GS.
208
209 For users of RPM-based systems like Red Hat, I have a source RPM
210 available which automates most of the process of compiling and
211 installing Ghostscript. A discussion of the details of compiling
212 and installing with this source RPM is available on my web page at
213 <http://localhost:80/~pbw/ghostscript/compileGS.html>.
214
215 The RPM includes a number of patch files which are applied to the
216 pristine Ghostscript 6.0 sources. Users of non-RPM systems can
217 extract these patches from the cpio archive which is also noted in
218 the instructions.
219
220 I have compiled and tested on a RedHat 6.0 i386 system, using
221 egcs-2.91.66 19990314/Linux (egcs-1.1.2 release), so the relevant
222 system-specific .mak file for me was unix-gcc.mak. The .mak file
223 of general application is contrib.mak.
224
225 */
226
227 /************************************************************************
228 * I N C L U D E F I L E S *
229 ************************************************************************/
230 #include "gdevprn.h"
231 #include "gsparam.h"
232
233 /************************************************************************
234 * R C S I D E N T S T R I N G S *
235 ************************************************************************/
236 const char Id[] =
237 "$Id: gdevlx50.c,v 1.41 2000-04-18 14:35:41+10 pbw Exp pbw $";
238 const char RCSFile[] = "$RCSFile$";
239 const char Revision[] = "$Revision: 1.41 $";
240 const char Author[] =
241 "Peter B. West pbwest@netscape.net\n"
242 "$Author: pbw $\n";
243 /*===========================================================================
244 In gxdevice.h, the default width and height are expressed in 10ths of an
245 inch. The conversion to mm will therefore, not be exact.
246
247 These values are immediately converted to (x,y) pixels for storage in the
248 width and height fields defined in the gx_device_common macro which is
249 defined in gxdevcli.h. These in turn are converted to points and stored
250 in the float MediaSize[2] array in gx_device_common by the
251 std_device_part_2_ macro in gxdevice.h.
252
253 The same macro stores the (x,y)dpi values in the float arrays
254 HWResolution[2] and MarginsHWResolution[2].
255
256 The macro prn_device_std_margins_body in gdevprn.h provides for X and Y
257 offsets, as well as left, bottom, right and top margin values. X & Y are
258 expressed in inches, as are all the other margin values.
259
260 The X & Y offsets are known as Margins in gx_device_common. They provide
261 the offset from the physical page corner (presumably top left, but may
262 depend on the position of 0,0) to 0,0 in the device co-ordinate system.
263 These values are converted by prn_device_std_margins_body into _negated_
264 (x,y)dpi and stored in the float Margins[2] array.
265
266 The left, bottom, right and top margin values are converted to points,
267 and stored in the float HWMargins[4] array. Note that these values are
268 defined relative to the physical paper, not the co-ordinate system. The
269 Margins array is used to transform from physical page offsets to the
270 device co-ordinate system.
271
272 The implications of this are that the X & Y offset from page corner to
273 0,0 should be defined as accurately as possible. The other four margins
274 should then be defined for a comprehensive coverage of the physical page.
275 The definitions of paper size given in 10ths of an inch in gxdevice.h are
276 a constraint.
277
278 I presume that the intention of the transformation from 0,0 to
279 the physical page is to leave the defined width and height mapped
280 onto the physical page, and for the left and top margins to then restore
281 those two dimensions of the accessible page. The result would be, if the
282 values of X & Y offset precisely reversed the values of left and top
283 HWMargins, that the top left hand printable point would be at device
284 co-ordinates 0,0. The bottom and right HWMargins would then provide the
285 necessary clipping of the co-ordinate system to keep output within the
286 printable area.
287
288 In fact, this is the way the x, Y offsets and the left and top margin
289 values are set up in the default prn_device_std_body macro in gdevprn.h.
290 In that macro, the X, Y offset values (expressed in inches) are simply
291 copied from the left and top margins.
292
293 What I have found with my 5000, is that it can print on virtually the
294 whole area of the paper. This shows some remarkable paper handling cap-
295 ability. This capability almost demands that 0,0 in the device co-ordin-
296 ate system be _outside_ the paper area. It is. On my printer, the X
297 offset from the physical page top left corner is 48 600ths of an inch -
298 a little less than 6 points.
299
300 The physical paper is a little narrower than 8.3 inches (210.82 mm), so
301 the attempt to print right to the 8.3" margin falls short by about 16
302 600ths, or about 2 points. When 0,0 falls _within_ the page, the combin-
303 ed margin clipping ensures that the driver will never issue printer com-
304 mands which exceed the defined width and height of the page. What
305 happens when 0,0 is outside the page? This implies, especially when the
306 hardware is capable of printing to the edges of the paper, that the
307 driver may issue print commands whose offsets exceed the defined width of
308 the page, in order to print to the right edge of the paper. I don't know
309 whether Ghostscript will allow this.
310
311 Print width
312 |<------------ 8.3" ----------->|
313 | |
314 | |
315 +-------------- ~ --------------+
316 |<-->| 2 pts
317 | |<----- Paper width --------->|
318 6 pts |<---->| |
319 +-------------- ~ ------------+
320
321 In this case, the X offset is going to be negative, and the device co-
322 ordinate value of X for the left edge of the paper is going to almost 50
323 600ths. It is a good idea to apply some restrictions on printing to the
324 edge of the paper, so a HWMargin should be applied.
325
326 The problem with setting the margins is this: Ghostscript knows where the
327 top and left sides of the page are relative to 0,0, because it is spec-
328 ifically informed of these values. It has no way of knowing where the
329 bottom and right of the page are, except from the height and width values.
330 These are only provided to an accuracy of a tenth of an inch, so the
331 assumed right and bottom margins may fall short of or overrun the edge of
332 the paper.
333
334 In these circumstances, it seems a good idea to provide HWMargin values
335 designed to enforce a uniform margin around all of the edges. The left &
336 top margins can be given directly; the others must be worked out so that
337 when applied with reference to the height and width parameters, they
338 result in the same margin.
339
340 For example, on my 5000, 0,0 is approximately 48/600" (about 6 points) to
341 the left of the physical page. When I print at an offset from 0 of
342 8.3", the default A4 width, the print is approximately 32/600" (about 4
343 points) inside the right edge of the page. That is, 8.3" is (48-32)/600"
344 too wide for the physical page.
345
346 4 points (4/72") is 0.05555", and 32/600" is 0.053333". If I set a left
347 HWMargin of 0.053", and Ghostscript obliges by mapping a new printable
348 origin 4 points inside the left edge of the paper, with 8.3" of print-
349 able line to the right of it, my left margin will need to account for the
350 extra 16/600" that GS thinks exists on the right, and for the actual
351 margin of 0.053" that I want to establish on the right. I think.
352
353 The interest in the top margin is that it seems to be keyed to the colour
354 pens. These form three blocks of nozzles vertically aligned in the
355 colour print head.
356
357 --- -- +-----+ v Alignment B
358 ^ ^ | | v --- +-----+ ---
359 | 64 | C | -- --- +-----+ --- | | ^
360 | v v | | 40 ^ | | ^ | | |
361 | -- -- +-----+ -- | | | | | |
362 | 24 ^ | | | | | |
363 | -- -- +-----+ | | | | | |
364 | ^ ^ | | | | | | |
365 240 64 | M | 192 | K | | K | 208
366 | v v | | | | | | |
367 | -- -- +-----+ | | | | | |
368 | 24 v | | | | | |
369 | -- -- +-----+ -- | | | | | |
370 | ^ ^ | | 40 v | | | | |
371 | 64 | Y | -- --- +-----+ | | v
372 v v | | ^ +-----+ ---
373 --- -- +-----+
374
375 The colour pens have 64 nozzles each, and the black has 208. Black can
376 also be driven in colour compatibility mode, when it uses 192 nozzles
377 only, the same as the total number of colour nozzles. In order to align
378 the black nozzles with the colour, an alignment value is specified in the
379 initialization sequence for the page. This value is in turn determined
380 by printing an alignment page under control of the printer driver (See
381 ancilliary files above.)
382
383 Note that when an odd number is specified as Alignment B, an odd numbered
384 nozzle will be mapped as nozzle 0 of the 192 nozzle black pen, so the
385 even/odd association of nozzle numbers will be reversed; i.e., nozzle 0
386 will become and ODD nozzle.
387
388 The paper handler seems to assume that the paper load position is with
389 the page lined up immediately before the lowest nozzle of the YELLOW pen.
390 (Note that the paper is being fed in from the bottom of the printheads.)
391 When I issue a paper feed instruction of 480 (240x2) 1200ths, and print a
392 three-colour bar, the top of the CYAN pen is just on the physical page.
393 Efectively, the Y component of 0,0 is right at the top of the page, with
394 respect to the YELLOW pen. Y=0 with respect to the 192 nozzle black pen
395 is always constant, and with respect to the 208 pen, can be determined
396 from Alignment B.
397
398
399 *===========================================================================*/
400
401 /************************************************************************
402 * B A S I C M A C R O S *
403 ************************************************************************/
404
405 #define A5_11_5000 1
406 #define A5_11_5700 2
407
408
409 #define ALIGN_A_DEF 15
410 #define ALIGN_A_OFFSET 5 /* in pageinit escape sequence */
411 #define ALIGN_B_DEF 8
412 #define ALIGN_B_OFFSET 6 /* in pageinit escape sequence */
413
414 #define HEADSEP_DEF 16
415 /* number of pixels between even columns in */
416 /* output and odd ones */
417 #define DRY_TIME_DEF 0 /* Default pause for page to dry */
418
419
420 /************************************************************************
421 * P R I N T E R T Y P E D E F I N I T I O N S *
422 ************************************************************************/
423
424 #ifndef LX_BI
425 # define LX_UNI
426 /* or define LX_BI */
427 #endif
428 #define MIN_LX5000_X 300
429 #define MAX_LX5000_X 1200
430 #define DEF_LX5000_X 600
431 #define MIN_LX5000_Y 600
432 #define MAX_LX5000_Y 1200
433 #define DEF_LX5000_Y MIN_LX5000_Y
434
435 #ifndef LX5000_XDPI
436 # define LX5000_XDPI DEF_LX5000_X
437 #endif
438 #ifndef LX5000_YDPI
439 # define LX5000_YDPI DEF_LX5000_Y
440 #endif
441
442 /* Multiply lines by FEED_FACTOR when feeding
443 paper. The 5000 feeds in 1200ths. */
444 #define FEED_FACTOR ( 1200/LX5000_YDPI )
445
446 #define LX5000_XOFFSET_TO_0_0_XDPI (-48.0)
447 #define LX5000_YOFFSET_TO_0_0_YDPI (0.0)
448
449 #define LX5000_XOFFSET_TO_0_0 ( LX5000_XOFFSET_TO_0_0_XDPI/LX5000_XDPI )
450 #define LX5000_YOFFSET_TO_0_0 ( LX5000_YOFFSET_TO_0_0_YDPI/LX5000_YDPI )
451
452 /* The theory */
453 #define LX5000_LEFT_HWMARGIN_INS 0.053
454 #define LX5000_BOTTOM_HWMARGIN_INS 0.067
455 #define LX5000_RIGHT_HWMARGIN_INS 0.08
456 #define LX5000_TOP_HWMARGIN_INS 0.053
457 /**/
458 /* The practice
459 ??
460 */
461
462 #define LINE_PAD_BYTES 8
463 /* number of bytes of padding on each end of */
464 /* scan line to account for head separation */
465 /* N.B. Keep this value 16-bit aligned. */
466
467 #define RIGHTWARD 0
468 #define LEFTWARD 1
469
470 #define SWIPE_WORD_BITS 16
471 /* Bits per directory word */
472 #define BLACK_NOZZLES 208
473 /* height of printhead in pixels */
474 #define _1COLOUR_NOZZLES 64
475 /* Height of one colour pen in pixels */
476
477 /* Height of colour compatible black swipe */
478 #define BLK_COLOUR_NOZZLES (_1COLOUR_NOZZLES * 3)
479
480 /* number of shorts described by each */
481 /* full black column directory */
482 #define BLK_SWIPE_WORDS ( BLACK_NOZZLES / SWIPE_WORD_BITS )
483 #define COLOUR_SWIPE_WORDS ( BLK_COLOUR_NOZZLES / SWIPE_WORD_BITS )
484 /* and for a colour swipe command */
485 #define _1COLOUR_WORDS ( _1COLOUR_NOZZLES / SWIPE_WORD_BITS )
486 /* and for a single colour pen */
487
488 #define BLK_DIRECTORY_MASK (( ~0 << BLK_SWIPE_WORDS ) ^ ~0 )
489 #define COLOUR_DIRECTORY_MASK (( ~0 << COLOUR_SWIPE_WORDS ) ^ ~0 )
490 #define DIRECTORY_TYPE_BIT 0x2000
491 /* Directory type: Set = normal;
492 unset = repeat compression */
493
494 #define COLOUR_PEN_GAP 24 /* Defined in equivalent nozzles. This will */
495 /* also be the offset from the top of the */
496 /* first colour pen to the top of the colour */
497 /* compatible black pen. */
498 #define COLOUR_PEN_DIFF ( _1COLOUR_NOZZLES + COLOUR_PEN_GAP )
499 /* The difference between corresponding */
500 /* nozzle positions (e.g. bottom nozzle) on */
501 /* contiguous colour pens. */
502
503 /* The intial pen scanline positions are */
504 /* defined with reference to the first */
505 /* printable line (line 0) on the page. The */
506 /* initial colour cartridge position is */
507 /* immediately above line 0. */
508 #define INITIAL_YELLOW_BOTTOM_LINE ( -1 )
509
510 /* The pen buffer size must be a power of */
511 /* 2, so that the index into the buffer */
512 /* will either wrap within that size on */
513 /* increment, or be able to be masked to */
514 /* force a wrap of the index into the */
515 /* circular pen buffers. See discussion */
516 /* of pen buffers in lx5000_print_page(). */
517 #define COLOUR_BUF_MASK 0xff
518 /* 2^8 - 1 */
519 #define COLOUR_BUF_LINES ( COLOUR_BUF_MASK + 1 )
520
521 /************************************************************************
522 * S W I P E C O M M A N D M A C R O S *
523 ************************************************************************/
524
525 #define SWIPE_LEADER 0x1b, '*', 4
526 /* Lead-in bytes for swipe command */
527
528 #define CMDLEN_X 3
529 /* Index in swipe command of 4 byte */
530
531 #define DIRECTION_X 7
532 /* Index in swipe cmd of direction flag */
533
534 #define UNIDIRECTIONAL 0
535 #define BIDIRECTIONAL 1
536
537 #define HEADSPEED_X 8
538 /* Index in swipe cmd of head speed */
539 /* Head speeds for various densities */
540 #define _300X 1
541 #define _600X 2
542 #define _1200X 5
543
544 #define PEN_X 9
545 /* Index of 2 byte pen selectors */
546 #define BLACK0 1
547 #define BLACK1 1
548 #define COLOUR0 2
549 #define COLOUR1 0
550
551 #define NOZZLE_COUNT_X 11
552 /* Index of nozzle count selector */
553 #define _192NOZZLES 0x18
554 #define _208NOZZLES 0x1a
555
556 #define UNKNOWN1_X 12
557 /* Index of an unknown byte */
558 #define UNKNOWN1VAL 0
559 #define NUM_COLUMNS_X 13
560 /* Index in swipe command of 2 byte */
561 /* column count */
562 #define _1ST_COLUMN_X 15
563 /* Index in swipe command of 2 byte */
564 /* first column horizontal offset */
565 #define LAST_COLUMN_X 17
566 /* Index in swipe command of 2 byte */
567 /* last column horizontal offset */
568
569 #define SWIPE_HDR_END_X 19
570 #define SWIPE_HDR_END_LEN 7
571 #define SWIPE_HDR_END 0, 0, '+', 'p', 'b', 'w', 1
572 /* Final byte sequence of swipe cmd header */
573
574 #define SWIPE_HDR_LEN ( SWIPE_HDR_END_X + SWIPE_HDR_END_LEN )
575
576 /************************************************************************
577 * C O L O U R H A N D L I N G M A C R O S *
578 ************************************************************************/
579 /* Macros for the relative position on the colour components in */
580 /* gx_color_index, the driver defined representation of individual */
581 /* colours. */
582
583 #define BLACK_X 0
584 #define YELLOW_X 1
585 #define MAGENTA_X 2
586 #define CYAN_X 3
587
588 #define LO_PEN 0
589 #define HI_PEN 1
590
591 /* Colour defines for lx5000 black printer */
592
593 # define NUM_COMPONENTS_BLK 1
594 # define BITS_PER_PIXEL_BLK 1
595 # define MAX_GREY_BLK 1
596 # define MAX_RGB_BLK 0
597 # define DITHER_GREYS_BLK 2
598 # define DITHER_COLOURS_BLK 0
599
600 /* Colour defines for lx5000 colour printer */
601 # define NUM_COMPONENTS_CMY 4
602 # define BITS_PER_PIXEL_CMY 4
603 # define MAX_GREY_CMY 1
604 # define MAX_RGB_CMY 1
605 # define DITHER_GREYS_CMY 2
606 # define DITHER_COLOURS_CMY 2
607
608 # define MIN_COLOUR BLACK_X
609 # define MAX_COLOUR CYAN_X
610 # define BLACK_PEN BLACK_X
611 # define _1ST_CMY_COLOUR YELLOW_X
612 # define LAST_CMY_COLOUR CYAN_X
613
614 #define BPP BITS_PER_PIXEL_CMY
615 /* N.B. This is only required for
616 processCMYKline */
617 # define PIXEL_MASK (( 1 << BPP ) - 1 )
618 # define INITIAL_PIXEL_SHIFT ( ( sizeof( uchar ) * 8 ) - BPP )
619
620 #define NUM_COLOURS ( MAX_COLOUR - MIN_COLOUR + 1 )
621 #define PENS_PER_COLOUR 2
622 #define NUM_PENS ( NUM_COLOURS * PENS_PER_COLOUR )
623
624 #define BITS_PER_COLOUR (BITS_PER_PIXEL_CMY / NUM_COMPONENTS_CMY)
625
626 #define DEF_NUM_COLOURS NUM_COLOURS
627 #define DEF_PENS_PER_COLOUR 1
628 #define DEF_LINE_INCREMENT 1
629
630 /* !!!!!!!!!!!!!!!!!!!!! WARNING, WARNING, WILL ROBINSON !!!!!!!!!!!!!!!!!!!!*/
631 /* If BPP ever exceeds 8, this will break
632 badly, as will the whole of processCMYKline.
633 PIXELS_PER_BYTE is used when skipping over
634 empty bytes in processCMYKline(). Each
635 empty scanline byte skips over this many
636 bits in the colourBufs. */
637 #define PIXELS_PER_BYTE (8 / BPP)
638
639 #define COLOUR_MASK (( 1 << ( BITS_PER_COLOUR ) ) - 1 )
640
641 /************************************************************************
642 * Memory allocation macros *
643 * ( For use with getColourBufs & releaseAllocations ) *
644 ************************************************************************/
645 #define ALLOCATE true
646 #define DEALLOCATE false
647
648 /************************************************************************
649 * " F U N C T I O N A L " M A C R O S *
650 ************************************************************************/
651 /************************************************************************
652 * Macro to fill the swipe header *
653 ************************************************************************/
654
655 #define FILL_SWIPE_HEADER( swipeHdr, len, dir, speed, pen0, pen1, nozzles, \
656 unknown, numcols, firstcol, lastcol ) \
657 swipeHdr[ CMDLEN_X ] = ( ( len >> 24 ) & 0xff ); \
658 swipeHdr[ CMDLEN_X + 1 ] = ( ( len >> 16 ) & 0xff ); \
659 swipeHdr[ CMDLEN_X + 2 ] = ( ( len >> 8 ) & 0xff ); \
660 swipeHdr[ CMDLEN_X + 3 ] = ( len & 0xff ); \
661 swipeHdr[ DIRECTION_X ] = dir; \
662 swipeHdr[ HEADSPEED_X ] = speed; \
663 swipeHdr[ PEN_X ] = pen0; \
664 swipeHdr[ PEN_X + 1 ] = pen1; \
665 swipeHdr[ NOZZLE_COUNT_X ] = nozzles; \
666 swipeHdr[ UNKNOWN1_X ] = unknown; \
667 swipeHdr[ NUM_COLUMNS_X ] = ( numcols >> 8 ); \
668 swipeHdr[ NUM_COLUMNS_X + 1 ] = ( numcols & 0xff ); \
669 swipeHdr[ _1ST_COLUMN_X ] = ( firstcol >> 8 ); \
670 swipeHdr[ _1ST_COLUMN_X + 1 ] = ( firstcol & 0xff ); \
671 swipeHdr[ LAST_COLUMN_X ] = ( lastcol >> 8 ); \
672 swipeHdr[ LAST_COLUMN_X + 1 ] = ( lastcol & 0xff )
673
674
675 /************************************************************************
676 * Macros to manipulate bit pointers in bitBuf & scanPixels structs *
677 ************************************************************************/
678 #define BIT_TO_MASK( n ) ( 0x80 >> ( n ) )
679 #define INC_BIT( bitPtr ) \
680 do { \
681 if ( ! ((bitPtr).xBit >>= 1 )) \
682 { (bitPtr).xByte++ ; (bitPtr).xBit = 0x80; } \
683 } while (0)
684
685 #define DEC_BIT( bitPtr ) \
686 do { \
687 if ( ! ( (bitPtr).xBit = (( (bitPtr).xBit << 1 ) & 0xff ))) \
688 { (bitPtr).xByte-- ; (bitPtr).xBit = 1; } \
689 } while (0)
690
691 /************************************************************************
692 * Macro for defining gx_device_procs structure *
693 ************************************************************************/
694
695 #define lx5000_proctab(get_params, put_params, map_color_rgb, map_cmyk_color)\
696 { gdev_prn_open,\
697 gx_default_get_initial_matrix,\
698 NULL, /* sync_output */\
699 gdev_prn_output_page,\
700 gdev_prn_close,\
701 NULL, /* map_rgb_color */\
702 map_color_rgb,\
703 NULL, /* fill_rectangle */\
704 NULL, /* tile_rectangle */\
705 NULL, /* copy_mono */\
706 NULL, /* copy_color */\
707 NULL, /* draw_line */\
708 NULL, /* get_bits */\
709 get_params,\
710 put_params,\
711 map_cmyk_color,\
712 NULL, /* get_xfont_procs */\
713 NULL, /* get_xfont_device */\
714 NULL, /* map_rgb_alpha_color */\
715 gx_page_device_get_page_device /* get_page_device */\
716 }
717
718 /************************************************************************
719 * T Y P E D E F S E N U M S & E X T E R N A L S T O R A G E *
720 ************************************************************************/
721 /* The procedure descriptors */
722 /* declare functions */
723 private dev_proc_print_page(lx5000_print_page);
724 private dev_proc_get_params(lx5000_get_params);
725 private dev_proc_put_params(lx5000_put_params);
726
727 private dev_proc_map_cmyk_color(lx5000_map_cmyk_color);
728 private dev_proc_map_color_rgb(lx5000_map_color_rgb);
729
730 private const gx_device_procs lx5000_procs =
731 lx5000_proctab(
732 lx5000_get_params,
733 lx5000_put_params,
734 lx5000_map_color_rgb,
735 lx5000_map_cmyk_color
736 );
737
738 /* The device descriptors */
739 /* define a subclass containing useful state */
740 /* a sub-class of gx_device_printer */
741 typedef struct lx5000_device_s {
742 gx_device_common;
743 gx_prn_device_common;
744 int alignA;
745 int alignB;
746 int headSeparation;
747 int dryTime; /* Seconds delay at end of page for drying */
748 int pensPerColour; /* 1 for 600Y; 2 for 1200Y */
749 int lineIncrement; /* 1 for 600Y; 2 for 1200Y */
750 int scanLineBytes; /* Returned by GS */
751 int penLineBytes; /* When scanline colour elements are each
752 reduced to a single bit, this is the result-
753 ing line length in bytes. */
754 int penLineLen; /* penLineBytes + BOL + EOL padding */
755 int penBufSize; /* penLineLen * no. of lines */
756 int swipeBufSize; /* calculated size of a swipe command buffer */
757 bool isCMYK;
758 } lx5000_device;
759
760 /* Define a structure for a pointer to an */
761 /* individual bit in a scanline */
762 typedef struct bufBit_s {
763 byte *xByte; /* Pointer to byte in buffer */
764 uchar xBit; /* Mask for invidual bit in byte */
765 } bufBit;
766
767
768 typedef struct penData_s {
769 int topLine; /* Top printable line of this pen */
770 int bottomLine; /* Bottom printable line of this pen */
771 int nextPrintLine; /* Next line to be printed, this pen */
772
773 int initialBottomLine;
774 int bottomToBottomYellow;
775 int topToBottomYellow;
776 int finalLine;
777 } penData;
778
779 /* Structure for extracting pixels from the
780 initial scan line, which must be int
781 aligned. */
782 typedef struct scanPixels_s {
783 uchar *scanByte; /* Pointer to a byte in the scan buffer */
784 int pixShift; /* Shift required to get next pixel to */
785 } scanPixels; /* the LSBits of the word. */
786
787 /* Standard lx5000 device */
788 lx5000_device far_data gs_lx5000_device = {
789 prn_device_margins_body
790 ( lx5000_device,
791 lx5000_procs,
792 "lx5000",
793 DEFAULT_WIDTH_10THS,
794 DEFAULT_HEIGHT_10THS,
795 LX5000_XDPI, /* x dpi */
796 LX5000_YDPI, /* y dpi */
797 /* Offset inches from page left to 0,0 */
798 LX5000_XOFFSET_TO_0_0,
799 /* Offset inches from page top to 0,0 */
800 LX5000_YOFFSET_TO_0_0,
801 LX5000_LEFT_HWMARGIN_INS, /* margins */
802 LX5000_BOTTOM_HWMARGIN_INS,
803 LX5000_RIGHT_HWMARGIN_INS,
804 LX5000_TOP_HWMARGIN_INS,
805 NUM_COMPONENTS_CMY, /* colour info */
806 BITS_PER_PIXEL_CMY, /* " */
807 MAX_GREY_CMY, /* " */
808 MAX_RGB_CMY, /* " */
809 DITHER_GREYS_CMY, /* " */
810 DITHER_COLOURS_CMY, /* " */
811 lx5000_print_page
812 ),
813 ALIGN_A_DEF, /* default(!) horizontal pen alignment */
814 ALIGN_B_DEF, /* default(!) vertical pen alignment */
815 HEADSEP_DEF, /* default headSeparation value */
816 DRY_TIME_DEF, /* Default page drying time */
817 DEF_PENS_PER_COLOUR,
818 DEF_LINE_INCREMENT,
819 0, /* scanLineBytes */
820 0, /* penLineBytes */
821 0, /* penLineLen */
822 0, /* penBufSize */
823 0, /* swipeBufSize */
824 true /* isCMYK - defaults to using colour */
825 };
826
827 private const gx_device_color_info color_info_cmy =
828 {
829 NUM_COMPONENTS_CMY,
830 BITS_PER_PIXEL_CMY,
831 MAX_GREY_CMY,
832 MAX_RGB_CMY,
833 DITHER_GREYS_CMY,
834 DITHER_COLOURS_CMY
835 };
836
837 private const gx_device_color_info color_info_blk =
838 {
839 NUM_COMPONENTS_BLK,
840 BITS_PER_PIXEL_BLK,
841 MAX_GREY_BLK,
842 MAX_RGB_BLK,
843 DITHER_GREYS_BLK,
844 DITHER_COLOURS_BLK
845 };
846
847
848 /************************************************************************
849 ************************************************************************
850 * D R I V E R P R O C E D U R E S *
851 ************************************************************************
852 ************************************************************************/
853
854 /************************************************************************
855 * U T I L I T Y P R O C E D U R E S *
856 ************************************************************************/
857
858 /*----------------------------------------------------------------------*
859 * i n i t P e n C o n s t a n t s ( ) *
860 *----------------------------------------------------------------------*
861 *----------------------------------------------------------------------*/
862 private void
initPenConstants(lx5000_device * lx5000dev,penData pens[NUM_COLOURS][PENS_PER_COLOUR])863 initPenConstants( lx5000_device *lx5000dev,
864 penData pens[NUM_COLOURS][PENS_PER_COLOUR] )
865 {
866 /* Indexed by pensPerColour. */
867 static const int nozzleCount[ NUM_COLOURS ][ PENS_PER_COLOUR + 1 ] =
868 {
869 { -1, BLACK_NOZZLES, (BLACK_NOZZLES / 2) },
870 { -1, _1COLOUR_NOZZLES, (_1COLOUR_NOZZLES / 2) },
871 { -1, _1COLOUR_NOZZLES, (_1COLOUR_NOZZLES / 2) },
872 { -1, _1COLOUR_NOZZLES, (_1COLOUR_NOZZLES / 2) }
873 };
874
875 int colour, pen;
876 int pensPerColour = lx5000dev->pensPerColour;
877
878 pens[YELLOW_X][LO_PEN].initialBottomLine = -1;
879 pens[MAGENTA_X][LO_PEN].initialBottomLine =
880 pens[YELLOW_X][LO_PEN].initialBottomLine
881 - COLOUR_PEN_DIFF;
882 pens[CYAN_X][LO_PEN].initialBottomLine =
883 pens[MAGENTA_X][LO_PEN].initialBottomLine
884 - COLOUR_PEN_DIFF;
885 pens[BLACK_X][LO_PEN].initialBottomLine =
886 pens[YELLOW_X][LO_PEN].initialBottomLine
887 - COLOUR_PEN_GAP
888 + ( SWIPE_WORD_BITS - lx5000dev->alignB );
889
890 for ( colour = 0; colour < NUM_COLOURS; colour++ )
891 {
892 pens[colour][LO_PEN].bottomToBottomYellow
893 = pens[YELLOW_X][LO_PEN].initialBottomLine
894 - pens[colour][LO_PEN].initialBottomLine;
895 }
896
897 if ( pensPerColour == 1 )
898 {
899 pens[BLACK_X][LO_PEN].topToBottomYellow =
900 BLK_COLOUR_NOZZLES + COLOUR_PEN_GAP
901 + lx5000dev->alignB - 1;
902 pens[YELLOW_X][LO_PEN].topToBottomYellow = _1COLOUR_NOZZLES - 1;
903 pens[MAGENTA_X][LO_PEN].topToBottomYellow =
904 pens[YELLOW_X][LO_PEN].topToBottomYellow
905 + COLOUR_PEN_DIFF;
906 pens[CYAN_X][LO_PEN].topToBottomYellow =
907 pens[MAGENTA_X][LO_PEN].topToBottomYellow
908 + COLOUR_PEN_DIFF;
909
910 for ( colour = 0; colour < NUM_COLOURS; colour++ )
911 {
912 pens[colour][HI_PEN].topToBottomYellow
913 = pens[colour][LO_PEN].topToBottomYellow;
914 pens[colour][HI_PEN].initialBottomLine
915 = pens[colour][LO_PEN].initialBottomLine;
916 pens[colour][HI_PEN].bottomToBottomYellow
917 = pens[colour][LO_PEN].bottomToBottomYellow;
918 }
919 }
920 else /* pensPerColour > 1 */
921 {
922 pens[BLACK_X][HI_PEN].topToBottomYellow =
923 BLK_COLOUR_NOZZLES + COLOUR_PEN_GAP
924 + lx5000dev->alignB - 1;
925 pens[BLACK_X][LO_PEN].topToBottomYellow =
926 pens[BLACK_X][HI_PEN].topToBottomYellow
927 - nozzleCount[BLACK_X][pensPerColour];
928 pens[YELLOW_X][HI_PEN].topToBottomYellow = _1COLOUR_NOZZLES - 1;
929 pens[YELLOW_X][LO_PEN].topToBottomYellow =
930 pens[YELLOW_X][HI_PEN].topToBottomYellow
931 - nozzleCount[YELLOW_X][pensPerColour];
932 pens[MAGENTA_X][HI_PEN].topToBottomYellow =
933 pens[YELLOW_X][HI_PEN].topToBottomYellow
934 + COLOUR_PEN_DIFF;
935 pens[MAGENTA_X][LO_PEN].topToBottomYellow =
936 pens[MAGENTA_X][HI_PEN].topToBottomYellow
937 -nozzleCount[MAGENTA_X][pensPerColour];
938 pens[CYAN_X][HI_PEN].topToBottomYellow =
939 pens[MAGENTA_X][HI_PEN].topToBottomYellow
940 + COLOUR_PEN_DIFF;
941 pens[CYAN_X][LO_PEN].topToBottomYellow =
942 pens[CYAN_X][HI_PEN].topToBottomYellow
943 - nozzleCount[CYAN_X][pensPerColour];
944
945 for ( colour = 0; colour < NUM_COLOURS; colour++ )
946 {
947 pens[colour][HI_PEN].bottomToBottomYellow =
948 pens[colour][LO_PEN].bottomToBottomYellow
949 + nozzleCount[colour][pensPerColour];
950 pens[colour][HI_PEN].initialBottomLine =
951 pens[colour][LO_PEN].initialBottomLine
952 - nozzleCount[colour][pensPerColour];
953 }
954 }
955
956 for ( colour = 0; colour < NUM_COLOURS; colour++ )
957 {
958 for ( pen = 0; pen < PENS_PER_COLOUR; pen++ )
959 {
960 pens[colour][pen].finalLine =
961 ( lx5000dev->height ) + pens[colour][pen].topToBottomYellow;
962 }
963 }
964 }
965
966 /*----------------------------------------------------------------------*
967 * p a g e I n i t ( ) *
968 *----------------------------------------------------------------------*
969 *----------------------------------------------------------------------*/
970 private void
pageInit(unsigned int alignA,unsigned int alignB,FILE * prn_stream)971 pageInit( unsigned int alignA, unsigned int alignB, FILE *prn_stream )
972 {
973 static char page_init[] = {
974 0x1b, '*', 'm', 0, 0x40, ALIGN_A_DEF, ALIGN_B_DEF, 0xf, 0xf
975 };
976
977 page_init[ALIGN_A_OFFSET] = (uchar)alignA;
978 page_init[ALIGN_B_OFFSET] = (uchar)alignB;
979
980 fwrite( page_init, 1, sizeof( page_init ), prn_stream );
981 }
982
983 /*----------------------------------------------------------------------*
984 * p a g e E n d ( ) *
985 *----------------------------------------------------------------------*
986 *----------------------------------------------------------------------*/
987 private void
pageEnd(FILE * prn_stream)988 pageEnd( FILE *prn_stream )
989 {
990 static const char page_end[] = {
991 0x1b,'*', 7, 0x65
992 };
993
994 fwrite( page_end, 1, sizeof( page_end ), prn_stream );
995 /* Do it twice - that's what the Windows */
996 /* driver for the 5000 does */
997 fwrite( page_end, 1, sizeof( page_end ), prn_stream );
998 }
999
1000 /*----------------------------------------------------------------------*
1001 * f e e d P a p e r ( ) *
1002 *----------------------------------------------------------------------*
1003 *----------------------------------------------------------------------*/
1004 private void
feedPaper(lx5000_device * lx5000dev,int newLine,int * currentLine,penData pens[NUM_COLOURS][PENS_PER_COLOUR],FILE * prn_stream)1005 feedPaper( lx5000_device *lx5000dev, int newLine, int *currentLine,
1006 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1007 FILE *prn_stream )
1008 {
1009 static const char feed_paper[] = {
1010 0x1b, '*', 3
1011 };
1012
1013 ushort _1200ths;
1014 int colour, pen;
1015
1016 if ( newLine >= *currentLine )
1017 {
1018 _1200ths = (ushort)(( newLine - *currentLine ) * FEED_FACTOR );
1019 fwrite( feed_paper, 1, sizeof( feed_paper ), prn_stream );
1020 putc( _1200ths >> 8 , prn_stream);
1021 putc( _1200ths & 0xff, prn_stream );
1022
1023 *currentLine = newLine;
1024
1025 for ( colour = 0;
1026 colour < lx5000dev->color_info.num_components;
1027 colour++ )
1028 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1029 {
1030 pens[colour][pen].topLine =
1031 newLine - pens[colour][pen].topToBottomYellow;
1032 pens[colour][pen].bottomLine =
1033 newLine - pens[colour][pen].bottomToBottomYellow;
1034 }
1035
1036 }
1037 }
1038
1039
1040 /*----------------------------------------------------------------------*
1041 * g e t C o l o u r B u f s ( ) *
1042 *----------------------------------------------------------------------*
1043 Return pointers to the allocated buffers in those pointers whose addresses
1044 have been passed as parameters, or release the allocations.
1045
1046 Allocation is indicated by a true value of the argument `allocate'.
1047
1048 The buffers themselves are allocated and the pointers to them are kept
1049 in static storage. On the first call, the buffers are allocated, and the
1050 pointers to them are maintained in static storage. On all subsequent
1051 calls, the pointer contents are simply returned.
1052
1053 Deallocation is indicated by a false value of the argument `allocate'.
1054
1055 If the pointers are non-null, the allocated memory is released, and
1056 the pointer values are set to NULL.
1057
1058 N.B. The arrays are defined in terms of the maximum values for the array
1059 dimensions, even though the actual usage of each dimension is dynamically
1060 determined. E.g. colourBufs is dimensioned [NUM_COLOURS],
1061 even though the number of colour dimensions actually used is determined
1062 by the variable numColours, which will be 1 if the driver is being used
1063 in black-only mode.
1064 *----------------------------------------------------------------------*/
1065 int
getColourBufs(lx5000_device * lx5000dev,byte ** lineBufferPtr,byte * colourBufPtrs[],byte ** swipeBufPtr,bool allocate)1066 getColourBufs( lx5000_device *lx5000dev,
1067 byte **lineBufferPtr, byte *colourBufPtrs[],
1068 byte **swipeBufPtr, bool allocate )
1069 {
1070 static byte *colourBufs[ NUM_COLOURS ];
1071 /* Only an array of pointers; OK if too big */
1072 static byte *lineBuffer = NULL;
1073 static byte *swipeBuf = NULL;
1074
1075 int colour;
1076 int colourBufNull = 0;
1077 int numColours = lx5000dev->color_info.num_components;
1078
1079 if ( allocate )
1080 {
1081 if ( lineBuffer == NULL )
1082 {
1083 /* Initialise the pen buffers */
1084 for ( colour = 0; colour < numColours; colour++ )
1085 colourBufs[ colour ] = NULL;
1086
1087 /*---------------------------------------------------------------*
1088 Derive the size of a colour buffer line: If the number of
1089 components is one and the number of bits per pixel is one, then
1090 there is only one bit per pixel in the scan line, so the colour
1091 buffer line is the same size.
1092
1093 Otherwise, reduce each gx_color_index element in the scan line to
1094 one bit in the penprint buffer.
1095 *--------------------------------------------------------------*/
1096
1097 lx5000dev->scanLineBytes = gdev_mem_bytes_per_scan_line(
1098 (gx_device *)lx5000dev );
1099 lx5000dev->penLineBytes =
1100 ( lx5000dev->color_info.num_components == 1
1101 && lx5000dev->color_info.depth == 1 )
1102 ? lx5000dev->scanLineBytes
1103 : ( lx5000dev->scanLineBytes / sizeof( gx_color_index ));
1104
1105 lx5000dev->penLineLen =
1106 lx5000dev->penLineBytes + ( LINE_PAD_BYTES * 2);
1107
1108 lx5000dev->penBufSize
1109 = lx5000dev->penLineLen * COLOUR_BUF_LINES;
1110
1111 /* swipeBuf size:
1112 * No. of columns = No. of bits in the linebuf
1113 * Bits per column = maximum swipe height
1114 * Bytes per column = Bits per column / 8 + 2 byte directory
1115 * Total bytes = Bytes/column * no. of columns + header bytes
1116 */
1117 lx5000dev->swipeBufSize =
1118 ((lx5000dev->penLineLen * 8)
1119 * ((BLACK_NOZZLES / 8) + 2) + SWIPE_HDR_LEN);
1120
1121 /* Allocate a buffer for a single scan line */
1122 lineBuffer = (byte *)gs_alloc_byte_array
1123 ( &gs_memory_default, lx5000dev->scanLineBytes, 1,
1124 "lx5000_print_page(lineBuffer)" );
1125
1126 swipeBuf = (byte *)gs_alloc_byte_array
1127 ( &gs_memory_default, lx5000dev->swipeBufSize, 1,
1128 "lx5000_print_page(swipeBuf)" );
1129
1130 for ( colour = 0 ; colour < numColours; colour++ )
1131 {
1132 if ( ( colourBufs[colour] =
1133 (byte *)gs_alloc_byte_array
1134 ( &gs_memory_default, lx5000dev->penBufSize, 1,
1135 "lx5000_print_page(colourBufs)"
1136 )
1137 ) == NULL )
1138 {
1139 colourBufNull = 1;
1140 colour = numColours;
1141 }
1142 }
1143 /* Check allocations */
1144 if ( lineBuffer == NULL || colourBufNull || swipeBuf == NULL ) {
1145 getColourBufs( lx5000dev, lineBufferPtr, colourBufPtrs,
1146 swipeBufPtr, DEALLOCATE );
1147 return_error( gs_error_VMerror );
1148 }
1149 }
1150 /* Clear the black buffer, iff ! isCMYK. If CMYK, scan lines are
1151 processed by processCMYKlines(), and buffer lines are cleared
1152 individually, before a new scan line is processed. As part of this
1153 clearing, the line EOL and BOL pads are also cleared.
1154 If ! CMYK, the black-only scan line is read or copied directly
1155 into the black buffer, without clearing the buffer. Therefore, the
1156 line pad regions must either be cleared individually for each line
1157 processed, or cleared once when the buffer is allocated.
1158 */
1159 if ( ! lx5000dev->isCMYK )
1160 memset( colourBufs[BLACK_X], 0, lx5000dev->penBufSize );
1161
1162 /* Return the values */
1163 *lineBufferPtr = lineBuffer;
1164 *swipeBufPtr = swipeBuf;
1165 for ( colour = 0; colour < numColours; colour++ )
1166 colourBufPtrs[colour] = colourBufs[colour];
1167
1168 return 0;
1169 }
1170 else /* Deallocate the buffers */
1171 {
1172 for ( colour = 0; colour < numColours; colour++ )
1173 {
1174 if ( colourBufs[colour] != NULL )
1175 gs_free_object( &gs_memory_default,
1176 (char *)colourBufs[colour],
1177 "lx5000_print_page(colourBufs)" );
1178 colourBufs[ colour ] = NULL;
1179 colourBufPtrs[ colour ] = NULL;
1180 }
1181 if ( swipeBuf != NULL )
1182 gs_free_object( &gs_memory_default,
1183 (char *)swipeBuf, "lx5000_print_page(swipeBuf)" );
1184 swipeBuf = NULL;
1185 *swipeBufPtr = NULL;
1186 if ( lineBuffer != NULL )
1187 gs_free_object( &gs_memory_default,
1188 (char *)lineBuffer, "lx5000_print_page(lineBuffer)" );
1189 lineBuffer = NULL;
1190 *lineBufferPtr = NULL;
1191 return 0;
1192 }
1193 }
1194
1195
1196 /*----------------------------------------------------------------------*
1197 * p r o c e s s C M Y K l i n e ( ) *
1198 *----------------------------------------------------------------------*
1199 Given a scan line number, a pointer to a scan line, an array of pointers to
1200 individual colour buffers, and an array of the individual pen scanBit
1201 arrays, distribute the scan line elements into the colour buffers.
1202
1203 N.B. The empty indicator for each line for each pen buffer must also be
1204 set by this procedure.
1205
1206 Things like dithering may well end up in here.
1207 *----------------------------------------------------------------------*/
1208 private void
processCMYKline(lx5000_device * lx5000dev,int linenum,byte * lineBuffer,byte * scanLine,byte * colourBufs[NUM_COLOURS],bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],penData pens[NUM_COLOURS][PENS_PER_COLOUR],bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES])1209 processCMYKline( lx5000_device *lx5000dev, int linenum,
1210 byte *lineBuffer, byte *scanLine,
1211 byte *colourBufs[NUM_COLOURS],
1212 bufBit
1213 colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],
1214 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1215 bool lineEmpty[NUM_COLOURS][ COLOUR_BUF_LINES ] )
1216 {
1217 int colour;
1218 int numColours = lx5000dev->color_info.num_components;
1219
1220 uchar colourBits[ numColours ];
1221 uchar lineIndex;
1222 uchar scanPixel;
1223 scanPixels nextPixel;
1224 bufBit nextBit[ numColours ];
1225 /* The end of the (scan)line. */
1226 uchar *scanEnd = scanLine + lx5000dev->scanLineBytes;
1227
1228 nextPixel.scanByte = scanLine; /* Set up the moving pixel pointer. */
1229 nextPixel.pixShift = INITIAL_PIXEL_SHIFT;
1230 lineIndex = (uchar)( linenum & COLOUR_BUF_MASK );
1231
1232 for ( colour = 0; colour < numColours; colour++ )
1233 {
1234 /* Set up the moving output bit pointer for
1235 each of the colours. */
1236 nextBit[ colour ].xByte = colourBufs[ colour ] + LINE_PAD_BYTES
1237 + ( lineIndex * lx5000dev->penLineLen );
1238 nextBit[ colour ].xBit = BIT_TO_MASK( 0 );
1239 /* Clear the colourBuf line if necessary */
1240 if ( ! lineEmpty[ colour ][ lineIndex ] )
1241 {
1242 memset( nextBit[ colour ].xByte - LINE_PAD_BYTES,
1243 0, lx5000dev->penLineLen );
1244 lineEmpty[ colour ][ lineIndex ] = true;
1245 }
1246 }
1247 /* Is the line empty? */
1248 if (( ! *scanLine ) &&
1249 ! memcmp( scanLine, scanLine + 1, lx5000dev->scanLineBytes - 1 ))
1250 return; /* N.B. empty flag is pre-set to true */
1251
1252 while ( nextPixel.scanByte < scanEnd )
1253 {
1254 int colour;
1255 int cmy; /* Used to detect if C+M+Y set */
1256 int skipPixels, skipBytes, skipBits;
1257 /* Number of consecutive empty pixels, equiv-
1258 alent bytes and remainder bits just skipped
1259 over in the CMYK line being processed. */
1260
1261 /* Get next pixel and increment the pointer */
1262 scanPixel =
1263 ( ( *(nextPixel.scanByte) >> nextPixel.pixShift ) & PIXEL_MASK );
1264
1265 /* pixShift is the number of bits to right-shift the scanByte
1266 before applying PIXEL_MASK. When we attempt to decrement
1267 it past 0, it's time to look at the next scanByte.
1268 N.B. We assume that the subtraction of BPP will end with
1269 zero, i.e., that there are an integral number of BPPs in
1270 INITIAL_PIXEL_SHIFT. We test for <= 0 just
1271 in case this condition gets violated.
1272 */
1273 skipPixels = 0;
1274 if ( nextPixel.pixShift <= 0 )
1275 {
1276 nextPixel.scanByte++;
1277 nextPixel.pixShift = INITIAL_PIXEL_SHIFT;
1278 /* If the next byte is empty, skip it */
1279 while (( ! *nextPixel.scanByte ) && nextPixel.scanByte < scanEnd )
1280 {
1281 nextPixel.scanByte++;
1282 skipPixels += PIXELS_PER_BYTE;
1283 }
1284 }
1285 else
1286 nextPixel.pixShift -= BPP;
1287 /* Get the black bit(s) */
1288 colourBits[ BLACK_X ] = scanPixel & COLOUR_MASK;
1289 scanPixel >>= BITS_PER_COLOUR;
1290 /* Set to catch all ANDed bits from colours */
1291 cmy = ~0;
1292 for ( colour = YELLOW_X; colour <= CYAN_X; colour++ )
1293 {
1294 colourBits[ colour ] = scanPixel & COLOUR_MASK;
1295 cmy &= scanPixel & COLOUR_MASK;
1296 scanPixel >>= BITS_PER_COLOUR;
1297 }
1298 if ( ( cmy ^ COLOUR_MASK ) == 0 ) /* C, M & Y all set == COLOUR_MASK */
1299 {
1300 colourBits[ YELLOW_X ] =
1301 colourBits[ MAGENTA_X ] = colourBits[ CYAN_X ] = 0;
1302 colourBits[ BLACK_X ] = COLOUR_MASK;
1303 }
1304 /* Now set the colourBuf bits */
1305 skipBytes = skipPixels >> 3;
1306 skipBits = skipPixels & 7;
1307 for ( colour = 0; colour < numColours; colour++ )
1308 {
1309 if ( colourBits[ colour ] )
1310 {
1311 *( nextBit[ colour ].xByte ) |= nextBit[ colour ].xBit;
1312 lineEmpty[ colour ][ lineIndex ] = false;
1313 }
1314 INC_BIT( nextBit[ colour ] );
1315 if ( skipPixels )
1316 {
1317 int bitSkip = skipBits;
1318
1319 nextBit[ colour ].xByte += skipBytes;
1320 while ( bitSkip-- )
1321 {
1322 INC_BIT( nextBit[ colour ] );
1323 }
1324 }
1325 }
1326 }
1327 }
1328
1329
1330 /*----------------------------------------------------------------------*
1331 * r e f r e s h B u f f e r ( ) *
1332 *----------------------------------------------------------------------*
1333 Given pointers to the values of the next line to retrieve from GS, and
1334 the next printable line, the GS line buffer, the per colour bit buffers,
1335 the per colour arrays containing the per line `empty'
1336 indicators, and the per pen penData structs, containing the next print
1337 line for each pen, refresh the buffer, and perform initial processing on
1338 the lines read from GS.
1339
1340 When the scan line is for a black-only device, the line bits can be read
1341 directly into the appropriate colour buffer at the appropriate place.
1342
1343 When the scan lines hold colour info, each line must undergo CMYK pro-
1344 cessing to derive the individual arrays of single-colour bits.
1345
1346 Refreshing the buffers involves reading lines into the circular colour
1347 buffers until COLOUR_BUF_LINES have been read, or until the available
1348 lines have been exhausted.
1349
1350 On return, nextLineToPrint must be set to the said line number, or beyond
1351 the end of the page, if no more remain to be printed.
1352 *----------------------------------------------------------------------*/
1353 private void
refreshBuffer(lx5000_device * lx5000dev,int * nextLineToGet,int * nextLineToPrint,byte * lineBuffer,byte * colourBufs[],bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],penData pens[NUM_COLOURS][PENS_PER_COLOUR],bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES])1354 refreshBuffer( lx5000_device *lx5000dev,
1355 int *nextLineToGet, int *nextLineToPrint,
1356 byte *lineBuffer, byte *colourBufs[],
1357 bufBit
1358 colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],
1359 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1360 bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES] )
1361 {
1362 byte *lineBuf;
1363 uchar nextToGet; /* Circular buffer pointer, 0 to ff */
1364 int bufferOffset;
1365 int colour, pen;
1366 int _1stPrintable; /* Across all pens */
1367 int numColours = lx5000dev->color_info.num_components;
1368
1369 /* Establish the next line to print, if it
1370 is already in the buffer. */
1371 _1stPrintable = pens[YELLOW_X][LO_PEN].finalLine;
1372 for ( colour = 0; colour < numColours; colour++ )
1373 {
1374 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1375 if ( pens[ colour ][ pen ].nextPrintLine < _1stPrintable)
1376 _1stPrintable = pens[ colour ][ pen ].nextPrintLine;
1377 }
1378 *nextLineToPrint = _1stPrintable;
1379
1380 nextToGet = (uchar)(*nextLineToGet & COLOUR_BUF_MASK);
1381 /* nextLineToPrint may be set high (i.e. not
1382 known), or may be a known print line. */
1383 while ( ( *nextLineToGet < *nextLineToPrint
1384 || ( *nextLineToGet - *nextLineToPrint ) < COLOUR_BUF_LINES )
1385 && *nextLineToGet < lx5000dev->height )
1386 {
1387 bufferOffset = LINE_PAD_BYTES + ( lx5000dev->penLineLen * nextToGet );
1388
1389 if ( ! lx5000dev->isCMYK )
1390 {
1391 /* For black-only, read the bits directly into
1392 the colour buffer. */
1393 gdev_prn_get_bits( (gx_device_printer *)lx5000dev, *nextLineToGet,
1394 colourBufs[BLACK_X] + bufferOffset, &lineBuf );
1395 /* If necessary, copy the bits into the actual
1396 buffer. */
1397 if ( lineBuf != colourBufs[BLACK_X] + bufferOffset )
1398 memcpy(colourBufs[BLACK_X] + bufferOffset,
1399 lineBuf, lx5000dev->penLineBytes);
1400 /* Check for a printing line */
1401 if ( *(colourBufs[BLACK_X] + bufferOffset) != 0
1402 || memcmp( colourBufs[BLACK_X] + bufferOffset,
1403 colourBufs[BLACK_X] + bufferOffset + 1,
1404 lx5000dev->scanLineBytes - 1 ))
1405 lineEmpty[ BLACK_X ][ nextToGet ] = false;
1406 else
1407 lineEmpty[ BLACK_X ][ nextToGet ] = true;
1408 }
1409 else /* CMYK printing */
1410 {
1411 /* Process a CMYK line from GS */
1412 gdev_prn_get_bits( (gx_device_printer *)lx5000dev,
1413 *nextLineToGet, lineBuffer, &lineBuf );
1414 processCMYKline( lx5000dev, *nextLineToGet, lineBuffer, lineBuf,
1415 colourBufs, colourLines, pens, lineEmpty );
1416 }
1417 for (colour = 0; colour < numColours; colour++ )
1418 {
1419 /* Check for printing line -
1420 N.B. For two-pen colour, this becomes more
1421 complicated. The relationship between the
1422 first print line of the lower and of the
1423 upper pen is determined by odd/even line
1424 numbers, although this is not an essential
1425 relationship. Blank lines at the top of
1426 the lower pen could be skipped, and the
1427 first available line could be printed by
1428 the lower pen. */
1429 if ( ! lineEmpty[colour][nextToGet] )
1430 {
1431 if ( pens[colour][LO_PEN].nextPrintLine > *nextLineToGet )
1432 pens[colour][LO_PEN].nextPrintLine = *nextLineToGet;
1433 if ( *nextLineToPrint > *nextLineToGet )
1434 *nextLineToPrint = *nextLineToGet;
1435 }
1436 }
1437 ++*nextLineToGet;
1438 nextToGet = ( *nextLineToGet & COLOUR_BUF_MASK ); /* N.B. This is safer
1439 than just doing the increment, in case the
1440 buffer length changes. */
1441 }
1442 /* Check that no buffer padding is necessary */
1443 if ( *nextLineToPrint < lx5000dev->height )
1444 {
1445 while ( ( *nextLineToGet - *nextLineToPrint ) < COLOUR_BUF_LINES )
1446 { /* Last refresh fell short of COLOUR_BUF_LINES
1447 because last line of page was reached.
1448 Pad the buffer to COLOUR_BUF_LINES with 0
1449 (no print) bytes. */
1450 for ( colour = 0; colour < numColours; colour++ )
1451 { /* Fill the colour line buffer, incl pad */
1452 memset( colourBufs[colour]
1453 + ( lx5000dev->penLineLen * nextToGet ),
1454 0, lx5000dev->penLineLen );
1455 /* Set empty indicator - note that firstBit
1456 is NOT set here. */
1457 lineEmpty[colour][nextToGet] = true;
1458 }
1459 ++*nextLineToGet;
1460 nextToGet = ( *nextLineToGet & COLOUR_BUF_MASK );
1461 }
1462 }
1463 }
1464
1465 /*----------------------------------------------------------------------*
1466 * c a r t r i d g e M o v e T o ( ) *
1467 *----------------------------------------------------------------------*
1468 Given the array of penBits structures for each pen, containing the
1469 nextPrintLine value for the pen, return the line position to
1470 which the colour cartridge must be moved to print that line with the
1471 TOP nozzle of the required pen.
1472 If the print line for any pen is within the current range of that pen,
1473 a line less than the current colour head position will be returned.
1474 If colour is not defined, return a value off the end of the page.
1475 *----------------------------------------------------------------------*/
1476 private int
cartridgeMoveTo(lx5000_device * lx5000dev,penData pens[NUM_COLOURS][PENS_PER_COLOUR],int _1stColour,int lastColour)1477 cartridgeMoveTo( lx5000_device *lx5000dev,
1478 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1479 int _1stColour, int lastColour )
1480 {
1481 if ( _1stColour != BLACK_X && ! lx5000dev->isCMYK )
1482 /* Send back an off-the-page value */
1483 return pens[CYAN_X][LO_PEN].finalLine;
1484 else
1485 {
1486 int colour, pen, minLine;
1487
1488 minLine = pens[CYAN_X][LO_PEN].finalLine; /* Initialise high */
1489 /* For each pen, calculate a moveto value
1490 which will print the next line with the
1491 first nozzle of that pen.
1492 Return the minimum of these values. */
1493 for ( colour = _1stColour; colour <= lastColour; colour++ )
1494 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1495 if ( ( pens[colour][pen].nextPrintLine
1496 + pens[colour][pen].topToBottomYellow )
1497 < minLine )
1498 minLine =
1499 pens[colour][pen].nextPrintLine
1500 + pens[colour][pen].topToBottomYellow;
1501
1502 return minLine;
1503 }
1504 }
1505 /*----------------------------------------------------------------------*
1506 * s e t C o l o u r C o l u m n E x t e n t ( ) *
1507 *----------------------------------------------------------------------*
1508 Given a colour buffer, a single array of colourBits structures,
1509 1st and last lines, 1st nozzle, and the addresses of
1510 _1stColumn, lastColumn and columnExtent variables, calculate and set
1511 these column variables after stripping leading and trailing white space.
1512 *----------------------------------------------------------------------*/
1513 private void
setColourColumnExtent(lx5000_device * lx5000dev,byte * colourBuf,bool lineEmpty[COLOUR_BUF_LINES],int _1stLine,int _1stNozzle,int lastLine,int * _1stColumn,int * lastColumn,int * columnExtent)1514 setColourColumnExtent( lx5000_device *lx5000dev, byte *colourBuf,
1515 bool lineEmpty[COLOUR_BUF_LINES],
1516 int _1stLine, int _1stNozzle, int lastLine,
1517 int *_1stColumn, int *lastColumn, int *columnExtent )
1518 {
1519 uchar _1stIndex;
1520 int firstPrintByte, lastPrintByte;
1521 int line;
1522
1523 line = _1stLine;
1524 firstPrintByte = lx5000dev->penLineBytes;
1525 lastPrintByte = 0;
1526
1527 for ( ; line <= lastLine; line += lx5000dev->lineIncrement )
1528 { /* For each active line in swipe */
1529 int columnByte;
1530
1531 _1stIndex = line & COLOUR_BUF_MASK;
1532 if ( lineEmpty[ _1stIndex ] )
1533 continue; /* If the line is empty, skip it. */
1534 /* Otherwise, scan from the beginning to any
1535 previously found non-zero byte for the
1536 beginning of the active column extent. */
1537 for ( columnByte = 0; columnByte < firstPrintByte; columnByte++ )
1538 if ( colourBuf[ _1stIndex * lx5000dev->penLineLen
1539 + LINE_PAD_BYTES + columnByte ] )
1540 {
1541 firstPrintByte = columnByte;
1542 break;
1543 }
1544 /* Scan from the end of the line to any pre-
1545 viously found non-zero byte for the end of
1546 the active column extent. */
1547 for ( columnByte = lx5000dev->penLineBytes;
1548 columnByte > lastPrintByte; columnByte-- )
1549 if ( colourBuf[ _1stIndex * lx5000dev->penLineLen
1550 + LINE_PAD_BYTES + columnByte ] )
1551 {
1552 lastPrintByte = columnByte;
1553 break;
1554 }
1555 }
1556 /* If we have no extent, there are no
1557 printable lines for this pen. */
1558 if ( firstPrintByte > lastPrintByte )
1559 {
1560 *_1stColumn = firstPrintByte * 8;
1561 *lastColumn = lastPrintByte * 8;
1562 *columnExtent = 0;
1563 return;
1564 }
1565
1566 *_1stColumn = firstPrintByte * 8;
1567 *lastColumn = lastPrintByte * 8 + 7 + lx5000dev->headSeparation;
1568 *columnExtent = ( *lastColumn - *_1stColumn ) + 1;
1569
1570 }
1571
1572 /*----------------------------------------------------------------------*
1573 * s e t C o l o u r L i n e s ( ) *
1574 *----------------------------------------------------------------------*
1575 Given a single colour/pen buffer, a single array of bufBit structures,
1576 1st and last lines, 1st nozzle, print direction, and
1577 _1stColumn, lastColumn and columnExtent variables, set up the pointers
1578 to the first actual column of each line, taking account of even and odd
1579 nozzle numbers.
1580 *----------------------------------------------------------------------*/
1581 private void
setColourLines(lx5000_device * lx5000dev,byte * colourBuf,bufBit colourLines[COLOUR_BUF_LINES],int _1stLine,int _1stNozzle,int lastLine,int direction,int _1stColumn,int lastColumn)1582 setColourLines( lx5000_device *lx5000dev,
1583 byte *colourBuf, bufBit colourLines[COLOUR_BUF_LINES],
1584 int _1stLine, int _1stNozzle, int lastLine, int direction,
1585 int _1stColumn, int lastColumn )
1586 {
1587 uchar _1stIndex;
1588 int line, nozzle, bit, headSep, headSepBytes, headSepBits;
1589 int firstPrintByte, lastPrintByte, lastPrintBit;
1590 bufBit startPtr;
1591
1592 /* Now initialize the penBits bufBit structures to point to the
1593 beginning and end of the extent for each of the active lines in
1594 this swipe
1595
1596 Adjust the beginning for all EVEN nozzles by moving it to the
1597 left by HeadSeparation bits.
1598 */
1599
1600 headSep = lx5000dev->headSeparation;
1601 if ( lx5000dev->x_pixels_per_inch == 300.0 )
1602 headSep = headSep >> 1; /* Halve the value at 300 dpi */
1603 if ( lx5000dev->x_pixels_per_inch == 1200.0 )
1604 headSep = headSep << 1; /* Double the value at 1200dpi */
1605 headSepBytes = headSep / 8;
1606 headSepBits = headSep % 8;
1607
1608 firstPrintByte = _1stColumn / 8;
1609 lastPrintByte = lastColumn / 8;
1610 lastPrintBit = lastColumn % 8;
1611
1612 if ( direction == RIGHTWARD )
1613 {
1614 /* Set up the ODD columns first */
1615 startPtr.xByte = colourBuf + LINE_PAD_BYTES + firstPrintByte;
1616 startPtr.xBit = BIT_TO_MASK( 0 );
1617 line = _1stLine;
1618 nozzle = _1stNozzle; /* Is 1st nozzle effectively odd? */
1619 if ( ! ( nozzle & 1 ) ) /* Nozzle is even, so increment */
1620 line += lx5000dev->lineIncrement;
1621 for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1622 {
1623 _1stIndex = (uchar)( line & COLOUR_BUF_MASK );
1624 colourLines[_1stIndex].xByte =
1625 startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1626 colourLines[_1stIndex].xBit = startPtr.xBit;
1627 }
1628 /* Set up EVEN columns */
1629 startPtr.xByte -= headSepBytes;
1630 for ( bit = 0; bit < headSepBits; bit++ )
1631 {
1632 DEC_BIT( startPtr );
1633 }
1634 line = _1stLine;
1635 nozzle = _1stNozzle; /* Is 1st nozzle effectively even? */
1636 if ( nozzle & 1 ) /* Nozzle is odd, so increment */
1637 line += lx5000dev->lineIncrement;
1638 for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1639 {
1640 _1stIndex = (uchar)( line & COLOUR_BUF_MASK );
1641 colourLines[_1stIndex].xByte =
1642 startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1643 colourLines[_1stIndex].xBit = startPtr.xBit;
1644 }
1645 }
1646 else /* direction == LEFTWARD */
1647 {
1648 /* Set up the ODD columns first */
1649 startPtr.xByte = colourBuf + LINE_PAD_BYTES + lastPrintByte;
1650 startPtr.xBit = BIT_TO_MASK( lastPrintBit );
1651 line = _1stLine;
1652 nozzle = _1stNozzle; /* Is 1st nozzle effectively odd? */
1653 if ( ! ( nozzle & 1 ) ) /* Nozzle is even, so increment */
1654 line += lx5000dev->lineIncrement;
1655 for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1656 {
1657 _1stIndex = (uchar)( line & COLOUR_BUF_MASK );
1658 colourLines[_1stIndex].xByte =
1659 startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1660 colourLines[_1stIndex].xBit = startPtr.xBit;
1661 }
1662 /* Set up EVEN columns */
1663 startPtr.xByte -= headSepBytes;
1664 for ( bit = 0; bit < headSepBits; bit++ )
1665 {
1666 DEC_BIT( startPtr );
1667 }
1668 line = _1stLine;
1669 nozzle = _1stNozzle; /* Is 1st nozzle effectively even? */
1670 if ( nozzle & 1 ) /* Nozzle is odd, so increment */
1671 line += lx5000dev->lineIncrement;
1672 for ( ; line <= lastLine; line += ( lx5000dev->lineIncrement << 1 ) )
1673 {
1674 _1stIndex = (uchar)( line & COLOUR_BUF_MASK );
1675 colourLines[_1stIndex].xByte =
1676 startPtr.xByte + _1stIndex * lx5000dev->penLineLen;
1677 colourLines[_1stIndex].xBit = startPtr.xBit;
1678 }
1679 }
1680 }
1681
1682 /*----------------------------------------------------------------------*
1683 * p r i n t S w i p e ( ) *
1684 *----------------------------------------------------------------------*
1685 *----------------------------------------------------------------------*/
1686 private void
printSwipe(lx5000_device * lx5000dev,byte * colourBufs[NUM_COLOURS],bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],penData pens[NUM_COLOURS][PENS_PER_COLOUR],bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES],byte * swipeBuf,int * nextLineToPrint,int * nextLineToGet,int direction,int _1stColour,int lastColour,FILE * prn_stream)1687 printSwipe( lx5000_device *lx5000dev, byte *colourBufs[NUM_COLOURS],
1688 bufBit
1689 colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES],
1690 penData pens[NUM_COLOURS][PENS_PER_COLOUR],
1691 bool lineEmpty[NUM_COLOURS][COLOUR_BUF_LINES], byte *swipeBuf,
1692 int *nextLineToPrint, int *nextLineToGet, int direction,
1693 int _1stColour, int lastColour, FILE *prn_stream )
1694 {
1695 /*--------------------------------------------------------------------*
1696 For unidirectional colour swathes, the effective print direction on
1697 a 5000 is reversed. The implication of this is that, once the extent
1698 of the printing columns has been determined, the data for the colour
1699 pens must be fed to the head bit-reversed; i.e., set the bit pointer
1700 to the last column to be printed, and decrement the bit pointer until
1701 all of the columns have been printed.
1702 *--------------------------------------------------------------------*/
1703
1704 static const char swipeHeader[SWIPE_HDR_LEN] = {
1705 SWIPE_LEADER,
1706 0, 0, 0, 0, /* command length */
1707 0, /* direction */
1708 0, /* head speed */
1709 0, 0, /* pen selector */
1710 0, /* nozzle count */
1711 0, /* don't know */
1712 0, 0, /* number of columns */
1713 0, 0, /* 1st column */
1714 0, 0, /* last column */
1715 SWIPE_HDR_END
1716 };
1717
1718 static const int wordsPerPen[NUM_COLOURS][PENS_PER_COLOUR + 1] =
1719 {
1720 { -1,
1721 BLACK_NOZZLES / SWIPE_WORD_BITS,
1722 BLACK_NOZZLES / SWIPE_WORD_BITS / 2
1723 },
1724 { -1,
1725 _1COLOUR_NOZZLES / SWIPE_WORD_BITS,
1726 _1COLOUR_NOZZLES / SWIPE_WORD_BITS / 2
1727 },
1728 { -1,
1729 _1COLOUR_NOZZLES / SWIPE_WORD_BITS,
1730 _1COLOUR_NOZZLES / SWIPE_WORD_BITS / 2
1731 },
1732 { -1,
1733 _1COLOUR_NOZZLES / SWIPE_WORD_BITS,
1734 _1COLOUR_NOZZLES / SWIPE_WORD_BITS / 2
1735 }
1736 };
1737
1738 int _1stNozzle[NUM_COLOURS][PENS_PER_COLOUR];
1739 /* 1st active nozzle for pen */
1740 int lastNozzle[NUM_COLOURS][PENS_PER_COLOUR];
1741 /* Last nozzle of this pen */
1742 int _1stLine[NUM_COLOURS][PENS_PER_COLOUR];
1743 /* Line no. of first print line for pen */
1744 int _1stPenColumn[NUM_COLOURS][PENS_PER_COLOUR];
1745 int lastPenColumn[NUM_COLOURS][PENS_PER_COLOUR];
1746 /* Per-pen values... */
1747 int penExtent[NUM_COLOURS][PENS_PER_COLOUR];
1748 int _1stColumn; /* ...and overall values of... */
1749 int lastColumn;
1750 int columnExtent; /* Column range after */
1751 /* stripping leading and trailing white space*/
1752 int column; /* Loop variable - current column */
1753 int line; /* Loop variables - line corresponding to
1754 current nozzle & temp line variable. */
1755 uchar lineIndex; /* Circular index into pen buffer,
1756 corresponding to current line. */
1757 int swipeCmdLen; /* Length of the swipe command */
1758 int colour, pen;
1759 byte *outp;
1760 int x_dpi = (int)( lx5000dev->x_pixels_per_inch + 0.1 );
1761
1762 /* Initialize worst case values for column
1763 extremities. */
1764 _1stColumn = lx5000dev->penLineBytes * 8
1765 + 7 + lx5000dev->headSeparation;
1766 lastColumn = 0;
1767 /* Set up extents on a per-colour basis. */
1768 for ( colour = _1stColour; colour <= lastColour; colour++ )
1769 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1770 {
1771 _1stLine[colour][pen] = pens[colour][pen].nextPrintLine;
1772 _1stNozzle[colour][pen] = _1stLine[colour][pen]
1773 - pens[colour][pen].topLine;
1774 lastNozzle[colour][pen] = pens[colour][pen].bottomLine
1775 - pens[colour][pen].topLine;
1776
1777 setColourColumnExtent( lx5000dev, colourBufs[colour],
1778 lineEmpty[colour], _1stLine[colour][pen],
1779 _1stNozzle[colour][pen],
1780 pens[colour][pen].bottomLine,
1781 &_1stPenColumn[colour][pen],
1782 &lastPenColumn[colour][pen],
1783 &penExtent[colour][pen] );
1784 /* Get the overall extents for the swipe */
1785 if ( _1stPenColumn[colour][pen] < _1stColumn )
1786 _1stColumn = _1stPenColumn[colour][pen];
1787 if ( lastPenColumn[colour][pen] > lastColumn )
1788 lastColumn = lastPenColumn[colour][pen];
1789 }
1790 /* Set overall extent */
1791 columnExtent = ( lastColumn - _1stColumn ) + 1;
1792
1793 /* Set the column range for each of the colour
1794 pens now that the full extent is known. */
1795 for ( colour = _1stColour; colour <= lastColour; colour++ )
1796 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1797 {
1798 setColourLines( lx5000dev, colourBufs[colour],
1799 colourLines[colour][pen],
1800 _1stLine[colour][pen], _1stNozzle[colour][pen],
1801 pens[colour][pen].bottomLine, direction,
1802 _1stColumn, lastColumn );
1803 }
1804
1805 memcpy( swipeBuf, swipeHeader, SWIPE_HDR_LEN );
1806 outp = swipeBuf + SWIPE_HDR_LEN;
1807 /* For each column of the output, build two
1808 stripes. One uses the standard directory
1809 scheme, and the other uses the repeat
1810 compression scheme. Output the more
1811 compact result. */
1812 for ( column = _1stColumn; column <= lastColumn; column++ )
1813 {
1814 ushort dataword; /* Loop transient - contents of swipe data
1815 word currently under construction. */
1816 ushort lastWord; /* Last data word constructed for repeat
1817 compression directory method. */
1818 int nozzle; /* Loop variable - current nozzle */
1819 /* The arrays of the two sets of data words
1820 generated by each of the swipe construction
1821 methods for a single swipe. Does not
1822 include the 16 bit directory word. */
1823 int wordCount1; /* The count of words in the column arrays, */
1824 int wordCount2; /* below. */
1825 ushort column1[BLK_SWIPE_WORDS];
1826 ushort column2[BLK_SWIPE_WORDS];
1827 int columnWord; /* Current word within column. */
1828 bufBit *lineBit; /* Loop transient - current scan line bit */
1829 ushort wordBit; /* Current bit within swipe word - incremented
1830 by right shifts. */
1831 ushort directoryBit; /* Current bit within directory word. It
1832 indicates the currently active set of 16
1833 nozzles. Incremented by left shifts. */
1834 ushort directory1; /* The directories for the two methods. Each */
1835 ushort directory2; /* bit controls one following 16bit word. */
1836
1837 if ( _1stColour == BLACK_X )
1838 {
1839 directory1 = (ushort)(BLK_DIRECTORY_MASK); /* empty */
1840 directory2 = (ushort)(BLK_DIRECTORY_MASK); /* empty */
1841 }
1842 else
1843 {
1844 directory1 = (ushort)(COLOUR_DIRECTORY_MASK); /* empty */
1845 directory2 = (ushort)(COLOUR_DIRECTORY_MASK); /* empty */
1846 }
1847 directory1 |= DIRECTORY_TYPE_BIT; /* Normal directory */
1848 directory2 &= ~DIRECTORY_TYPE_BIT; /* Repeat compression
1849 directory */
1850 /* LSBit of directory refers to 1st following
1851 word */
1852 directoryBit = 1;
1853 lastWord = 0;
1854 wordCount1 = 0;
1855 wordCount2 = 0;
1856 /* Note that the order of the pens in the
1857 datawords (top nozzle to bottom) is
1858 CMY, the reverse of the numbering */
1859 /*------------------------------------------
1860 N.B. What are the implications of this for
1861 pen processing within a colour?
1862 -----------------------------------------*/
1863 for ( colour = lastColour; colour >= _1stColour; colour-- )
1864 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1865 {
1866 dataword = 0;
1867 nozzle = 0;
1868 line = _1stLine[colour][pen];
1869 /* If there are any non-printing nozzles at
1870 the top of the printhead, set up the entries
1871 for them here. */
1872 while ( ( ( _1stNozzle[colour][pen] - nozzle )
1873 >= SWIPE_WORD_BITS )
1874 && ( nozzle <= lastNozzle[colour][pen] ) )
1875 {
1876 if ( lastWord != 0 )
1877 {
1878 directory2 &= ~directoryBit;
1879 column2[ wordCount2++ ] = dataword;
1880 lastWord = dataword;
1881 }
1882 nozzle += SWIPE_WORD_BITS;
1883 directoryBit <<= 1;
1884 }
1885 /* Shift over any remaining empty bits in
1886 the current column word. */
1887 wordBit = ( 1 << ( SWIPE_WORD_BITS - 1 ));
1888 wordBit >>= ( _1stNozzle[colour][pen] - nozzle );
1889
1890 for ( columnWord = _1stNozzle[colour][pen] / SWIPE_WORD_BITS;
1891 columnWord <
1892 wordsPerPen[colour][lx5000dev->pensPerColour];
1893 columnWord++ )
1894 {
1895 while ( wordBit )
1896 {
1897 lineIndex = (uchar)( line & COLOUR_BUF_MASK );
1898 /* Get the bit from the next line */
1899 lineBit = &colourLines[colour][pen][lineIndex];
1900 if ( *(lineBit->xByte) & lineBit->xBit )
1901 dataword |= wordBit;
1902 wordBit >>= 1;
1903 if ( direction == LEFTWARD )
1904 {
1905 DEC_BIT( *lineBit );
1906 }
1907 else
1908 {
1909 INC_BIT( *lineBit );
1910 }
1911 line += lx5000dev->lineIncrement;
1912 }
1913 /* Do we have a non-null dataword? */
1914 if ( dataword )/* For normal compression, every nonempty */
1915 { /* dataword is noted and sent to printer */
1916 directory1 &= ~directoryBit;
1917 column1[ wordCount1++ ] = dataword;
1918 }
1919 if ( dataword != lastWord ) /* For repeat compression, */
1920 { /* only datawords which change are recorded */
1921 directory2 &= ~directoryBit;
1922 column2[ wordCount2++ ] = dataword;
1923 lastWord = dataword;
1924 }
1925 /* Look at next set of nozzles */
1926 directoryBit <<= 1;
1927 dataword = 0;
1928 /* Reset dataword bit mask to 1st bit */
1929 wordBit = ( 1 << ( SWIPE_WORD_BITS - 1 ));
1930 }
1931 }
1932 /* Output the smaller array of column words -
1933 is it normal or repeat compressed? */
1934 if ( wordCount1 < wordCount2 )
1935 { /* A normal directory + data */
1936 int i;
1937
1938 *outp++ = directory1 >> 8;
1939 *outp++ = directory1 & 0xff;
1940 for ( i = 0; i < wordCount1; i++ )
1941 {
1942 *outp++ = column1[ i ] >> 8;
1943 *outp++ = column1[ i ] & 0xff;
1944 }
1945 }
1946 else
1947 { /* A repeat compression directory + data */
1948 int i;
1949
1950 *outp++ = directory2 >> 8;
1951 *outp++ = directory2 & 0xff;
1952 for ( i = 0; i < wordCount2; i++ )
1953 {
1954 *outp++ = column2[ i ] >> 8;
1955 *outp++ = column2[ i ] & 0xff;
1956 }
1957 }
1958 }
1959 /* Set up the header and output the swipe */
1960 swipeCmdLen = outp - swipeBuf;
1961 {
1962 int ps1, ps2, direction, density, nozzles;
1963
1964 direction = UNIDIRECTIONAL;
1965 if ( x_dpi == 300 )
1966 {
1967 density = _300X;
1968 }
1969 else
1970 {
1971 if ( x_dpi == 1200 )
1972 density = _1200X;
1973 else
1974 density = _600X;
1975 }
1976
1977 if ( _1stColour == BLACK_X )
1978 {
1979 ps1 = BLACK0;
1980 ps2 = BLACK1;
1981 nozzles = _208NOZZLES;
1982 }
1983 else
1984 {
1985 ps1 = COLOUR0;
1986 ps2 = COLOUR1;
1987 nozzles = _192NOZZLES;
1988 }
1989 FILL_SWIPE_HEADER( swipeBuf, swipeCmdLen, direction, density,
1990 ps1, ps2, nozzles, UNKNOWN1VAL,
1991 columnExtent, _1stColumn, lastColumn );
1992 }
1993 fwrite( swipeBuf,1, outp - swipeBuf, prn_stream );
1994
1995 for ( colour = _1stColour; colour <= lastColour; colour++ )
1996 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
1997 {
1998 /* Scan the buffer for the next print line,
1999 if present. If not, set sentinel value. */
2000 if ( pens[colour][pen].nextPrintLine
2001 <= pens[colour][pen].bottomLine
2002 || pens[colour][pen].nextPrintLine >= *nextLineToGet )
2003 {
2004 pens[colour][pen].nextPrintLine =
2005 pens[YELLOW_X][LO_PEN].finalLine;
2006 line = pens[colour][pen].bottomLine + 1;
2007 while ( line < *nextLineToGet )
2008 {
2009 lineIndex = (uchar)( line & COLOUR_BUF_MASK );
2010 if ( ! lineEmpty[colour][ lineIndex ] )
2011 {
2012 pens[colour][pen].nextPrintLine = line;
2013 break;
2014 }
2015 line += lx5000dev->lineIncrement;
2016 }
2017 }
2018 }
2019 }
2020
2021 /*----------------------------------------------------------------------*
2022 * l x 5 0 0 0 _ p r i n t _ p a g e ( ) *
2023 *----------------------------------------------------------------------*
2024 Send the page to the printer.
2025 *----------------------------------------------------------------------*/
2026 private int
lx5000_print_page(gx_device_printer * pdev,FILE * prn_stream)2027 lx5000_print_page( gx_device_printer *pdev, FILE *prn_stream )
2028 {
2029 /*
2030 Data structures for the buffer:
2031
2032 ------------------------------------------------------------------*
2033 C O L O U R B U F F E R S
2034 ------------------------------------------------------------------*
2035 The colour buffers contain the individual colour bits that will
2036 actually be passed to the print heads; therefore, there is one bit
2037 per printable element. So far, the correspondence between the
2038 gx_color_index elements in the scan line and the individual print
2039 bits is 1-to-1.
2040
2041 For the colour driver, the colour buffers will be:
2042 Cbuffer, Mbuffer, Ybuffer and Kbuffer
2043 while for the black driver, only Kbuffer is used.
2044 (See BUFFER HANDLING MACROS.)
2045
2046 ------------------------------------------------------------------*
2047 D E T E R M I N I N G B U F F E R S I Z E
2048 ------------------------------------------------------------------*
2049 The colour buffers are circular buffers: in order to implement this
2050 characteristic, the size of the buffer must be 2^n. The buffers may
2051 then be indexed by the scan line number, masked by 2^n - 1.
2052
2053 The buffer must be able to accommodate the maximum range of scan
2054 lines that might be affected by a single swipe command. For colour
2055 pens this is 240 ( 3 x 64 pens + 2 x 24 inter-pen gaps). For the
2056 black pen, this is 208. Therefore, the minimum buffer size is 256.
2057 In fact, this is probably also the optimal buffer size, as there seems
2058 to be no advantage in buffering twice the number of scan line required
2059 to hold any individual swipe.
2060
2061 ------------------------------------------------------------------*
2062 S T R U C T U R E O F T H E C O L O U R B U F F E R S
2063 ------------------------------------------------------------------*
2064 The colour buffers hold the data for individual colour printheads,
2065 extracted from the original data provided as scan lines. When the
2066 data for each colour is extracted from the scan line, it is placed
2067 into a line of the colour buffer corresponding to the scan line.
2068
2069 Within each line of the colour buffer, the data is structured like so:
2070 +-------+------------------- ~ ---------------------+-------+
2071 | Pad | Scan line data bits for one colour | Pad |
2072 | bytes | | bytes |
2073 +-------+-------------------------------------------+-------+
2074
2075 When the scan line data is first processed, the colour data is copied
2076 into the colour buffer in the position indicated above. This line of
2077 data is padded on both ends. The size of the pad is sufficient to
2078 account for the number of bits of head separation between the EVEN
2079 and ODD rows of nozzles in each print head; by default 16.
2080
2081 The individual lines are accessed through an array of colourLines struct-
2082 ures. This is defined in the TYPEDEFS & EXTERNAL STORAGE secion above.
2083
2084 The colourLines structure contains a byte pointer which points to one of
2085 the bytes of an individual colour buffer line, and an unsigned char
2086 which is a single bit mask isolating one bit of the byte pointed to by
2087 the other element.
2088 typedef struct bufBit_s {
2089 byte * xByte;
2090 uchar xBit;
2091 } bufBit;
2092
2093 The colourLines structure holds one instance of a bufBit; it points to
2094 the first bit of the scan line. In general, the bit pointers for the
2095 first bit of the EVEN columns will point to the beginning of the
2096 extracted scan line data. For the ODD columns, the first bit
2097 will point into the leading PAD bytes by 16 bits before the start of
2098 the actual scan line data.
2099
2100 In this way, all of the complications of managing the separation
2101 between the EVEN and ODD columns on the heads is contained in the
2102 set-up procedures for the pointers in the scanLines array. If it is
2103 required to reverse the adjustments of EVEN and ODD columns (for bi-
2104 directional printing, for example) this is achieved by adjusting the
2105 firstBit entries in this array.
2106
2107 That, at any rate, is the theory. It seemed like a good idea at the
2108 time.
2109
2110 */
2111
2112 static const char init_string[] = {
2113 0xa5, 0, 6, 0x40, 3, 3, 0xc0, 0x0f, 0x0f,
2114 0xa5, 0, 3, 0x40, 4, 5,
2115 0xa5, 0, 3, 0x40, 4, 6,
2116 0xa5, 0, 3, 0x40, 4, 7,
2117 0xa5, 0, 3, 0x40, 4, 8,
2118 0xa5, 0, 4, 0x40, 0xe0, 0xb, 3,
2119 0xa5, 0, 11, 0x40, 0xe0, 0x41, 0, 0, 0, 0, 0, 0, 0, A5_11_5000,
2120 0xa5, 0, 6, 0x40, 5, 0, 0, 0x80, 0,
2121 0x1b, '*', 7, 0x73, 0x30,
2122 0x1b, '*', 'm', 0, 0x14, 3, 0x84, 2, 0, 1, 0xf4,
2123 0x1b, '*', 7, 0x63,
2124 0x1b, '*', 'm', 0, 0x42, 0, 0,
2125 0xa5, 0, 5, 0x40, 0xe0, 0x80, 8, 7
2126 };
2127
2128 byte *lineBuffer;
2129 byte *swipeBuffer;
2130 byte *colourBufs[ NUM_COLOURS ];
2131 bufBit colourLines[NUM_COLOURS][PENS_PER_COLOUR][COLOUR_BUF_LINES];
2132 bool lineEmpty[ NUM_COLOURS ][ COLOUR_BUF_LINES ];
2133 penData pens[ NUM_COLOURS ][ PENS_PER_COLOUR ];
2134 /* nextLineToPrint is the top unprinted line
2135 in the buffers. It is adjusted as lines
2136 are processed and printed. Its sentinel
2137 value is pens[YELLOW_X][LO_PEN].finalLine.
2138 When any line
2139 which is not blank is read from GS &
2140 processed, nextLineToPrint will be set to
2141 this line if it is less than the current
2142 value.
2143
2144 nextLineToGet is the next scanline to read
2145 from GS. */
2146 int nextLineToPrint;
2147 int nextLineToGet = 0;
2148 /* The current bottom line position of
2149 the colour cartridge. */
2150 int bottomYellowLine;
2151 int retval;
2152
2153 lx5000_device *lx5000dev = (lx5000_device *)pdev;
2154
2155 nextLineToPrint = pens[YELLOW_X][LO_PEN].finalLine;
2156 bottomYellowLine = INITIAL_YELLOW_BOTTOM_LINE;
2157 /* Allocate the buffer storage */
2158 if ( ( retval = getColourBufs( lx5000dev, &lineBuffer, colourBufs,
2159 &swipeBuffer, ALLOCATE ) ))
2160 return retval;
2161
2162 initPenConstants( lx5000dev, pens );
2163 /* Initialize the lineEmpty[] and pens[] arrays -
2164 should happen during parameter setup process */
2165 {
2166 int colour, pen, line;
2167
2168 for ( colour = 0;
2169 colour < lx5000dev->color_info.num_components;
2170 colour++ )
2171 {
2172 for ( pen = 0; pen < lx5000dev->pensPerColour; pen++ )
2173 {
2174 pens[colour][pen].nextPrintLine =
2175 pens[YELLOW_X][LO_PEN].finalLine;
2176
2177 pens[colour][pen].bottomLine =
2178 pens[colour][pen].initialBottomLine;
2179 pens[colour][pen].topLine =
2180 bottomYellowLine
2181 - pens[colour][pen].topToBottomYellow;
2182 }
2183 for ( line = 0; line < COLOUR_BUF_LINES; line++ )
2184 /* Force the zeroing of the line first time through */
2185 lineEmpty[colour][line] = false;
2186 }
2187 }
2188
2189 /* Initialize the printer and reset margins. */
2190 pageInit( (uchar)lx5000dev->alignA, (uchar)lx5000dev->alignB, prn_stream );
2191 fwrite( init_string, 1, sizeof( init_string ), prn_stream );
2192
2193 /*--------------------------------------------------------------*
2194 Assume that COLOUR_BUF_LINES of data are available, starting with
2195 nextLineToPrint. Work out which cartridge will be doing the
2196 printing, and how far it will have to move.
2197
2198 Something is available to be printed. This may (should?) involve
2199 initial paper movement to line up the appropriate pen. Deciding
2200 on when to move the paper and by how much is tricky. One aim is
2201 to minimize paper movements.
2202
2203 Check for black vs colour printing first. If the required
2204 movement for any of the colour pens is less than the required
2205 movement for the black pen, print a colour swathe, adjust all of
2206 the colour buffer values, and the nextLineToPrint value if
2207 necessary.
2208
2209 Then refreshBuffer() and take another look. Sooner or later,
2210 the next required movement of the colour cartridge will exceed
2211 the movement required of the black cartridge. Print a black
2212 swathe. Whether to move the black cartridge for this print is
2213 determined by checking on the subsequent colour cartridge
2214 movement.
2215
2216 If the difference between the required movement for the black
2217 and the required movement for the colour is less than or equal
2218 to one colour pen depth, do not move the pen before printing the
2219 black swathe.
2220
2221 Adjust black buffer values, including nextLineToPrint, which will
2222 (almost?) certainly change after a black print. refreshBuffer()
2223 and try again.
2224
2225 A note on 192 vs 208 black swathes. I can see the reasons for
2226 using the 192 swathes. When printing solid blocks with some of
2227 each colour and black on each scan line, use of 192 nozzles
2228 obviates the need for any black-related head movement. A black
2229 swathe can be printed on every third movement of the heads, and,
2230 in the circumstances sketched above, will use all 192 nozzles.
2231
2232 Obviously, the same simple algorithm can be used when the colours
2233 are less densely packed. The Alignment B value, coded into the
2234 header of every swipe command, automatically adjusts the first
2235 pen of the set of 192 within a range of 0-15, so that the 192
2236 nozzles are symmetrically arranged with respect to the colour
2237 pens. The complication is that the EVEN/ODD status of the
2238 nozzles in the 208 set is unaffected, even though the numbering
2239 may change.
2240
2241 It originally seemed to me that it was completely unnecessary
2242 to use the 192 nozzle set. The alignment value was needed to
2243 get the positioning right, but for all other purposes, the
2244 208 set could be used, and adjustments made on the fly.
2245 However, I when considering the printing of pseudo 1200Y
2246 pages, which involves the use of half-height pseudo-pens, it
2247 became clear that the calculation of the half-height of a
2248 pens would be greatly simplified by the use of 192 nozzles.
2249 This would leave the height of a pseudo-pen at an integral
2250 number of 16-bit datawords.
2251
2252 As a result, I will use 192 nozzles only when printing at
2253 Nx1200Ydpi.
2254
2255 *--------------------------------------------------------------*/
2256 refreshBuffer( lx5000dev, &nextLineToGet, &nextLineToPrint,
2257 lineBuffer, colourBufs, colourLines, pens, lineEmpty );
2258 while ( nextLineToPrint < pdev->height )
2259 {
2260 int blackDirection = RIGHTWARD;
2261 int colourDirection = LEFTWARD;
2262 /* Target of next move of colour cartridge */
2263 int nextColourLine;
2264 int nextBlack208Line = cartridgeMoveTo( lx5000dev, pens,
2265 BLACK_X,
2266 BLACK_X );
2267
2268 /* In Black-only mode, cartridgeMoveTo
2269 will return an off-page value for the
2270 colour pens. */
2271 nextColourLine = cartridgeMoveTo( lx5000dev, pens,
2272 _1ST_CMY_COLOUR,
2273 LAST_CMY_COLOUR );
2274 if ( lx5000dev->isCMYK && nextColourLine <= nextBlack208Line )
2275 { /* Move the head & print a 3-colour swathe */
2276 feedPaper( lx5000dev, nextColourLine, &bottomYellowLine, pens,
2277 prn_stream );
2278 printSwipe( lx5000dev, colourBufs, colourLines, pens,
2279 lineEmpty, swipeBuffer,
2280 &nextLineToPrint, &nextLineToGet, colourDirection,
2281 _1ST_CMY_COLOUR, LAST_CMY_COLOUR,
2282 prn_stream );
2283 }
2284 else
2285 {
2286 feedPaper( lx5000dev, nextBlack208Line, &bottomYellowLine,
2287 pens, prn_stream );
2288 printSwipe( lx5000dev, colourBufs, colourLines, pens,
2289 lineEmpty, swipeBuffer,
2290 &nextLineToPrint, &nextLineToGet, blackDirection,
2291 BLACK_X, BLACK_X,
2292 prn_stream );
2293 }
2294 refreshBuffer( lx5000dev, &nextLineToGet, &nextLineToPrint,
2295 lineBuffer, colourBufs, colourLines, pens, lineEmpty );
2296 } /* ends the loop for swipes of the print head.*/
2297
2298 /* Eject the page, reinitialize the printer */
2299 pageEnd( prn_stream );
2300 fflush( prn_stream );
2301 getColourBufs( lx5000dev, &lineBuffer, colourBufs, &swipeBuffer,
2302 DEALLOCATE );
2303 if ( lx5000dev->dryTime )
2304 sleep( lx5000dev->dryTime );
2305
2306 return 0;
2307 }
2308
2309 /*
2310 * There are a number of parameters which can differ between ink cartridges.
2311 * The Windows driver asks you to recalibrate every time you load a new
2312 * cartridge.
2313 *
2314 * [The Lexmark 5700 black
2315 * cartridge has two columns of dots, separated by about 16 pixels.
2316 * This `head separation' distance can vary between cartridges, so
2317 * we provide a parameter to set it. In my small experience I've not
2318 * set the corresponding parameter in windows to anything greater than 17
2319 * or smaller than 15, but it would seem that it can vary from 1 to 32,
2320 * based on the calibration choices offered.
2321 * Stephen Taylor's comment on the 5700 ]
2322 *
2323 * N.B. The above discussion relates to the 5700. On the 5000, in the
2324 * Windows driver at any rate, there is no adjustment for the pixel
2325 * distance between the rows of jets on the one print head.
2326 *
2327 * There are, however, two values which are always encoded into the initial
2328 * escape sequence that the Windows driver sends to the printer for each
2329 * new page: alignA the horizontal alignment between the colour and the
2330 * black pens, and alignB, the vertical alignment between the same pens.
2331 *
2332 * AlignC is a black-only alignment, which seems to have something to do
2333 * with bi-directional alignment.
2334 *
2335 * AlignD is a colour-only alignment, corresponding to AlignC.
2336 *
2337 * [As I understand the rules laid out in gsparams.h,
2338 * lx5000_get_params is supposed to return the current values of parameters
2339 * and lx5000_put_params is supposed to set up values in the lx5000_device
2340 * structure which can be used by the lx5000_print_page routine.
2341 * I've copied my routines from gdevcdj.c
2342 * Stephen Taylor]
2343 *
2344 * DryingTime is a delay to allow page drying before a new page is fed
2345 * through.
2346 *
2347 * CMYK is a boolean parameter which specifies colour capability. Set
2348 * -dCMYK=false for black-only printing.
2349 *
2350 * See lx5000_put_params() for the legal ranges of values for these parameters.
2351 *
2352 */
2353
2354 /*----------------------------------------------------------------------*
2355 * l x 5 0 0 0 b _ g e t _ p a r a m s ( ) *
2356 *----------------------------------------------------------------------*/
2357 private int
lx5000_get_params(gx_device * pdev,gs_param_list * plist)2358 lx5000_get_params( gx_device *pdev, gs_param_list *plist )
2359 /*----------------------------------------------------------------------*/
2360 {
2361 lx5000_device *lx5000dev = (lx5000_device *)pdev;
2362 int code = gdev_prn_get_params( pdev, plist );
2363
2364 if ( code < 0 ||
2365 ( code =
2366 param_write_int( plist, "HeadSeparation",
2367 &lx5000dev->headSeparation )) < 0 ||
2368 ( code = param_write_int(plist, "AlignA", &lx5000dev->alignA)) < 0 ||
2369 ( code = param_write_int(plist, "AlignB", &lx5000dev->alignB)) < 0 ||
2370 ( code = param_write_bool( plist, "CMYK", &lx5000dev->isCMYK )) < 0 ||
2371 ( code = param_write_bool( plist,
2372 "DryingTime", &lx5000dev->dryTime )) < 0
2373 )
2374 return code;
2375
2376 return code;
2377 }
2378
2379 /*----------------------------------------------------------------------*
2380 * l x 5 0 0 0 b _ p u t _ p a r a m _ i n t ( ) *
2381 *----------------------------------------------------------------------*/
2382 private int
lx5000_put_param_int(gs_param_list * plist,gs_param_name pname,int * pvalue,int minval,int maxval,int ecode)2383 lx5000_put_param_int(
2384 gs_param_list *plist, gs_param_name pname,
2385 int *pvalue, int minval, int maxval, int ecode
2386 )
2387 /*----------------------------------------------------------------------*/
2388 {
2389 int code, value;
2390
2391 switch ( code = param_read_int( plist, pname, &value ) )
2392 {
2393 default:
2394 return code;
2395 case 0:
2396 if ( value < minval || value > maxval )
2397 {
2398 code =
2399 param_signal_error( plist, pname, gs_error_rangecheck );
2400 ecode = ( code < 0 ? code : ecode );
2401 }
2402 else
2403 *pvalue = value;
2404 case 1:
2405 return ecode;
2406 }
2407 }
2408
2409 /*----------------------------------------------------------------------*
2410 * l x 5 0 0 0 b _ p u t _ p a r a m _ b o o l ( ) *
2411 *----------------------------------------------------------------------*/
2412 private int
lx5000_put_param_bool(gs_param_list * plist,gs_param_name pname,bool * pvalue,int ecode)2413 lx5000_put_param_bool(
2414 gs_param_list *plist, gs_param_name pname,
2415 bool *pvalue, int ecode
2416 )
2417 /*----------------------------------------------------------------------*/
2418 {
2419 int code;
2420
2421 switch ( code = param_read_bool( plist, pname, pvalue ) )
2422 {
2423 default:
2424 ecode = code;
2425 param_signal_error(plist, pname, ecode);
2426 return code;
2427 case 1:
2428 case 0:
2429 return ecode;
2430 }
2431 }
2432
2433 /*----------------------------------------------------------------------*
2434 * l x 5 0 0 0 b _ p u t _ p a r a m s ( ) *
2435 *----------------------------------------------------------------------*/
2436 private int
lx5000_put_params(gx_device * pdev,gs_param_list * plist)2437 lx5000_put_params( gx_device *pdev, gs_param_list *plist )
2438 /*----------------------------------------------------------------------*/
2439 /* put_params is supposed to check all the parameters before setting any. */
2440 /*----------------------------------------------------------------------*/
2441 {
2442 lx5000_device *lx5000dev = (lx5000_device *)pdev;
2443
2444 int ecode, code = 0;
2445 int headSeparation = lx5000dev->headSeparation;
2446 int alignA = lx5000dev->alignA;
2447 int alignB = lx5000dev->alignB;
2448 int dryTime = lx5000dev->dryTime;
2449 int bitsPerPixel = lx5000dev->isCMYK ? 4 : 1;
2450 int oldBPP = bitsPerPixel;
2451 bool isCMYK = lx5000dev->isCMYK;
2452 bool isCMYK_old = isCMYK;
2453
2454 code = lx5000_put_param_int( plist, "HeadSeparation", &headSeparation,
2455 8, 24, code ); /* 8 - 24 columns */
2456
2457 code = lx5000_put_param_int( plist, "AlignA", &alignA, 0, 30, code );
2458 /* 0 - 30 columns */
2459
2460 code = lx5000_put_param_int( plist, "AlignB", &alignB, 0, 15, code );
2461 /* 0 -15 nozzles */
2462
2463 code = lx5000_put_param_int( plist, "DryingTime", &dryTime, 0, 60, code );
2464 /* 0 -60 seconds */
2465
2466 code = lx5000_put_param_int
2467 ( plist, "BitsPerPixel", &bitsPerPixel, 1, 4, code );
2468 /* Black cartridge only */
2469
2470 code = lx5000_put_param_bool( plist, "CMYK", &isCMYK, code );
2471 /* Black cartridge only */
2472
2473 /* Take precautions against input errors */
2474 if ( bitsPerPixel != 1 ) { bitsPerPixel = 4; }
2475
2476 if ( isCMYK != isCMYK_old || bitsPerPixel != oldBPP )
2477 {
2478 bool isCMYK_new;
2479 /* What has changed? Assume that initial values were consistent,
2480 and set isCMYK to a value consistent with the changed args
2481 If both have changed, give precedence to isCMYK
2482 */
2483 if ( bitsPerPixel != oldBPP )
2484 {
2485 if ( bitsPerPixel == 1 )
2486 { isCMYK_new = false; }
2487 else
2488 { isCMYK_new = true; };
2489 }
2490 if ( isCMYK != isCMYK_old )
2491 { isCMYK_new = isCMYK; }
2492
2493 isCMYK = isCMYK_new;
2494 bitsPerPixel = isCMYK ? 4 : 1;
2495
2496 if ( isCMYK )
2497 {
2498 lx5000dev->color_info = color_info_cmy;
2499 dev_proc(pdev, map_cmyk_color) = lx5000_map_cmyk_color;
2500 dev_proc(pdev, map_rgb_color) = NULL;
2501 dev_proc(pdev, map_color_rgb) = lx5000_map_color_rgb;
2502 }
2503 else
2504 {
2505 lx5000dev->color_info = color_info_blk;
2506 dev_proc(pdev, map_cmyk_color) = NULL;
2507 dev_proc(pdev, map_rgb_color) = gdev_prn_map_rgb_color;
2508 dev_proc(pdev, map_color_rgb) = gdev_prn_map_color_rgb;
2509 }
2510 if ( pdev->is_open )
2511 gs_closedevice(pdev);
2512 }
2513
2514 /* call super class put_params */
2515 ecode = gdev_prn_put_params( pdev, plist );
2516
2517 if ( ecode < 0 || code < 0 )
2518 {
2519 if ( isCMYK != isCMYK_old )
2520 {
2521 if ( ! isCMYK )
2522 {
2523 lx5000dev->color_info = color_info_cmy;
2524 dev_proc(pdev, map_cmyk_color) = lx5000_map_cmyk_color;
2525 dev_proc(pdev, map_rgb_color) = NULL;
2526 dev_proc(pdev, map_color_rgb) = lx5000_map_color_rgb;
2527 }
2528 else
2529 {
2530 lx5000dev->color_info = color_info_blk;
2531 dev_proc(pdev, map_cmyk_color) = NULL;
2532 dev_proc(pdev, map_rgb_color) = gdev_prn_map_rgb_color;
2533 dev_proc(pdev, map_color_rgb) = gdev_prn_map_color_rgb;
2534 }
2535 if ( pdev->is_open )
2536 gs_closedevice(pdev);
2537 }
2538 return ecode < 0 ? ecode : code;
2539 }
2540
2541 /* looks like everything okay; */
2542 /* go ahead and set parameters */
2543 lx5000dev->headSeparation = headSeparation;
2544 lx5000dev->alignA = alignA;
2545 lx5000dev->alignB = alignB;
2546 lx5000dev->dryTime = dryTime;
2547 lx5000dev->isCMYK = isCMYK;
2548 /* N.B. I am only setting these values here -
2549 should they also be set as part of the "two
2550 phase commit" of parameter changes? My
2551 code is the only place these things are
2552 accessed. */
2553 if ( lx5000dev->y_pixels_per_inch == MAX_LX5000_Y )
2554 {
2555 lx5000dev->pensPerColour = 2;
2556 lx5000dev->lineIncrement = 2;
2557 }
2558 else
2559 {
2560 lx5000dev->pensPerColour = 1;
2561 lx5000dev->lineIncrement = 1;
2562 }
2563 if ( code == 1 ) return ecode;
2564 return 0;
2565 }
2566
2567
2568 /*----------------------------------------------------------------------*
2569 * The following colour handling procedures are lifted from gdevbit.c
2570 *----------------------------------------------------------------------*/
2571 /* Map color to RGB. This has 3 separate cases, but since it is rarely */
2572 /* used, we do a case test rather than providing 3 separate routines. */
2573 private int
lx5000_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value rgb[3])2574 lx5000_map_color_rgb(gx_device * dev, gx_color_index color,
2575 gx_color_value rgb[3])
2576 {
2577 int depth = dev->color_info.depth;
2578 int ncomp = dev->color_info.num_components;
2579 int bpc = depth / ncomp;
2580 uint mask = (1 << bpc) - 1;
2581
2582 #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
2583
2584 /* Map CMYK back to RGB. */
2585
2586 gx_color_index cshift = color;
2587 uint c, m, y, k;
2588
2589 k = cshift & mask;
2590 cshift >>= bpc;
2591 y = cshift & mask;
2592 cshift >>= bpc;
2593 m = cshift & mask;
2594 c = cshift >> bpc;
2595 /* We use our improved conversion rule.... */
2596 rgb[0] = cvalue((mask - c) * (mask - k) / mask);
2597 rgb[1] = cvalue((mask - m) * (mask - k) / mask);
2598 rgb[2] = cvalue((mask - y) * (mask - k) / mask);
2599
2600 return 0;
2601 #undef cvalue
2602 }
2603
2604 /* Map CMYK to color. */
2605 private gx_color_index
lx5000_map_cmyk_color(gx_device * dev,gx_color_value cyan,gx_color_value magenta,gx_color_value yellow,gx_color_value black)2606 lx5000_map_cmyk_color(gx_device * dev, gx_color_value cyan,
2607 gx_color_value magenta, gx_color_value yellow, gx_color_value black)
2608 {
2609 int bpc = dev->color_info.depth / 4;
2610 int drop = sizeof(gx_color_value) * 8 - bpc;
2611 gx_color_index color =
2612 ((((((cyan >> drop) << bpc) +
2613 (magenta >> drop)) << bpc) +
2614 (yellow >> drop)) << bpc) +
2615 (black >> drop);
2616
2617 return (color == gx_no_color_index ? color ^ 1 : color);
2618 }
2619
2620 /*=============== Clean up my #define's =================*/
2621 #undef A5_11_5000
2622 #undef A5_11_5700
2623 #undef ALIGN_A_DEF
2624 #undef ALIGN_A_OFFSET
2625 #undef ALIGN_B_DEF
2626 #undef ALIGN_B_OFFSET
2627 #undef HEADSEP_DEF
2628 #undef DRY_TIME_DEF
2629 #undef LX_UNI
2630 #undef MIN_LX5000_X
2631 #undef MAX_LX5000_X
2632 #undef DEF_LX5000_X
2633 #undef MIN_LX5000_Y
2634 #undef MAX_LX5000_Y
2635 #undef DEF_LX5000_Y
2636 #undef LX5000_XDPI
2637 #undef LX5000_YDPI
2638 #undef FEED_FACTOR
2639 #undef LX5000_XOFFSET_TO_0_0_XDPI
2640 #undef LX5000_YOFFSET_TO_0_0_YDPI
2641 #undef LX5000_XOFFSET_TO_0_0
2642 #undef LX5000_YOFFSET_TO_0_0
2643 #undef LX5000_LEFT_HWMARGIN_INS
2644 #undef LX5000_BOTTOM_HWMARGIN_INS
2645 #undef LX5000_RIGHT_HWMARGIN_INS
2646 #undef LX5000_TOP_HWMARGIN_INS
2647 #undef LINE_PAD_BYTES
2648 #undef RIGHTWARD
2649 #undef LEFTWARD
2650 #undef SWIPE_WORD_BITS
2651 #undef BLACK_NOZZLES
2652 #undef _1COLOUR_NOZZLES
2653 #undef BLK_COLOUR_NOZZLES
2654 #undef BLK_SWIPE_WORDS
2655 #undef COLOUR_SWIPE_WORDS
2656 #undef _1COLOUR_WORDS
2657 #undef BLK_DIRECTORY_MASK
2658 #undef COLOUR_DIRECTORY_MASK
2659 #undef DIRECTORY_TYPE_BIT
2660 #undef COLOUR_PEN_GAP
2661 #undef COLOUR_PEN_DIFF
2662 #undef INITIAL_YELLOW_BOTTOM_LINE
2663 #undef COLOUR_BUF_MASK
2664 #undef COLOUR_BUF_LINES
2665 #undef SWIPE_LEADER
2666 #undef CMDLEN_X
2667 #undef DIRECTION_X
2668 #undef UNIDIRECTIONAL
2669 #undef BIDIRECTIONAL
2670 #undef HEADSPEED_X
2671 #undef _300X
2672 #undef _600X
2673 #undef _1200Y
2674 #undef PEN_X
2675 #undef BLACK0
2676 #undef BLACK1
2677 #undef COLOUR0
2678 #undef COLOUR1
2679 #undef NOZZLE_COUNT_X
2680 #undef _192NOZZLES
2681 #undef _208NOZZLES
2682 #undef UNKNOWN1_X
2683 #undef UNKNOWN1VAL
2684 #undef NUM_COLUMNS_X
2685 #undef _1ST_COLUMN_X
2686 #undef LAST_COLUMN_X
2687 #undef SWIPE_HDR_END_X
2688 #undef SWIPE_HDR_END_LEN
2689 #undef SWIPE_HDR_END
2690 #undef SWIPE_HDR_LEN
2691 #undef BLACK_X
2692 #undef YELLOW_X
2693 #undef MAGENTA_X
2694 #undef CYAN_X
2695 #undef LO_PEN
2696 #undef HI_PEN
2697 #undef NUM_COMPONENTS_BLK
2698 #undef BITS_PER_PIXEL_BLK
2699 #undef MAX_GREY_BLK
2700 #undef MAX_RGB_BLK
2701 #undef DITHER_GREYS_BLK
2702 #undef DITHER_COLOURS_BLK
2703 #undef NUM_COMPONENTS_CMY
2704 #undef BITS_PER_PIXEL_CMY
2705 #undef MAX_GREY_CMY
2706 #undef MAX_RGB_CMY
2707 #undef DITHER_GREYS_CMY
2708 #undef DITHER_COLOURS_CMY
2709 #undef MIN_COLOUR
2710 #undef MAX_COLOUR
2711 #undef BLACK_PEN
2712 #undef _1ST_CMY_COLOUR
2713 #undef LAST_CMY_COLOUR
2714 #undef BPP
2715 #undef PIXEL_MASK
2716 #undef INITIAL_PIXEL_SHIFT
2717 #undef NUM_COLOURS
2718 #undef PENS_PER_COLOUR
2719 #undef NUM_PENS
2720 #undef BITS_PER_COLOUR
2721 #undef DEF_NUM_COLOURS
2722 #undef DEF_PENS_PER_COLOUR
2723 #undef DEF_LINE_INCREMENT
2724 #undef PIXELS_PER_BYTE
2725 #undef COLOUR_MASK
2726 #undef ALLOCATE
2727 #undef DEALLOCATE
2728 #undef FILL_SWIPE_HEADER
2729 #undef BIT_TO_MASK
2730 #undef INC_BIT
2731 #undef DEC_BIT
2732 #undef lx5000_proctab
2733