xref: /plan9/sys/src/cmd/gs/src/gdevphex.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevphex.c,v 1.7 2004/08/10 13:02:36 stefan Exp $ */
18 
19 /****************************************************************************/
20 /*	Ghostscript printer driver for Epson Color Photo, Photo EX, Photo 700	*/
21 /****************************************************************************/
22 
23 #include "gdevprn.h"
24 #include <math.h>
25 
26 /****************************************************************************/
27 /*								Legend										*/
28 /****************************************************************************/
29 
30 /*
31 
32 HISTORY
33 ~~~~~~~
34 
35 8 June 1999 Zolt�n K�csi (aka Kocsonya) zoltan@bendor.com.au
36 
37 	Initial revision.
38 	No shingling, depletion.
39 	Colour only.
40 	Dither matrix is blatantly copied from gslib.c.
41 
42 17 April 2000 Zolt�n K�csi
43 
44 	After much play worked out a reasonably simple colour mapping
45 	that gives fairly good results. It has some very hairy things
46 	in it but ot seems to work reasonably well on a variety of natural
47 	as well as artificial images.
48 
49 
50 LEGALISE
51 ~~~~~~~~
52 
53 The usual disclaimer applies, neither me (Zolt�n K�csi) nor
54 Bendor Research Pty. Ltd. assume any liability whatsoever in
55 relation to events arising out of or related to the use of
56 the software or the included documentation in any form, way
57 or purpose. This software is not guaranteed to work, you
58 get it "as is" and use it for your own risk.
59 
60 This code has been donated to Aladdin Enterprises, see their
61 license for details.
62 
63 CREDIT
64 ~~~~~~
65 This driver was written from scratch, however, I have used the
66 HP/BJ driver very heavily as a reference (GhostScript's documentation
67 needs some working :-). In addition, I got some help in understanding
68 the more arcane features of the printer by digging into the colour
69 Epson driver and its documentation (documentation for the Photo EX
70 did not exist). I thank to the authors of these drivers and the
71 related docs.
72 
73 I do also hereby express my despising Epson, Inc. who try to enlarge
74 Microsoft's monopoly by witholding programming information about such
75 a commodity item as a printer.
76 
77 KNOWN BUGS/LIMITATIONS
78 ~~~~~~~~~~~~~~~~~~~~~~
79 - Monochrome driver is not finished yet
80 - The driver is not optimised for speed
81 - The driver does not support TIFF compression
82 - Shingling and depletion is not implemented
83 - The colour correction and ink transfer curve are hardcoded
84 - The dither matrix is straight stolen from Ghostscript
85 - The alternative error diffusion included but does not work (yet)
86 
87 I plan to attend these issues later, however, I don't promise any timeframe
88 for I have a lot else to do for bread & butter too.
89 
90 PREFACE
91 ~~~~~~~
92 The Epson Stylus Photo EX is a colour ink-jet printer.
93 It can handle papers up to A3. It uses 6 inks, black in one cartridge
94 and cyan, magenta, yellow, light cyan and light magenta in an other
95 cartridge. The head has 32 nozzles, with 1/90" spacing.
96 The maximal resolution is 1440 dpi horizontal 720 dpi vertical.
97 In 720x720 and 360x360 dpi it supports microweave. To achieve
98 1440x720 you must use software weaving. It has only one built-in font,
99 namely 12pt Courier; the printer in general havily relies on the
100 driver software. It comes with (what else ?) Windows 9x and Mac drivers.
101 
102 The printer uses the ESC/P Raster protocol. This protocol is somewhat
103 similar to the ESC/P2 one. Initially Epson refused to give any info
104 about it. Later (unfortunately after I had already spent lot of time
105 to reverse engineer it) they released its definition. It could be
106 found on their website (http://www.ercipd.com/isv/level1/6clr_98b.pdf).
107 Alas, they removed it, so at the moment I do not know about any existing
108 docs of the printer.
109 There are still a few commands which are not covered by the docs
110 and for example the Windows driver uses them. There are others which
111 are in the docs, saying that you can find them in other docs but you
112 can't. Fortunately, these commands apparently have no effect on the
113 printing process so this driver simply ignores them. Tricky business.
114 
115 By the way, my personal experience is that Epson tech support is
116 a joke, or in Usenet lingvo it sucks big time - they know absolutely
117 nothing about the product they supposed to support. Epson's webpage
118 contains false info as well (they state that the Photo EX uses ESC/P2,
119 which is simply not true).
120 
121 This driver should in theory support the Stylus 700 and the Stylus Photo
122 as well but I have not tested it on them.
123 
124 If you think that you can get some useful info from me above of what you
125 can find below, feel free to email me at zoltan@bendor.com.au.
126 If you enhance the driver or find a bug *please* send me info about
127 it.
128 
129 DRIVER
130 ~~~~~~
131 The driver was written under Ghostscript 5.10.
132 This file should contain two drivers, one for colour mode and one for B&W.
133 The devices are "photoex" and "photoexm". The mono device driver is
134 catered for (that is, the rendering part knows how to render for B&W)
135 but it is not finished yet (no device structure and gray colour mapping
136 procedures) mainly because all my B&W needs are fairly well satisfied
137 by our laser printer.
138 
139 The driver features the following:
140 
141 Supported resolutions
142 
143 	 360x360	Y weaving (not that micro :-) by the printer
144 	 720x720	Y microweave by the driver (quicker than the printer)
145 	1440x720	Y and X microweave by the driver
146 
147 	Resolutions other than these will result in a rangecheck error.
148 
149 Papersize:
150 
151 	Whatever Ghostscript supports. The printer docs say that if you load
152 	multiple sheets of transparencies into the tray you should at least
153 	have 30mm or 1.2" top margin. The driver always sets the smallest
154 	possible top margin (3mm or 0.12"), it's up to you to comply.
155 
156 	In addition, the printer says that the bottom margin is at least
157 	14mm or 0.54". I violate it by setting it to 0.5" or 12.7mm.
158 	0.5" seems to be a common margin value for documents and you
159 	would hate it when the last line of your page gets printed on the
160 	top of the next sheet ...
161 
162 Options:
163 
164 	-dDotSize=n
165 
166 		n = 0		Let the driver choose a dotsize
167 		n = 1		small dots
168 		n = 2		more ink
169 		n = 3		ink flood
170 		n = 4		'super microdots' (whatever they are, they are *big*)
171 
172 		The default is 0 which is n=1 for 1440x720, 2 for 720x720 and
173 		3 for 360x360. Do not use large dots if you don't have to, you
174 		will soak the paper. If you print 720x720 on normal paper, try
175 		using n=1.
176 
177 	-dRender=n
178 
179 		n = 0		Floyd-Steinbeck error diffusion
180 		n = 1		Clustered dither
181 		n = 2		Bendor's error diffusion (experimental, do not use)
182 
183 		Default is Floyd-Steinbeck error diffusion
184 
185 	-dLeakage=nn
186 
187 		nn is between 0 and 25. It only effects Bendor's error diffusion.
188 		It sets the percentage of the error which is left to 'leak', that
189 		is it is the coefficient of an exponential decay of the error.
190 		Experiments show that it can be beneficial on image quality.
191 		Default is 0 (no leakage).
192 
193 	-dSplash=nn
194 
195 		nn is between 0 and 100. It only affects Bendor's error diffusion.
196 		The ED routine tries to take the increase of dot diameter on certain
197 		paper types into account.
198 		It sets the percentage of the ink dot size increase as it splashes
199 		onto the paper and spreads. 0 means no splashing, 100 means that
200 		the dot is twice as large as it should be.
201 		Default is 0.
202 
203 	-dBinhibit=n
204 
205 		If n is 1, then if black ink is deposited to a pixel, it will
206 		inhibit the deposition of any other ink to the same pixel.
207 		If 0, black ink may be deposited together with other inks.
208 		Default is on (1).
209 
210 ESC/P RASTER DOCS
211 ~~~~~~~~~~~~~~~~~
212 The parts of the ESC/P Raster protocol which I've managed to decipher,
213 and which are actually used in this driver can be found below.
214 nn, mm, xx, etc. represent a single byte with a binary value in it.
215 nnnn, xxxx etc. represent a 16-bit binary number, sent in two bytes,
216 in little endian order (low byte first). 2-digit numbers are a single
217 byte in hex. Other chars are themselves.
218 Quite a few commands are identical to the ESC/P2 commands, these are
219 marked with (P2).
220 
221 ESC @								(P2)
222 
223 	Resets the printer.
224 
225 
226 ESC ( U 01 00 nn					(P2)
227 
228 	Sets the unit to 3600/nn dpi. Note that 1440 can not be set !
229 
230 
231 ESC ( C 02 00 nnnn					(P2)
232 
233 	Sets the page (paper) length to nnnn units
234 
235 
236 ESC ( c 04 00 bbbb tttt				(P2)
237 
238 	Sets the top margin to tttt units, the bottom margin to
239 	bbbb units. The bottom margin is measured from the top
240 	of the page not from the bottom of the page !
241 
242 
243 ESC	U nn							(P2)
244 
245 	Unidirectional printing
246 
247 	nn
248 	00	off
249 	01	on
250 	30	off (this is ASCII 0)
251 	31	on	(this is ASCII 1)
252 
253 
254 ESC	( i 01 00 nn					(P2)
255 
256 	Microweave
257 
258 	nn
259 	00	off
260 	01	on
261 	30	off (this is ASCII 0)
262 	31	on	(this is ASCII 1)
263 
264 	Turns microweave on for 720x720 dpi printing.
265 
266 ESC r nn							(P2)
267 
268 	Select colour
269 
270 	nn
271 	01		Cyan
272 	02		Magenta
273 	04		Yellow
274 	08		Black
275 
276 
277 ESC ( G 01 00 nn					(P2)
278 
279 	Selects graphics mode:
280 
281 	nn
282 	00		Off
283 	01		On
284 	30		Off
285 	31		On
286 
287 
288 ESC ( v 02 00 dddd					(P2)
289 
290 	Advance the paper by dddd units defined by ESC ( U
291 
292 
293 ESC . cc vv hh nn mmmm <data>		(P2)
294 
295 	Sends graphics data to the printer.
296 
297 	cc	Encoding mode
298 
299 		00	Raw data
300 		01	Run-length encoded data
301 
302 	vv	Vertical resolution
303 
304 		28	  90 dpi	*interleave*
305 		14	 180 dpi	*interleave*
306 		0a	 360 dpi
307 		05	 720 dpi
308 
309 	hh	Horizontal resolution
310 
311 		0a	 360 dpi
312 		05	 720 dpi
313 
314 	nn	Number of nozzles
315 
316 		It should be set to 32 (normal printing) or 1 (microweave)
317 
318 	mmmm Number of collumns of data (not number of data bytes !)
319 
320 	<data>
321 
322 		The data should contain as many bytes as needed to fill the
323 		mmmm * nn pixels. Data is presented horizontally, that is,
324 		the bits of a byte will be represented by eight pixels in
325 		a row. If the number of collumns is not an integer multiple
326 		of eight, then some bits from the last byte belonging to the
327 		row will be discarded and the next row starts on a byte boundary.
328 		If a bit in a byte is '1' ink is deposited, if '0' not.
329 		The leftmost pixel is represented by the MSB, rightmost by LSB.
330 		In case of raw data that's about it.
331 
332 		In case of run-length encoded data, the following is done:
333 		The first byte is a counter. If the counter is <= 127 then
334 		the following counter+1 bytes are uncompressed data.
335 		If the counter is >= 128 then the following single byte should
336 		be repeated 257-counter times.
337 
338 	There are resolution restrictions:
339 
340 		360x360 nozzle= 1 microweave on
341 		360x360 nozzle=32 microweave off
342 		720x 90 nozzle=32 microweave off
343 		720x720	nozzle= 1 microweave on
344 
345 	Other combinations are not supported.
346 
347 ESC ( e 02 00 00 nn
348 
349 	Sets the amount of ink spat onto the paper.
350 
351 	nn
352 	01		microdots (faint printing)
353 	02		normal dots (not so faint printing)
354 	03		double dots (full inking)
355 	04		super microdots (ink is continuously dripping :-)
356 
357 	Values other than that have apparently no effect.
358 
359 ESC ( K 02 00 xxxx
360 
361 	This command is sent by the Windows driver but it is not used
362 	in the Epson test images. I have not found it having any effect
363 	whatsoever. The driver does not use it. The Epson docs don't
364 	mention it.
365 
366 ESC ( r 02 00 nn mm
367 
368 	Selects the ink according to this:
369 
370 	nn mm
371 	00 00	black
372 	00 01	magenta
373 	00 02	cyan
374 	00 04	yellow
375 	01 01	light magenta
376 	01 02	light yellow
377 
378 
379 ESC ( \ 04 00 xxxx llll
380 
381 	Horizontal positioning of the head.
382 
383 	Moves the head to the position llll times 1/xxxx inches from
384 	the left margin.
385 	On the example images xxxx was always set to 1440.
386 	I tried other values in which case the command was ignored,
387 	so stick to 1440.
388 
389 
390 ESC ( R ll 00 00 <text> <cc> xxxx nn .. nn
391 ESC 00 00 00
392 
393 	This is supposedly sets the printer into 'remote' mode.
394 	ll is the length of the <text> + 1 which consists of ASCII
395 	characters (e.g. REMOTE1).
396 	<cc> is a two-character code, for example "SN" or "LD".
397 	xxxx is the number of bytes (nn -s) which will follow.
398 	After that there's either a new <cc> xxxx nn .. nn sequence or
399 	the ESC 00 00 00.
400 	I have absolutely no idea about this command and the Epson document
401 	says that it's in an other document. It's not in that other one.
402 	The driver does not use it. The printer does not miss it.
403 	The Epson test images use it and the Windows driver uses it too.
404 	They send different <cc>-s and different values for identical <cc>-s.
405 	Go figure.
406 
407 DRIVER INTERNALS
408 ~~~~~~~~~~~~~~~~
409 First, some comments.
410 Anything I know about the printer can be found above.
411 Anything I know about Ghostscript internals (not much) can be
412 found in the comments in the code. I do not believe in the 'it was hard
413 to write, it should be hard to read' principle since I once had to
414 understand my own code.
415 Therefore, the code has lots of comments in it, sometimes apparently
416 superfluous but I find it easier to understand the program 6 months
417 later that way.
418 I did not follow the Ghostscript or GNU style guide, I write code the way
419 I like it - I'm a lazy dog :-) I use hard tabs at every 4th position,
420 I use a *lot* of whitespace (as recommended by K&R in their original
421 C book) and I have a formatting style similar to the K&R with the
422 notable exception that I do not indent variable declarations that follow
423 the curly. Anyway, you can run your favourite C formatter through the
424 source.
425 
426 In addition to the above, the driver is not hand-optimised, it assumes
427 that it is compiled with a good optimising compiler which will handle
428 common subexpression ellimination, move loop independent code out of
429 the loop, transform repeated array accesses to cached pointer arithmetics
430 and so on. The code is much more readable this way and gcc is fairly
431 good at doing optimisation. Feel free to hand-optimise it.
432 
433 So, the driver works the following way:
434 
435 When it has to render a page, first it sets up the basics such as margins
436 and papersize and alike.
437 
438 Line scheduling
439 ---------------
440 
441 Then it calls the line scheduler. To see why do we have a scheduler, you
442 have to understand weaving. The printer head has 32 nozzles which are
443 spaced at 8 line intervals. Therefore, it prints 32 lines at a time but they
444 are distributed over a 256 line high area. Obviously, if you want to print
445 all the lines under the head, you should pass over the paper 8 times.
446 You can do it the obvious way:
447 Print, move down by one line, print ... repeat 8 times then move down
448 by 256 - 8 lines and start again. Unfortunately, this would result in
449 stripy images due to the differences between individual nozzles.
450 Lines 0-7 would be printed by nozzle 0, 8-15 by nozzle 1 and so on. An
451 8 line band has a visible height, so difference between nozzles will
452 cause 8-line high bands to appear on the image.
453 
454 The solution is 'microweave', a funny way of doing interlaced printing.
455 Instead of moving down 1, 1, 1, 1, .. 1, 248, 1, 1 .. you move down
456 a constant, larger amount (called a band). This amount must be chosen
457 in such a way that each line will be printed and preferably it will be
458 printed only once.
459 
460 Let for example the move down amount (the band) be 31. Let's say,
461 in band N nozzle 31 is over line 300, in which case nozzle 30 is over
462 line 292. We move the head down by 31 lines, then line 299 will be
463 under nozzle 27 and line 307 under nozzle 28.
464 Next move, nozzle 23 will print line 298 and nozzle 24 line 306, then
465 19/297 20/305, 15/296 16/304, 11/295 12/303, 7/294 8/302, 3/293 4/302,
466 0/292 3/301 which covers the entire area between 292 and 307.
467 The same will apply to any other area on the page. Also note that
468 adjacent lines are always printed by different nozzles.
469 You probably have realised that line 292 was printed in the first pass
470 and in the last one. In this case, of course, the line must not be printed
471 twice, one or the other pass should not deliver data to the nozzle which
472 passes over this line.
473 
474 Now there's a twist. When the horizontal resolution is 1440 dpi you have
475 to print each line twice, first depositing all even pixels then offset
476 the head by 1/1440" and deposit all odd pixels (the printer can only
477 print with 720 dpi but you can initially position the head with 1440 dpi
478 resolution). You could do it the easy way, passing over the same area
479 twice but you can do better. You can find a band size which will result
480 each line being printed twice. Instead of suppressing the double print,
481 you use this mechanism to print the odd and the even pixels.
482 Now if you print one line's odd pixels, obviously, all lines belonging
483 to the 31 other nozzles of the head will have their odd pixels printed too.
484 Therefore, you have to keep track which lines have been printed in which
485 phase and try to find an odd-even phase assignment to bands so that each line
486 has both groups printed (and each group only once).
487 The added bonus is that even the same line will be printed by two different
488 nozzles thus effects of nozzle differences can be decreased further.
489 
490 The whole issue is further complicated with the beginning of the page and
491 the end of the page. When you print the first 8 lines you *must* use the
492 print, down by 1, print ... method but then you have to switch over to the
493 banding method. To do it well, you should minimise the number of lines which
494 are printed out of band. This optimisation is not complex but not trivial
495 either. Our solution is to employ precalculated tables for the first 8 lines.
496 (Epson's solution is not to print the 'problematic' lines at all - they
497 warn you in the manual that at the top and bottom you may have "slight
498 distortions". Analyzing their output reveals the reason ... ).
499 The bottom is different. It is easier, because you are already banding, so
500 you can't screw up the rest of the image. On the other hand, you can't use
501 tables because these tables would depend on the page height which you don't
502 know a priori. Our solution is to switch to single line mode when we can
503 not do the banding any more and try to finish the page with the minimal
504 amount of passes.
505 
506 So, first the driver calls the scheduler which returns a list of lines which
507 it dispatched to print in the current band. Then the driver checks if it has
508 all these lines halftoned. Since the head covers an area of 256 lines, we
509 have to buffer that many lines (actually, 256-7). As the head moves down,
510 we can flush lines which it has left and halftone the new ones.
511 
512 
513 Colour transformations
514 ----------------------
515 
516 The next important issue is the colour transformation. The reason for doing
517 this is that the ink is not perfect. Ideally, you have 3 inks, namely cyan
518 magenta and yellow. Mixing these you can have all colours. Now the inks
519 are not pure, that is the cyan ink contains some particles that have a
520 colour other than the ideal cyan and so on. In addition, the inks are
521 not exactly cyan, magenta and yellow. Therefore, you have to do some
522 transformations that will map the ideal C, M, Y values to amounts of
523 ink of the real kind. You also have a black ink. Although in theory
524 mixing C, M, Y in equal amount will give you black, it doesn't exactly
525 work that way. In addition, black ink is cheap compared to the colour
526 so if you can use black, you rather use that. On top of all that,
527 because of other effects (ink splashing on the paper and things like that)
528 you have to apply some non-linear functions to get reasonable colours.
529 
530 Halftoning
531 ----------
532 
533 The driver has different halftoning methods.
534 There is the classic Floyd-Stenberg error diffusion. There is an other
535 ED, of which I'm hammering the matrix. The matrix is larger than the
536 FS one and IMHO results in somewhat lower halftoning noise. However,
537 it completely screws up some flat colours so don't use it.
538 There is also dithering, which is quick but noisy.
539 
540 For any halftoning method, it is assumed that the haltoning can be
541 done on the 4 colours (CMYK) separately and all interdependencies are
542 already handled. It is an optimistic assumption, however, close enough.
543 
544 You can add any halftoning method you like by writing a halftoner
545 module. A halftoner module consists of 4 functions:
546 
547 - Init, which is called before halftoning starts.
548 - Threshold, which should return a number which tells the driver how many
549   empty lines needed before halftoning can be stopped (i.e. for how many
550   lines will a line affect halftoning of subsequent lines).
551 - Halftone, which halftones one colour of one line
552 - EndOfLine which is called when all colours of a scanline are halftoned,
553   you can do your housekeeping functions here.
554 
555 For example, in the case of ED init() clears the error buffers, threshold()
556 returns ~5 (5 empty lines are enough for the accumulated error to go to
557 almost zero), endofline() shuffles the error buffers and halftone() itself
558 does the error diffusion. In case of dithering, threshold is 0 (dithering
559 has no memory), init and endofline do nothing and halftone simply
560 dithers a line.
561 
562 A few options are available for all halftoners:
563 
564 - the black is rendered first. Now this black line is presented to all
565   further passes. If a pixel is painted black, there's no point to
566   deposit any other colour on it, even if the halftoning itself would do.
567   Therefore, an already set black pixel can block the halftoning of colours
568   for that pixel. Whether this thing is activated or not is a command line
569   switch (default is on). Your halftoner may choose to ignore this flag.
570 
571 - the intensity value of the light-cyan and light-magenta ink can be
572   set from the command line. My experience is that the default 127 is
573   good enough, but you can override it if you want to.
574 
575 Apart from these features, each halftoner can have all sorts of other
576 switches. Currently there are switches for the Bendor ED, see the
577 comments in front of the BendorLine() function to see what they are.
578 
579 Postprocessing
580 --------------
581 
582 After lines are halftoned, they are packed into bitstreams. If you use
583 1440x720 then the 2 passes for the horizontal interleave are separated.
584 Postprocessing should also do the shingling/depletion, but it is not
585 yet done.
586 
587 Compression
588 -----------
589 
590 The driver, before it sends the data to the printer, compresses it using
591 RLE (run-length encoding) compression. It is not very effective but still
592 more than nothing. I have not yet ventured into using TIFF as output format,
593 it may come later.
594 
595 */
596 
597 /****************************************************************************/
598 /*						Device specific definitions							*/
599 /****************************************************************************/
600 
601 /*
602 *	Device limits
603 */
604 
605 #define	MAX_WIDTH	11.46			/* Maximum printable width, 8250 dots	*/
606 #define	MAX_PIXELS	8250
607 #define	MAX_BYTES	(MAX_PIXELS+7)/8
608 
609 /*
610 *	Margins (in inch)
611 */
612 
613 #define	MARGIN_L	0.12			/* Left margin							*/
614 #define	MARGIN_R	0.12			/* Right margin							*/
615 #define	MARGIN_T	0.12			/* Top margin							*/
616 #define	MARGIN_B	0.50			/* Bottom margin (should be 0.54 !)		*/
617 
618 /*
619 *	We default to 720x720 dpi
620 */
621 
622 #define	Y_DPI		720				/* Default vertical resolution	[dpi]	*/
623 #define	X_DPI		720				/* Default horizontal resolution [dpi]	*/
624 
625 /*
626 *	Encoding of resolutions. Does *not* work with 1440 dpi !
627 */
628 
629 #define	RESCODE( x )	(3600/(x))
630 
631 /*
632 *	The device has 6 different inks
633 */
634 
635 #define	DCOLN			6
636 
637 /*
638 *	Device colour codes
639 *	CAVEAT: if you change them change the SendColour() procedure too !
640 */
641 
642 #define	DEV_BLACK		0
643 #define	DEV_CYAN		1
644 #define	DEV_MAGENTA		2
645 #define	DEV_YELLOW		3
646 #define	DEV_LCYAN		4
647 #define	DEV_LMAGENTA	5
648 
649 /*
650 *	The head has 32 nozzles, with 8 x 1/720" spacing
651 */
652 
653 #define	NOZZLES			32
654 #define	HEAD_SPACING	8
655 
656 /*
657 *	Some ASCII control characters
658 */
659 
660 #define	CR				13			/* Carriage return						*/
661 #define	FF				12			/* Form feed							*/
662 #define	ESC				"\033"		/* Escape								*/
663 
664 /****************************************************************************/
665 /*						Internally used definitions							*/
666 /****************************************************************************/
667 
668 #ifndef	TRUE
669 #define	TRUE	1
670 #endif
671 
672 #ifndef	FALSE
673 #define	FALSE	0
674 #endif
675 
676 /*
677 *	Since the printer is CMYK, we use 4 colours internally
678 */
679 
680 #define	ICOLN			4
681 
682 /*
683 *	This is the maximum number of error lines needed by any
684 *	currently implemented rendering function.
685 *	If you need more, increase it.
686 */
687 
688 #define	MAX_ED_LINES	3
689 
690 /*
691 *	If this is defined to !0 then we use Adobe's CMYK -> RGB mapping,
692 *	Ghostscript's otherwise. Ghostscript claims that their mapping
693 *	is better. The mapping of CMYK to RGB according to Adobe is:
694 *
695 *		R = 1.0 - min( 1.0, C + K )
696 *		G = 1.0 - min( 1.0, M + K )
697 *		B = 1.0 - min( 1.0, Y + K )
698 *
699 *	while Ghostscript uses this:
700 *
701 *		R = ( 1.0 - C ) * ( 1.0 - K )
702 *		G = ( 1.0 - M ) * ( 1.0 - K )
703 *		B = ( 1.0 - Y ) * ( 1.0 - K )
704 */
705 
706 #define	MAP_RGB_ADOBE	0
707 
708 /*
709 *	We store a CMYK value in a 32 bit entity, each component being 8 bit.
710 *	These macros pack and unpack these blocks.
711 *	Ghostscript guarantees that when we get them back the unsigned long
712 *	will be placed in memory in a big-endian format (regardless of the
713 *	actual architecture it's running on), so we declare the colour offsets
714 *	accordingly.
715 */
716 
717 #define	OFFS_C		0
718 #define	OFFS_M		1
719 #define	OFFS_Y		2
720 #define	OFFS_K		3
721 
722 #define	DECOMPOSE_CMYK( index, c, m, y, k ) \
723 	{										\
724 		(k) = (index) & 255;				\
725 		(y) = ( (index) >> 8 ) & 255;		\
726 		(m) = ( (index) >> 16 ) & 255;		\
727 		(c) = ( (index) >> 24 ) & 255; 		\
728 	}
729 
730 #define	BUILD_CMYK( c, m, y, k ) \
731 	((((long)(c)&255)<<24)|(((long)(m)&255)<<16)|\
732 	(((long)(y)&255)<<8)|((long)(k)&255))
733 
734 /*
735 *	This structure is for colour compensation
736 */
737 
738 typedef	struct {
739 
740 	int		ra;						/* Real colour angle (hue)				*/
741 	int		ia;						/* Theoretical ink colour angle 		*/
742 	int		c;						/* Cyan component						*/
743 	int		m;						/* Magenta component					*/
744 	int		y;						/* Yellow component						*/
745 
746 } CCOMP;
747 
748 /*
749 *	Our device structure has some extensions
750 */
751 
752 typedef	struct gx_photoex_device_s {
753 
754 	gx_device_common;				/* This macro defines a graphics dev.	*/
755 	gx_prn_device_common;			/* This macro extends for printer dev.	*/
756 	int		shingling;				/* Shingling (multipass, overlap) mode	*/
757 	int		depletion;				/* Excess dot removal					*/
758 	int		halftoner;				/* Rendering type						*/
759 	int		splash;					/* Splashing compensation factor		*/
760 	int		leakage;				/* Error leakage (percentage)			*/
761 	int		mono;					/* Monochrome mode (black only)			*/
762 	int		pureblack;				/* Black ink blocks others				*/
763 	int		midcyan;				/* Light cyan ink value					*/
764 	int		midmagenta;				/* Light magenta ink value				*/
765 	int		dotsize;				/* Size of the ink dot					*/
766 
767 } gx_photoex_device;
768 
769 /*
770 *	These can save some typing
771 */
772 
773 typedef	gx_device			DEV;
774 typedef	gx_device_printer	PDEV;
775 typedef	gx_photoex_device	EDEV;
776 typedef	gx_color_index		CINX;
777 typedef	gx_color_value		CVAL;
778 typedef	gs_param_list		PLIST;
779 typedef	gs_param_name		PNAME;
780 
781 /*
782 *	How many lines do we have to think ahead
783 */
784 
785 #define	MAX_MARK		((NOZZLES)*(HEAD_SPACING))
786 
787 /*
788 *	This structure stores a device scanline for one colour
789 */
790 
791 typedef	struct	{
792 
793 	int		first;					/* Index of the first useful byte	*/
794 	int		last;					/* Index of the last useful byte	*/
795 	byte	data[ MAX_BYTES ];		/* Actual raw data					*/
796 
797 } RAWLINE;
798 
799 /*
800 *	These definitions are used by the microweave scheduler.
801 *	These are the band height definitions. Do not fiddle with them,
802 *	they are the largest number with which no lines are skipped
803 *	and the unused nozzles in the head for each band is minimal.
804 *	They, of course, depend on the number of nozzles in the head
805 *	and their spacing, these numbers are for 32 and 8, respectively.
806 */
807 
808 #define	BAND_1440		13			/* Band height for 1440dpi, double scan	*/
809 #define	BAND_720		31			/* Band height for 720dpi, single scan	*/
810 #define	BAND_360		1			/* Band height for 360dpi, single scan	*/
811 
812 #define	NOZZLE_1440		(NOZZLES)	/* Number of nozzles used for 1440dpi	*/
813 #define	NOZZLE_720		(NOZZLES)	/* Number of nozzles used for 720dpi	*/
814 #define	NOZZLE_360		1			/* Number of nozzles used for 360dpi	*/
815 
816 /*
817 *	This structure is used to generate the line scheduling data.
818 *	Input/output refers to the scheduler I/F: input means data
819 *	given to the scheduler, output is what it gives back. Unspecified
820 *	data is scheduler private.
821 */
822 
823 typedef	struct {
824 
825 	int		last;					/* Input	Last line to print			*/
826 	int		resol;					/* Input	X Resolution				*/
827 	int		nozzle;					/* Output	Number of nozzles			*/
828 	int		down;					/* Output	Lines to move down			*/
829 	int		head[ NOZZLES ];		/* Output	Which lines to be sent		*/
830 	int		offset;					/* Output	Offset line by 1/1440"		*/
831 	int		top;					/* 			Head position now			*/
832 	int		markbeg;				/* 			First marked line			*/
833 	byte	mark[ MAX_MARK ];		/* 			Marks already printed lines	*/
834 
835 } SCHEDUL;
836 
837 /*
838 *	These macros are used to access the printer device
839 */
840 
841 #define	SendByte( s, x )	fputc( (x), (s) )
842 
843 #define	SendWord( s, x )	SendByte((s), (x) & 255); \
844 							SendByte((s), ((x) >> 8 ) & 255);
845 
846 /*
847 *	This structure stores all the data during rendering
848 */
849 
850 typedef	struct {
851 
852 	EDEV	*dev;					/* The actual device struct			*/
853 	FILE	*stream;				/* Output stream					*/
854 	int		yres;					/* Y resolution						*/
855 	int		xres;					/* X resolution						*/
856 	int		start;					/* Left margin in 1/1440 inches		*/
857 	int		width;					/* Input data width in pixels		*/
858 	int		lines;					/* Number of lines					*/
859 	int		mono;					/* Black only						*/
860 	byte	*dbuff;					/* Data buffer 						*/
861 	int		htone_thold;			/* Halftoner restart threshold		*/
862 	int		htone_last;				/* Last line halftoned				*/
863 	SCHEDUL	schedule;				/* Line scheduling info				*/
864 
865 	/* These are the error buffers for error diffusion. MAX_PIXELS*2
866 	   is needed for 1440 dpi printing. */
867 
868 	short	err[ MAX_ED_LINES ][ ICOLN ][ MAX_PIXELS*2 ];
869 
870 	/* Error buffer pointers. I love C :-) */
871 
872 	short	( *error[ MAX_ED_LINES ] )[ MAX_PIXELS*2 ];
873 
874 	/* This stores the halftoning result for a line,
875 	   not yet in device format. (It's CMYK 1 byte/pixel/colour) */
876 
877 	byte	res[ ICOLN ][ MAX_PIXELS*2 ];
878 
879 	/* This is the buffer for rendered lines, converted
880 	   to raw device data (not yet run-length encoded).
881 	   That is, it's 6 colours, 1 bit/pixel/colour.
882 	   The first index is the 1440 dpi X-weave phase. */
883 
884 	RAWLINE	raw[ 2 ][ DCOLN ][ MAX_MARK ];
885 
886 	/* This buffer stores a single line of one colour,
887 	   run-length encoded, ready to send to the printer */
888 
889 	byte	rle[ MAX_PIXELS * 2 ];
890 
891 } RENDER;
892 
893 /*
894 *	This is the sctructure used by the actual halftoner algorithms
895 */
896 
897 typedef	struct	{
898 
899 	RENDER	*render;				/* Render info, if needed				*/
900 	byte	*data;					/* Input data							*/
901 	int 	step;					/* Steps on input data					*/
902 	byte	*res;					/* Result								*/
903 	byte	*block;					/* Blocking data						*/
904 	short	**err;					/* Pointers to error buffers			*/
905 	int		lim1; 					/* Halftoning lower limit				*/
906 	int		lim2; 					/* Halftoning upper limit				*/
907 	int		mval; 					/* Level represented by 'light' colour	*/
908 
909 } HTONE;
910 
911 /*
912 *	Halftoner function table
913 */
914 
915 typedef	struct {
916 
917 	int		(*hthld)( RENDER *rend );
918 	void	(*hstrt)( RENDER *rend, int line );
919 	void	(*hteol)( RENDER *rend, int line );
920 	void	(*htone)( HTONE *htone, int line );
921 
922 } HFUNCS;
923 
924 /*
925 *	Number of known halftoning methods
926 */
927 
928 #define	MAXHTONE		3
929 
930 /*
931 *	Dither matrix size
932 */
933 
934 #define	DMATRIX_X		16
935 #define	DMATRIX_Y		16
936 
937 /****************************************************************************/
938 /*							Prototypes										*/
939 /****************************************************************************/
940 
941 private int		photoex_open( gx_device *pdev );
942 private	int		photoex_print_page( PDEV *dev, FILE *prn_stream );
943 private	CINX	photoex_map_rgb_color( DEV *dev, CVAL r, CVAL g, CVAL b );
944 private int		photoex_map_color_rgb( DEV *dev, CINX index, CVAL prgb[3] );
945 private	int		photoex_get_params( DEV *dev, PLIST *plist );
946 private	int		photoex_put_params( DEV *dev, PLIST *plist );
947 
948 private int 	PutInt( PLIST *plist, PNAME name, int *val,
949 						int minval, int maxval, int code );
950 private	int		GetInt( PLIST *list, PNAME name, int *value, int code );
951 
952 private	int		Cmy2A( int c, int m, int y );
953 
954 private	void	SchedulerInit( SCHEDUL *p );
955 private	int		ScheduleLines( SCHEDUL *p );
956 private	void	ScheduleLeading( SCHEDUL *p );
957 private	void	ScheduleMiddle( SCHEDUL *p );
958 private	void	ScheduleTrailing( SCHEDUL *p );
959 private	void	ScheduleBand( SCHEDUL *p, int mask );
960 
961 private	void	RenderPage( RENDER *p );
962 private	void	RenderLine( RENDER *p, int line );
963 private	int		IsScanlineEmpty( RENDER *p, byte *line );
964 
965 private	int		RleCompress( RAWLINE *raw, int min, int max, byte *rle_data );
966 private	int		RleFlush( byte *first, byte *reps, byte *now, byte *out );
967 
968 private	void	SendReset( FILE *stream );
969 private	void	SendMargin( FILE *stream, int top, int bot );
970 private	void	SendPaper( FILE *stream, int length );
971 private	void	SendGmode( FILE *stream, int on );
972 private void	SendUnit( FILE *stream, int res );
973 private	void	SendUnidir( FILE *stream, int on );
974 private	void	SendMicro( FILE *stream, int on );
975 private void	SendInk( FILE *stream, int x );
976 private	void	SendDown( FILE *stream, int x );
977 private	void	SendRight( FILE *stream, int amount );
978 private	void	SendColour( FILE *stream, int col );
979 private void	SendData( FILE *stream, int hres, int vres, int noz, int col );
980 private	void	SendString( FILE *stream, const char *s );
981 
982 private	void	HalftonerStart( RENDER *render, int line );
983 private	int		HalftoneThold( RENDER *render );
984 private	void	HalftoneLine( RENDER *render, int line, byte *data );
985 
986 private	int		BendorThold( RENDER *p );
987 private	void	BendorStart( RENDER *p, int line );
988 private	void	BendorEol( RENDER *p, int line );
989 private	void	BendorLine( HTONE *htone, int y );
990 
991 private	int		FloydSThold( RENDER *p );
992 private	void	FloydSStart( RENDER *p, int line );
993 private	void	FloydSEol( RENDER *p, int line );
994 private	void	FloydSLine( HTONE *htone, int y );
995 
996 private	int		DitherThold( RENDER *p );
997 private	void	DitherStart( RENDER *p, int line );
998 private	void	DitherEol( RENDER *p, int line );
999 private	void	DitherLine( HTONE *htone, int y );
1000 
1001 /****************************************************************************/
1002 /*							Static data										*/
1003 /****************************************************************************/
1004 
1005 /*
1006 *	Halftoner function table
1007 */
1008 
1009 private	const HFUNCS	htable[ MAXHTONE ] = {
1010 
1011 	{ FloydSThold, FloydSStart, FloydSEol, FloydSLine },
1012 	{ DitherThold, DitherStart, DitherEol, DitherLine },
1013 	{ BendorThold, BendorStart, BendorEol, BendorLine }
1014 };
1015 
1016 /*
1017 *	Define the printer procedures.
1018 *	The definition is based on GS macros, the only real stuff that we
1019 *	define here are the photoex_ functions.
1020 */
1021 
1022 private	gx_device_procs photoex_device_procs = prn_color_params_procs(
1023 
1024 	photoex_open,					/* Opens the device						*/
1025 	gdev_prn_output_page,
1026 	gdev_prn_close,
1027 	photoex_map_rgb_color,			/* Maps an RGB pixel to device colour	*/
1028 	photoex_map_color_rgb,			/* Maps device colour back to RGB		*/
1029 	photoex_get_params,				/* Gets device parameters				*/
1030 	photoex_put_params				/* Puts device parameters				*/
1031 );
1032 
1033 /*
1034 *	Device descriptor structure - this is what GhostScript looks
1035 *	for and uses to identify our device.
1036 *	Do not make it private (or static) !
1037 */
1038 
1039 gx_photoex_device far_data gs_photoex_device = {
1040 
1041 	/* This is a macro that fills GS specific fields in the struct */
1042 
1043 	prn_device_body(
1044 
1045 		gx_photoex_device,			/* Device struct type					*/
1046 		photoex_device_procs, 		/* Procedure table						*/
1047 		"photoex",					/* Name of the device					*/
1048 		DEFAULT_WIDTH_10THS,		/* Default width						*/
1049 		DEFAULT_HEIGHT_10THS,		/* Default height						*/
1050 		X_DPI, 						/* Vertical resolution					*/
1051 		Y_DPI,						/* Horizontal resolution				*/
1052 		MARGIN_L, 					/* Left margin							*/
1053 		MARGIN_B, 					/* Bottom margin						*/
1054 		MARGIN_R,					/* Right margin							*/
1055 		MARGIN_T, 					/* Top margin							*/
1056 		ICOLN,						/* Number of colours (4:CMYK)			*/
1057 		32,							/* Bit per pixel for the device(!)		*/
1058 		255,						/* Max. gray level						*/
1059 		255, 						/* Max. colour level					*/
1060 		256,						/* Number of gray gradations			*/
1061 		256,						/* Number of colour gradations			*/
1062 		photoex_print_page			/* Print page procedure					*/
1063 	),
1064 
1065 	/* Here come our extensions */
1066 
1067 	0,								/* Shingling off, not implemented		*/
1068 	0,								/* Depletion off, not implemented		*/
1069 	0,								/* Dither type: FS ED					*/
1070 	0,								/* No splash correction					*/
1071 	0,								/* No leakage							*/
1072 	0,								/* Not monochrome						*/
1073 	1,								/* Colour inhibition on black			*/
1074 	127,							/* Mid level cyan						*/
1075 	127,							/* Mid level magenta					*/
1076 	0								/* Automatic dot size setting			*/
1077 };
1078 
1079 /*
1080 *	This table contains the line scheduling table for the first
1081 *	few runs if we are in 720 dpi mode.
1082 */
1083 
1084 private	const int	start_720[ HEAD_SPACING ][ NOZZLES ] = {
1085 
1086 	{	  0,	  8,	 16,	 24,	 32,	 40,	 48,	 56,
1087 		 64,	 72,	 80,	 88,	 96,	104,	112,	120,
1088 		128,	136,	144,	152,	160,	168,	176,	184,
1089 		192,	200,	208,	216,	224,	232,	240,	248 },
1090 
1091 	{	  1,	  9,	 17,	 25,	 33,	 41,	 49,	 57,
1092 		 65,	 73,	 81,	 89,	 97,	105,	113,	121,
1093 		129,	137,	145,	153,	161,	169,	177,	185,
1094 		193,	201,	209,	 -1,	 -1,	 -1,	 -1,	 -1 },
1095 
1096 	{	  2,	 10,	 18,	 26,	 34,	 42,	 50,	 58,
1097 		 66,	 74,	 82,	 90,	 98,	106,	114,	122,
1098 		130,	138,	146,	154,	162,	170,	178,	 -1,
1099 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1100 
1101 	{	  3,	 11,	 19,	 27,	 35,	 43,	 51,	 59,
1102 		 67,	 75,	 83,	 91,	 99,	107,	115,	123,
1103 		131,	139,	147,	 -1,	 -1,	 -1,	 -1,	 -1,
1104 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1105 
1106 	{	  4,	 12,	 20,	 28,	 36,	 44,	 52,	 60,
1107 		 68,	 76,	 84,	 92,	100,	108,	116,	 -1,
1108 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1109 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1110 
1111 	{	  5,	 13,	 21,	 29,	 37,	 45,	 53,	 61,
1112 		 69,	 77,	 85,	 -1,	 -1,	 -1,	 -1,	 -1,
1113 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1114 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1115 
1116 	{	  6,	 14,	 22,	 30,	 38,	 46,	 54,	 -1,
1117 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1118 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1119 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1120 
1121 	{	  7,	 15,	 23,	 -1,	 -1,	 -1,	 -1,	 -1,
1122 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1123 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1124 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 }
1125 };
1126 
1127 
1128 /*
1129 *	This table contains the scheduling table for the first
1130 *	few lines if we are in 1440 dpi mode
1131 */
1132 
1133 private	const int	start_1440[ 2 ][ HEAD_SPACING ][ NOZZLES ] = {
1134   {
1135 	{	  0,	  8,	 16,	 24,	 32,	 40,	 48,	 56,
1136 		 64,	 72,	 80,	 88,	 96,	104,	112,	120,
1137 		128,	136,	144,	152,	160,	168,	176,	184,
1138 		192,	200,	208,	216,	224,	232,	240,	248 },
1139 
1140 	{	  1,	  9,	 17,	 25,	 33,	 41,	 49,	 57,
1141 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1142 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1143 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1144 
1145 	{	  2,	 10,	 18,	 -1,	 -1,	 -1,	 -1,	 -1,
1146 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1147 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1148 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1149 
1150 	{	  3,	 11,	 19,	 27,	 35,	 43,	 51,	 59,
1151 		 67,	 75,	 83,	 -1,	 -1,	 -1,	 -1,	 -1,
1152 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1153 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1154 
1155 	{	  4,	 12,	 20,	 28,	 36,	 44,	 -1,	 -1,
1156 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1157 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1158 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1159 
1160 	{	  5,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1161 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1162 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1163 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1164 
1165 	{	  6,	 14,	 22,	 30,	 38,	 46,	 54,	 62,
1166 		 70,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1167 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1168 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1169 
1170 	{	  7,	 15,	 23,	 31,	 -1,	 -1,	 -1,	 -1,
1171 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1172 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1173 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1174 
1175   },
1176   {
1177 	{	  0,	  8,	 16,	 24,	 32,	 40,	 48,	 56,
1178 		 64,	 72,	 80,	 88,	 96,	 -1,	 -1,	 -1,
1179 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1180 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1181 
1182 	{	  1,	  9,	 17,	 25,	 33,	 41,	 49,	 57,
1183 		 65,	 73,	 81,	 89,	 97,	105,	113,	121,
1184 		129,	137,	145,	153,	161,	 -1,	 -1,	 -1,
1185 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1186 
1187 	{	  2,	 10,	 18,	 26,	 34,	 42,	 50,	 58,
1188 		 66,	 74,	 82,	 90,	 98,	106,	114,	122,
1189 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1190 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1191 
1192 	{	  3,	 11,	 19,	 27,	 35,	 43,	 51,	 59,
1193 		 67,	 75,	 83,	 91,	 99,	107,	115,	123,
1194 		131,	139,	147,	155,	163,	171,	179,	187,
1195 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1196 
1197 	{	  4,	 12,	 20,	 28,	 36,	 44,	 52,	 60,
1198 		 68,	 76,	 84,	 92,	100,	108,	116,	124,
1199 		132,	140,	148,	 -1,	 -1,	 -1,	 -1,	 -1,
1200 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1201 
1202 	{	  5,	 13,	 21,	 29,	 37,	 45,	 53,	 61,
1203 		 69,	 77,	 85,	 93,	101,	109,	 -1,	 -1,
1204 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1205 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1206 
1207 	{	  6,	 14,	 22,	 30,	 38,	 46,	 54,	 62,
1208 		 70,	 78,	 86,	 94,	102,	110,	118,	126,
1209 		134,	142,	150,	158,	166,	174,	 -1,	 -1,
1210 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1211 
1212 	{	  7,	 15,	 23,	 31,	 39,	 47,	 55,	 63,
1213 		 71,	 79,	 87,	 95,	103,	111,	119,	127,
1214 		135,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
1215 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
1216 
1217   }
1218 };
1219 
1220 /*
1221 *	This is the dither matrix we use for ordered dither
1222 *	It is a shameless copy of Ghostscript's own ...
1223 */
1224 
1225 private	byte	dmatrix[ DMATRIX_Y ][ DMATRIX_X ] = {
1226 	{
1227 		0x0e, 0x8e, 0x2e, 0xae, 0x06, 0x86, 0x26, 0xa6,
1228 		0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4
1229 	},
1230 	{
1231 		0xce, 0x4e, 0xee, 0x6e, 0xc6, 0x46, 0xe6, 0x66,
1232 		0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64
1233 	},
1234 	{
1235 		0x3e, 0xbe, 0x1e, 0x9e, 0x36, 0xb6, 0x16, 0x96,
1236 		0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94
1237 	},
1238 	{
1239 		0xfe, 0x7e, 0xde, 0x5e, 0xf6, 0x76, 0xd6, 0x56,
1240 		0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54
1241 	},
1242 	{
1243 		0x01, 0x81, 0x21, 0xa1, 0x09, 0x89, 0x29, 0xa9,
1244 		0x03, 0x83, 0x23, 0xa3, 0x0b, 0x8b, 0x2b, 0xab
1245 	},
1246 	{
1247 		0xc1, 0x41, 0xe1, 0x61, 0xc9, 0x49, 0xe9, 0x69,
1248 		0xc3, 0x43, 0xe3, 0x63, 0xcb, 0x4b, 0xeb, 0x6b
1249 	},
1250 	{
1251 		0x31, 0xb1, 0x11, 0x91, 0x39, 0xb9, 0x19, 0x99,
1252 		0x33, 0xb3, 0x13, 0x93, 0x3b, 0xbb, 0x1b, 0x9b
1253 	},
1254 	{
1255 		0xf1, 0x71, 0xd1, 0x51, 0xf9, 0x79, 0xd9, 0x59,
1256 		0xf3, 0x73, 0xd3, 0x53, 0xfb, 0x7b, 0xdb, 0x5b
1257 	},
1258 	{
1259 		0x0d, 0x8d, 0x2d, 0xad, 0x05, 0x85, 0x25, 0xa5,
1260 		0x0f, 0x8f, 0x2f, 0xaf, 0x07, 0x87, 0x27, 0xa7
1261 	},
1262 	{
1263 		0xcd, 0x4d, 0xed, 0x6d, 0xc5, 0x45, 0xe5, 0x65,
1264 		0xcf, 0x4f, 0xef, 0x6f, 0xc7, 0x47, 0xe7, 0x67
1265 	},
1266 	{
1267 		0x3d, 0xbd, 0x1d, 0x9d, 0x35, 0xb5, 0x15, 0x95,
1268 		0x3f, 0xbf, 0x1f, 0x9f, 0x37, 0xb7, 0x17, 0x97
1269 	},
1270 	{
1271 		0xfd, 0x7d, 0xdd, 0x5d, 0xf5, 0x75, 0xd5, 0x55,
1272 		0xff, 0x7f, 0xdf, 0x5f, 0xf7, 0x77, 0xd7, 0x57
1273 	},
1274 	{
1275 		0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa,
1276 		0x01, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8
1277 	},
1278 	{
1279 		0xc2, 0x42, 0xe2, 0x62, 0xca, 0x4a, 0xea, 0x6a,
1280 		0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68
1281 	},
1282 	{
1283 		0x32, 0xb2, 0x12, 0x92, 0x3a, 0xba, 0x1a, 0x9a,
1284 		0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98
1285 	},
1286 	{
1287 		0xf2, 0x72, 0xd2, 0x52, 0xfa, 0x7a, 0xda, 0x5a,
1288 		0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58
1289 	}
1290 };
1291 
1292 /*
1293 *	This is the (minimalistic) colour compensation table
1294 */
1295 
1296 static	CCOMP	ctable[] = {
1297 
1298 	{ -255, -255,   0,   0, 255 },		/* same as green */
1299 	{  102,    0, 255,   0,   0 },		/* cyan */
1300 	{  255,  255, 255, 255,   0 },		/* blue */
1301 	{  560,  512,   0, 255,   0 },		/* magenta */
1302 	{  765,  765,   0, 255, 255 },		/* red */
1303 	{ 1045, 1020,   0,   0, 255 },		/* yellow */
1304 	{ 1275, 1275, 255,   0, 255 },		/* green */
1305 	{ 1632, 1530, 255,   0,   0 }		/* same as cyan */
1306 };
1307 
1308 /*
1309 *	This is the ink transfer function.
1310 *	We use only one for all inks, this may be wrong.
1311 */
1312 
1313 static const unsigned char	xtrans[ 256 ] = {
1314 
1315 	  0,   0,   0,   0,   0,   0,   0,   0,
1316 	  0,   0,   0,   0,   0,   0,   0,   0,
1317 	  0,   0,   0,   0,   0,   0,   0,   0,
1318 	  0,   0,   0,   0,   0,   0,   0,   0,
1319 	  0,   0,   0,   0,   1,   1,   1,   1,
1320 	  1,   1,   1,   1,   1,   1,   1,   1,
1321 	  1,   1,   1,   1,   2,   2,   2,   2,
1322 	  2,   2,   2,   2,   2,   2,   3,   3,
1323 	  3,   3,   3,   3,   3,   4,   4,   4,
1324 	  4,   4,   4,   5,   5,   5,   5,   5,
1325 	  6,   6,   6,   6,   6,   7,   7,   7,
1326 	  7,   8,   8,   8,   8,   9,   9,   9,
1327 	 10,  10,  10,  11,  11,  11,  12,  12,
1328 	 12,  13,  13,  13,  14,  14,  14,  15,
1329 	 15,  16,  16,  17,  17,  17,  18,  18,
1330 	 19,  19,  20,  20,  21,  21,  22,  22,
1331 	 23,  23,  24,  24,  25,  26,  26,  27,
1332 	 27,  28,  29,  29,  30,  30,  31,  32,
1333 	 32,  33,  34,  34,  35,  36,  37,  37,
1334 	 38,  39,  40,  40,  41,  42,  43,  44,
1335 	 44,  45,  46,  47,  48,  49,  50,  51,
1336 	 51,  52,  53,  54,  55,  56,  57,  58,
1337 	 59,  60,  61,  62,  63,  64,  65,  67,
1338 	 68,  69,  70,  71,  72,  73,  74,  76,
1339 	 77,  78,  79,  80,  82,  83,  84,  86,
1340 	 87,  88,  89,  91,  92,  94,  95,  96,
1341 	 98,  99, 101, 102, 103, 105, 106, 108,
1342 	109, 111, 112, 114, 116, 117, 119, 120,
1343 	122, 124, 125, 127, 129, 130, 132, 134,
1344 	136, 137, 139, 141, 143, 145, 146, 148,
1345 	150, 152, 154, 156, 158, 160, 162, 164,
1346 	166, 168, 170, 172, 174, 176, 178, 180
1347 };
1348 
1349 /****************************************************************************/
1350 /*							Device opening									*/
1351 /****************************************************************************/
1352 
photoex_open(DEV * pdev)1353 private int		photoex_open( DEV *pdev )
1354 {
1355 double	height;
1356 double	width;
1357 float	margins[ 4 ];						/* L, B, R, T					*/
1358 
1359 	height = pdev->height / pdev->y_pixels_per_inch;
1360 	width  = pdev->width  / pdev->x_pixels_per_inch;
1361 
1362 	margins[ 0 ] = 0.12;
1363 	margins[ 1 ] = 0.5;
1364 	margins[ 2 ] = 0.12;
1365 	margins[ 3 ] = ( width > 11.46+0.12 ) ? width - (11.46+0.12) : 0.12;
1366 
1367 	gx_device_set_margins( pdev, margins, true );
1368 	return( gdev_prn_open( pdev ) );
1369 }
1370 
1371 /****************************************************************************/
1372 /*							Colour procedures								*/
1373 /****************************************************************************/
1374 
1375 /*
1376 *	Map an RGB colour to device colour.
1377 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1378 *
1379 *	Since we present ourselves to Ghostscript as if we were a
1380 *	full colour resolution RGB device, we calculate the CMYK
1381 *	values and pack them into the result. This depends on
1382 *	color_index being at least 32 bit !!!
1383 */
1384 
photoex_map_rgb_color(DEV * dev,CVAL r,CVAL g,CVAL b)1385 private	CINX	photoex_map_rgb_color( DEV *dev, CVAL r, CVAL g, CVAL b )
1386 {
1387 int		c, y, m, k;
1388 int		a, s, f;
1389 EDEV	*edev;
1390 int		i;
1391 
1392 	edev = (EDEV *) dev;
1393 
1394 	/* White and black are treated on their own */
1395 
1396 	if ( ( r & g & b ) == ( 1 << gx_color_value_bits ) - 1 ) {
1397 
1398 		/* White */
1399 
1400 		return( BUILD_CMYK( 0, 0, 0, 0 ) );
1401 	}
1402 
1403 	if ( ( r | g | b ) == 0 ) {
1404 
1405 		/* Black */
1406 
1407 		return( BUILD_CMYK( 0, 0, 0, xtrans[ 0xff ] ) );
1408 	}
1409 
1410 	/* Map RGB to 8 bit/colour CMY */
1411 
1412 	c = 255 - ( r >> ( gx_color_value_bits - 8 ) );
1413 	m = 255 - ( g >> ( gx_color_value_bits - 8 ) );
1414 	y = 255 - ( b >> ( gx_color_value_bits - 8 ) );
1415 
1416 	k = xtrans[ min( c, min( m, y ) ) ] * 0.8; /* FIXME:empirical constant */
1417 	c -= k;
1418 	m -= k;
1419 	y -= k;
1420 
1421 	s = max ( c, max( y, m ) );
1422 
1423 	/* Map the colour to an angle and find the relevant table range */
1424 
1425 	a = Cmy2A( c, m, y );
1426 	for ( i = 1 ; a > ctable[ i ].ra ; i++ );
1427 
1428 	/* Now map c, m, y. */
1429 
1430 	f = ((a - ctable[ i-1 ].ra) << 16 ) / (ctable[ i ].ra - ctable[ i-1 ].ra);
1431 	c = (( ctable[i-1].c << 16 ) + ( ctable[i].c - ctable[i-1].c ) * f ) >> 16;
1432 	m = (( ctable[i-1].m << 16 ) + ( ctable[i].m - ctable[i-1].m ) * f ) >> 16;
1433 	y = (( ctable[i-1].y << 16 ) + ( ctable[i].y - ctable[i-1].y ) * f ) >> 16;
1434 
1435 	s = xtrans[ s ];
1436 	c = ( c * s ) >> 8;
1437 	m = ( m * s ) >> 8;
1438 	y = ( y * s ) >> 8;
1439 
1440 	return( BUILD_CMYK( c, m, y, k ) );
1441 }
1442 
1443 /*
1444 *	Map a device colour value back to RGB.
1445 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1446 *
1447 *	CAVEAT:
1448 *	This mapping is *not* the inverse of the RGB->CMYK.
1449 *	It does not do any ink transfer compensation, colour compensation etc.
1450 */
1451 
photoex_map_color_rgb(DEV * dev,CINX index,CVAL prgb[3])1452 private int		photoex_map_color_rgb( DEV *dev, CINX index, CVAL prgb[3] )
1453 {
1454 uint	c, m, y, k;
1455 CVAL	r, g, b;
1456 
1457 	/* Let's separate the colours */
1458 
1459 	DECOMPOSE_CMYK( index, c, m, y, k );
1460 
1461 	k = index & 255;
1462 	y = ( index >> 8 ) & 255;
1463 	m = ( index >> 16 ) & 255;
1464 	c = ( index >> 24 ) & 255;
1465 
1466 	/* Depending on whether we use Adobe or Ghostscript mapping,
1467 	   calculate the colours */
1468 
1469 	if ( MAP_RGB_ADOBE ) {
1470 
1471 		r = gx_max_color_value * ( 1.0 - min( 1.0, (c / 255.0 + k / 255.0) ) );
1472 		g = gx_max_color_value * ( 1.0 - min( 1.0, (m / 255.0 + k / 255.0) ) );
1473 		b = gx_max_color_value * ( 1.0 - min( 1.0, (y / 255.0 + k / 255.0) ) );
1474 	}
1475 	else {
1476 
1477 		r = gx_max_color_value * ( 1.0 - c / 255.0 ) * ( 1.0 - k / 255.0);
1478 		g = gx_max_color_value * ( 1.0 - m / 255.0 ) * ( 1.0 - k / 255.0);
1479 		b = gx_max_color_value * ( 1.0 - y / 255.0 ) * ( 1.0 - k / 255.0);
1480 	}
1481 
1482 	prgb[ 0 ] = r;
1483 	prgb[ 1 ] = g;
1484 	prgb[ 2 ] = b;
1485 
1486 	return( 0 );
1487 }
1488 
1489 /*
1490 *	This function maps a (c,m,y) triplet into an angle.
1491 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1492 *
1493 *	Angle:    0 cyan	C=255 M=  0 Y=  0
1494 *			255 blue    C=255 M=255 Y=  0
1495 *			510 magenta	C=  0 M=255 Y=  0
1496 *			765 red     C=  0 M=255 Y=255
1497 *		   1020 yellow	C=  0 M=  0 Y=255
1498 *		   1275 green   C=255 M=  0 Y=255
1499 *		   1530 cyan
1500 */
1501 
Cmy2A(int c,int m,int y)1502 private	int		Cmy2A( int c, int m, int y )
1503 {
1504 int		black;
1505 int		maxim;
1506 int		a;
1507 
1508 	/* Calculate the black level */
1509 
1510 	black = min( c, min( m, y ) );
1511 
1512 	/* Remove the black from the colours themselves */
1513 
1514 	c -= black;
1515 	m -= black;
1516 	y -= black;
1517 
1518 	/* If all 3 remaining colours are 0, then it is a gray: special case */
1519 
1520 	if ( ! c && ! m && ! y ) return( 0 );
1521 
1522 	/* Normalise the colours. At least one at most two of them is 0
1523 	   and at least one at most two of them is 255 */
1524 
1525 	maxim = max( c, max( m, y ) );
1526 
1527 	c = ( 255 * c ) / maxim;
1528 	m = ( 255 * m ) / maxim;
1529 	y = ( 255 * y ) / maxim;
1530 
1531 	if ( c == 255 ) {
1532 
1533 		if ( ! y )
1534 
1535 			a = m;					/* cyan - blue */
1536 		else
1537 			a = 1530 - y;			/* green - cyan */
1538 	}
1539 	else if ( m == 255 ) {
1540 
1541 		if ( ! c )
1542 
1543 			a = 510 + y;			/* magenta - red */
1544 		else
1545 			a = 510 - c;			/* blue - magenta */
1546 	}
1547 	else {
1548 
1549 		if ( ! m )
1550 
1551 			a = 1020 + c;			/* yellow - green */
1552 		else
1553 			a = 1020 - m;			/* red - yellow */
1554 	}
1555 
1556 	return( a );
1557 }
1558 
1559 /****************************************************************************/
1560 /*						Device parameter handling							*/
1561 /****************************************************************************/
1562 
1563 /*
1564 *	Tell Ghostscript all about our extra device parameters
1565 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1566 */
1567 
photoex_get_params(DEV * device,PLIST * plist)1568 private	int		photoex_get_params( DEV *device, PLIST *plist )
1569 {
1570 int		code;
1571 EDEV	*dev;
1572 
1573 	dev  = (EDEV *) device;
1574 
1575 	code = gdev_prn_get_params( device, plist );
1576 
1577 	code = GetInt( plist, "Depletion",	&dev->depletion, code );
1578 	code = GetInt( plist, "Shingling",	&dev->shingling, code );
1579 	code = GetInt( plist, "Render",  	&dev->halftoner, code );
1580 	code = GetInt( plist, "Splash",		&dev->splash,    code );
1581 	code = GetInt( plist, "Leakage",	&dev->leakage,   code );
1582 	code = GetInt( plist, "Binhibit",	&dev->pureblack, code );
1583 	code = GetInt( plist, "DotSize",	&dev->dotsize,	 code );
1584 	return( code );
1585 }
1586 
1587 /*
1588 *	Get all extra device-dependent parameters
1589 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1590 */
1591 
photoex_put_params(DEV * device,PLIST * plist)1592 private	int		photoex_put_params( DEV *device, PLIST *plist )
1593 {
1594 int		code;
1595 EDEV	*dev;
1596 
1597 	dev  = (EDEV *) device;
1598 	code = 0;
1599 
1600 	code = PutInt( plist, "Depletion",	&dev->depletion, 0,		    2, code );
1601 	code = PutInt( plist, "Shingling",	&dev->shingling, 0, 	    2, code );
1602 	code = PutInt( plist, "Render",		&dev->halftoner, 0,MAXHTONE-1, code );
1603 	code = PutInt( plist, "Splash",		&dev->splash,    0,		   50, code );
1604 	code = PutInt( plist, "Leakage",	&dev->leakage,   0,		   25, code );
1605 	code = PutInt( plist, "Binhibit",	&dev->pureblack, 0,		    1, code );
1606 	code = PutInt( plist, "DotSize",	&dev->dotsize,   0,		    4, code );
1607 
1608 	if ( code < 0 )
1609 
1610 		return( code );
1611 	else
1612 		return( gdev_prn_put_params( device, plist ) );
1613 }
1614 
1615 /*
1616 *	Reads a named integer from Ghostscript
1617 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1618 */
1619 
PutInt(PLIST * plist,PNAME name,int * val,int minval,int maxval,int code)1620 private int 	PutInt( PLIST *plist, PNAME name, int *val,
1621 						int minval, int maxval, int code )
1622 {
1623 int		new;
1624 
1625 	/* If code is already an error, we return it and do nothing. */
1626 
1627 	if ( code ) return( code );
1628 
1629 	/* Otherwise we try to read the value */
1630 
1631 	new = *val;
1632 
1633 	switch ( code = param_read_int( plist, name, &new ) ) {
1634 
1635 		case 1:						/* No such parameter defined, it's OK	*/
1636 
1637 			code = 0;
1638 			break;
1639 
1640 		case 0:						/* We have received a value, rangecheck	*/
1641 
1642 			if ( minval > new || new > maxval )
1643 
1644 				param_signal_error( plist, name, gs_error_rangecheck );
1645 			else
1646 				*val = new;
1647 
1648 			break;
1649 
1650 		default:					/* Error								*/
1651 			break;
1652 	}
1653 
1654 	return( code );
1655 }
1656 
1657 /*
1658 *	Writes a named integer to Ghostscript
1659 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1660 */
1661 
GetInt(PLIST * list,PNAME name,int * value,int code)1662 private	int		GetInt( PLIST *list, PNAME name, int *value, int code )
1663 {
1664 	if ( code < 0 ) return( code );
1665 	return( param_write_int( list, name, value ) );
1666 }
1667 
1668 /****************************************************************************/
1669 /*							Page rendering									*/
1670 /****************************************************************************/
1671 
1672 /*
1673 *	This is the function that Ghostscript calls to render a page
1674 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1675 */
1676 
photoex_print_page(PDEV * device,FILE * stream)1677 private	int		photoex_print_page( PDEV *device, FILE *stream )
1678 {
1679 int			pixels;						/* Length of the line 				*/
1680 int			x;							/* Work vars						*/
1681 EDEV		*dev;						/* Our device						*/
1682 RENDER		*render;					/* Rendering info					*/
1683 
1684 int			xres, yres;
1685 int			start, width;
1686 int			unit;
1687 double		psize;
1688 
1689 	dev = (EDEV *) device;
1690 
1691 	/* Check if the resolution is one of the supported ones */
1692 
1693 	yres = (int) dev->y_pixels_per_inch;
1694 	xres = (int) dev->x_pixels_per_inch;
1695 
1696 	if ( ! ( ( xres ==  360 && yres == 360 ) ||
1697 			 ( xres ==  720 && yres == 720 ) ||
1698 			 ( xres == 1440 && yres == 720 ) ) )
1699 
1700 		return( gs_error_rangecheck );
1701 
1702 	pixels = gdev_prn_raster( device ) / sizeof( long );
1703 	psize  = device->height / device->y_pixels_per_inch;
1704 
1705 	/* Check if the requested width is within device limits.
1706 	   The calculations are in 1440 dpi units. */
1707 
1708 	start = 1440.0 * dev_l_margin( device );
1709 
1710 	x = xres == 360 ? 4 : xres == 720 ? 2 : 1;
1711 
1712 	if ( start + x * pixels > 2 * MAX_PIXELS ) {
1713 
1714 		/* We're over the limit, clip width to the required level */
1715 
1716 		width = ( 2 * MAX_PIXELS - start ) / x;
1717 
1718 		/* It is rather inprobable that someone would set up a
1719 		   left margin wider than the printer, still ... */
1720 
1721 		if ( width <= 0 ) return( gs_error_rangecheck );
1722 	}
1723 	else {
1724 
1725 		/* We accept the width as it is */
1726 
1727 		width = pixels;
1728 	}
1729 
1730 	/* Now try to get the memory we need. It's actually quite a lot,
1731 	   since we have to cache 256 processed lines at 6kbyte each plus
1732 	   we need error buffers and stuff. All in all, we'll request
1733 	   about 1.5 ~ 2M. */
1734 
1735 	if ( ! ( render = (RENDER *) gs_malloc( dev->memory, 1, sizeof( RENDER ), "PhotoEX" )))
1736 
1737 		return_error( gs_error_VMerror );
1738 
1739 	if ( ! ( render->dbuff = (byte *) gs_malloc( dev->memory, pixels, sizeof( long ),
1740 			"PhotoEX" ) ) ) {
1741 
1742 		gs_free( dev->memory, render, 1, sizeof( RENDER ), "PhotoEX" );
1743 		return_error( gs_error_VMerror );
1744 	}
1745 
1746 	/* We've done every possible check and preparation, now
1747 	   do the work. Fill the rest of the structure so we can pass
1748 	   it to the actual render routine. */
1749 
1750 	render->dev		= dev;
1751 	render->yres	= yres;
1752 	render->xres	= xres;
1753 	render->width	= width;
1754 	render->lines	= dev->height;
1755 	render->stream	= stream;
1756 	render->mono	= dev->mono;
1757 
1758  	/* Initialise the printer */
1759 
1760 	SendReset( stream );
1761 	SendReset( stream );
1762 	SendGmode( stream, 1 );
1763 
1764 	/* Set up units */
1765 
1766 	unit = ( yres == 360 ) ? 360 : 720;
1767 	SendUnit( stream, RESCODE( unit ) );
1768 
1769 	/* Set up papersize and margins */
1770 
1771 	SendPaper( stream, device->height / device->y_pixels_per_inch * unit );
1772 	SendMargin( stream, ( psize - dev_b_margin( device ) ) * unit,
1773 					    dev_t_margin( device ) * unit );
1774 
1775 	/* Dot size as per user setting */
1776 
1777 	if ( dev->dotsize )
1778 
1779 		SendInk( stream, dev->dotsize );
1780 	else
1781 		SendInk( stream, yres == 360 ? 3 : ( xres == 720 ? 2 : 1 ) );
1782 
1783 	/* Microveawe is off, unidirectional printing on */
1784 
1785 	SendMicro( stream, 0 );
1786 	SendUnidir( stream, 1 );
1787 
1788 	/* Render the page and send image data to printer */
1789 
1790 	RenderPage( render );
1791 
1792 	/* Eject the paper, reset printer */
1793 
1794 	SendByte( stream, FF );
1795 	SendReset( stream );
1796 
1797 	/* Release the memory and return */
1798 
1799 	gs_free( dev->memory, render->dbuff, pixels, sizeof( long ), "PhotoEX" );
1800 	gs_free( dev->memory, render, 1, sizeof( RENDER ), "PhotoEX" );
1801 	return( 0 );
1802 }
1803 
1804 /*
1805 *	Renders a page
1806 *	~~~~~~~~~~~~~~
1807 */
1808 
RenderPage(RENDER * p)1809 private	void	RenderPage( RENDER *p )
1810 {
1811 int		last_done;					/* The last line rendered				*/
1812 int		last_need;					/* The largest line number we need		*/
1813 int		move_down;					/* Amount of delayed head positioning	*/
1814 int		last_band;					/* Indicates the last band				*/
1815 int		min, max;					/* Min/max active bytes in a raw line	*/
1816 int		phase;						/* 1440dpi X weave offset				*/
1817 int		i, j, l, col;
1818 
1819 	p->htone_thold = HalftoneThold( p );
1820 	p->htone_last  = -1 - p->htone_thold;
1821 
1822 	p->schedule.top   = -1;
1823 	p->schedule.resol = p->xres;
1824 	p->schedule.last  = p->lines;
1825 
1826 	last_done = -1;
1827 	move_down = 0;
1828 
1829 	do {
1830 
1831 		/* Schedule the next batch of lines */
1832 
1833 		last_band = ScheduleLines( &p->schedule );
1834 
1835 		/* Find the largest line number we have to process and
1836 		   halftone all lines which have not yet been done */
1837 
1838 		last_need = last_done;
1839 		for ( i = NOZZLES-1 ; i >= 0 && p->schedule.head[ i ] == -1 ; i-- );
1840 		if ( i >= 0 ) last_need = p->schedule.head[ i ];
1841 		while ( last_need > last_done ) RenderLine( p, ++last_done );
1842 
1843 		/* Now loop through the colours and build the data stream */
1844 
1845 		phase = p->schedule.offset;
1846 
1847 		for ( col = 0 ; col < DCOLN ; col++ ) {
1848 
1849 			/* First see if we have to send any data at all */
1850 
1851 			min = MAX_BYTES;
1852 			max = 0;
1853 
1854 			for ( i = 0 ; i < NOZZLES && i < p->schedule.nozzle ; i++ ) {
1855 
1856 				if ( ( j = p->schedule.head[ i ] ) != -1 ) {
1857 
1858 					j %= MAX_MARK;
1859 
1860 					if ( p->raw[ phase ][ col ][ j ].first < min )
1861 
1862 						min = p->raw[ phase ][ col ][ j ].first;
1863 
1864 					if ( p->raw[ phase ][ col ][ j ].last > max )
1865 
1866 						max = p->raw[ phase ][ col ][ j ].last;
1867 				}
1868 			}
1869 
1870 			if ( min <= max ) {
1871 
1872 				max++;
1873 
1874 				/* We have to send data to the printer. If we have
1875 				   to position the head, do so now */
1876 
1877 				if ( move_down ) {
1878 
1879 					SendDown( p->stream, move_down );
1880 					move_down = 0;
1881 				}
1882 
1883 				/* Set the desired colour */
1884 
1885 				SendColour( p->stream, col );
1886 
1887 				/* Move the head to the desired position */
1888 
1889 				if ( p->xres == 360 )
1890 
1891 					SendRight( p->stream, 4 * 8 * min );
1892 
1893 				else if ( p->xres == 720 )
1894 
1895 					SendRight( p->stream, 2 * 8 * min );
1896 				else
1897 					SendRight( p->stream, 8 * min + phase );
1898 
1899 				/* Send the data */
1900 
1901 				SendData( p->stream, p->xres, p->yres, p->schedule.nozzle,
1902 						  ( max-min ) * 8 );
1903 
1904 				for ( i = 0 ; i < p->schedule.nozzle ; i++ ) {
1905 
1906 					if ( ( j = p->schedule.head[ i ] ) == -1 ||
1907 						 ( p->raw[ phase ][ col ][ j % MAX_MARK ].last <
1908 						   p->raw[ phase ][ col ][ j % MAX_MARK ].first ) ) {
1909 
1910 						l = RleCompress( NULL, min, max, p->rle );
1911 					}
1912 					else {
1913 
1914 						l = RleCompress( p->raw[ phase ][ col ] + j % MAX_MARK,
1915 									   min, max, p->rle );
1916 					}
1917 
1918 					fwrite( p->rle, l, 1, p->stream );
1919 				}
1920 
1921 				SendByte( p->stream, CR );
1922 			}
1923 		}
1924 
1925 		/* Note the amount the head should go down before it prints the
1926 		   next band */
1927 
1928 		move_down += p->schedule.down;
1929 
1930 	} while	( ! last_band );
1931 }
1932 
1933 /*
1934 *	Render the the next scanline
1935 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1936 *
1937 *	If it finds a continuous sequence of empty lines, it renders
1938 *	the first htone_thold number of them then stops calling the
1939 *	actual rendering function (which is computationally expensive).
1940 *	When it sees a nonempty line again, it restarts the renderer.
1941 */
1942 
RenderLine(RENDER * p,int line)1943 private	void	RenderLine( RENDER *p, int line )
1944 {
1945 byte	*data;
1946 int		i;
1947 
1948 	/* Get the line from Ghostscript and see if its empty */
1949 
1950 	gdev_prn_get_bits( (PDEV *) p->dev, line, p->dbuff, &data );
1951 
1952 	if ( IsScanlineEmpty( p, data ) ) {
1953 
1954 		if ( line - p->htone_last > p->htone_thold ) {
1955 
1956 			/* The line is empty and is farer from the last nonempty
1957 			   line than the threshold, no need to render it. */
1958 
1959 			for ( i = 0 ; i < DCOLN ; i++ ) {
1960 
1961 				p->raw[ 0 ][ i ][ line % MAX_MARK ].first = MAX_BYTES;
1962 				p->raw[ 0 ][ i ][ line % MAX_MARK ].last  = 0;
1963 				p->raw[ 1 ][ i ][ line % MAX_MARK ].first = MAX_BYTES;
1964 				p->raw[ 1 ][ i ][ line % MAX_MARK ].last  = 0;
1965 
1966 			}
1967 		}
1968 		else {
1969 
1970 			/* The line is empty but it is within the threshold, so we
1971 			   have to render it. We do not move the index, though */
1972 
1973 			HalftoneLine( p, line, data );
1974 		}
1975 	}
1976 	else {
1977 
1978 		/* This line is not empty */
1979 
1980 		if ( line - p->htone_last >= p->htone_thold ) {
1981 
1982 			/* Previous lines were empty and we have already stopped
1983 			   rendering them. We have to restart the renderer */
1984 
1985 			HalftonerStart( p, line );
1986 		}
1987 
1988 		/* Render the line and move the last active index to this line */
1989 
1990 		HalftoneLine( p, line, data );
1991 		p->htone_last = line;
1992 	}
1993 }
1994 
1995 /*
1996 *	This function tests if a scanline is empty
1997 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1998 */
1999 
IsScanlineEmpty(RENDER * r,byte * line)2000 private	int		IsScanlineEmpty( RENDER *r, byte *line )
2001 {
2002 int		i;
2003 long	*p;
2004 
2005 	p = (long *) line;
2006 
2007 	for ( i = 0 ; i < r->width ; i++ ) {
2008 
2009 		if ( *p++ ) return( FALSE );
2010 	}
2011 
2012 	return( TRUE );
2013 }
2014 
2015 /****************************************************************************/
2016 /*						Microweaved line scheduling							*/
2017 /****************************************************************************/
2018 
2019 /*
2020 *	Schedule head data for the next band
2021 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2022 *
2023 *	This function fills the SCHEDUL structure with information
2024 *	about what to print. The head field will contain the line numbers
2025 *	which are assigned to the nozzles in the head. -1 means that
2026 *	no active data is assigned to the nozzle in this band.
2027 *	The offset field is only used for horizontal microweaving, if it
2028 *	is set then the line should be offseted by 1/1440".
2029 *	The down field contains the number of units which the head should
2030 *	move down when printing of the band is finished. Other fields are
2031 *	mainly for the routine's internal use. At the first call, however,
2032 *	the top field should be set to -1, the resol field should be set
2033 *	to 360, 720 or 1440 and the last field should contain the number
2034 *	of lines to print (that is, last + 1 :-).
2035 *
2036 *	The routine returns a flag indicating if this was the last print
2037 *	for the page.
2038 */
2039 
ScheduleLines(SCHEDUL * p)2040 private	int	ScheduleLines( SCHEDUL *p )
2041 {
2042 int		i;
2043 
2044 	if ( p->top == -1 ) {
2045 
2046 		/* First call, init everything, then fall through to the rest */
2047 
2048 		SchedulerInit( p );
2049 	}
2050 
2051 	/* If nozzle is one, just schedule the next line and that's it.
2052 	   You can use this feature for hardware microweave at 720 dpi,
2053 	   the driver uses it for 360 dpi. */
2054 
2055 	if ( p->nozzle == 1 ) {
2056 
2057 		p->head[ 0 ] = p->top;
2058 		p->down = 1;
2059 		p->top++;
2060 		return( p->top == p->last );
2061 	}
2062 
2063 	/* Release all expired entries in the mark array */
2064 
2065 	for ( i = p->markbeg ; i < p->top ; i++ ) p->mark[ i % MAX_MARK ] = 0;
2066 	p->markbeg = p->top;
2067 
2068 	/* If top is less than the the head spacing, then create the image
2069 	   by single steps. This will cause banding on the very top, but
2070 	   there's nothing we can do about it. We're still better than
2071 	   Epson's driver which simply ignores the first few lines,
2072 	   it does not even try to schedule them ... */
2073 
2074 	if ( p->top < HEAD_SPACING ) {
2075 
2076 		ScheduleLeading( p );
2077 		return( FALSE );
2078 	}
2079 
2080 	/* See if we are almost at the end. If yes, we will advance line by
2081 	   line. */
2082 
2083 	if ( p->top + p->resol + (NOZZLES) * HEAD_SPACING > p->last ) {
2084 
2085  		ScheduleTrailing( p );
2086 
2087 		if ( p->down )
2088 
2089 			return( p->top + (NOZZLES-1) * HEAD_SPACING >= p->last );
2090 		else
2091 			return( FALSE );
2092 	}
2093 
2094 	/* Otherwise we're in the middle of the page, just do the
2095 	   simple banding and selecting as many lines as we can. */
2096 
2097 	ScheduleMiddle( p );
2098 	return( FALSE );
2099 }
2100 
2101 /*
2102 *	Initialise the scheduler
2103 *	~~~~~~~~~~~~~~~~~~~~~~~~
2104 */
2105 
SchedulerInit(SCHEDUL * p)2106 private	void	SchedulerInit( SCHEDUL *p )
2107 {
2108 int		i;
2109 
2110 	p->top = 0;
2111 
2112 	switch ( p->resol ) {
2113 
2114 		case 360:
2115 			p->offset = 0;
2116 			p->resol  = BAND_360;
2117 			p->nozzle = NOZZLE_360;
2118 			break;
2119 
2120 		case 720:
2121 			p->offset = 0;
2122 			p->resol  = BAND_720;
2123 			p->nozzle = NOZZLE_720;
2124 			break;
2125 
2126 		case 1440:
2127 			p->offset = 1;			/* Need to be set for the algorithm! */
2128 			p->resol  = BAND_1440;
2129 			p->nozzle = NOZZLE_1440;
2130 			break;
2131 	}
2132 
2133 	for ( i = 0 ; i < NOZZLES  ; i++ ) p->head[ i ] = -1;
2134 	for ( i = 0 ; i < MAX_MARK ; i++ ) p->mark[ i ] = 0;
2135 	p->markbeg = 0;
2136 }
2137 
2138 /*
2139 *	Scheduling the first BAND lines for the image
2140 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2141 */
2142 
ScheduleLeading(SCHEDUL * p)2143 private	void	ScheduleLeading( SCHEDUL *p )
2144 {
2145 int		i;
2146 
2147 	if ( p->resol == BAND_720 ) {
2148 
2149 		/* Copy the line scheduling data to the struct */
2150 
2151 		memcpy( p->head, start_720[ p->top ], sizeof( int ) * NOZZLES );
2152 
2153 		/* Mark all lines to be set */
2154 
2155 		for ( i = 0 ; i < NOZZLES ; i++ )
2156 
2157 			if ( p->head[ i ] != -1 )
2158 
2159 				p->mark[ p->head[ i ] % MAX_MARK ] = 1;
2160 
2161 		/* We move down by one line except at the end */
2162 
2163 		if ( p->top == HEAD_SPACING - 1 ) {
2164 
2165 			p->down = BAND_720 - p->top;
2166 			p->top  = BAND_720;
2167 		}
2168 		else {
2169 
2170 			p->down = 1;
2171 			p->top++;
2172 		}
2173 	}
2174 	else {
2175 
2176 		/* 1440 dpi version, two passes needed for each scanline */
2177 
2178 		if ( p->offset ) {
2179 
2180 			/* Copy the non-offseted scheduling data to the struct */
2181 
2182 			memcpy( p->head, start_1440[0][p->top], sizeof( int ) * NOZZLES );
2183 
2184 			/* Mark all lines to be set */
2185 
2186 			for ( i = 0 ; i < NOZZLES ; i++ )
2187 
2188 				if ( p->head[ i ] != -1 )
2189 
2190 					p->mark[ p->head[ i ] % MAX_MARK ] = 1;
2191 
2192 			/* This is the non-offseted line, do not move ! */
2193 
2194 			p->offset = 0;
2195 			p->down = 0;
2196 		}
2197 		else {
2198 
2199 			/* Copy the non-offseted schduling data to the struct */
2200 
2201 			memcpy( p->head, start_1440[1][p->top], sizeof( int ) * NOZZLES );
2202 
2203 			/* Mark all lines to be set */
2204 
2205 			for ( i = 0 ; i < NOZZLES ; i++ )
2206 
2207 				if ( p->head[ i ] != -1 )
2208 
2209 					p->mark[ p->head[ i ] % MAX_MARK ] |= 2;
2210 
2211 			/* We move down by one line except at the end and set offset */
2212 
2213 			if ( p->top == HEAD_SPACING - 1 ) {
2214 
2215 				p->down = BAND_1440 - p->top;
2216 				p->top  = BAND_1440;
2217 			}
2218 			else {
2219 
2220 				p->down = 1;
2221 				p->top++;
2222 			}
2223 
2224 			p->offset = 1;
2225 		}
2226 	}
2227 }
2228 
2229 /*
2230 *	Scheduling the bulk of the image
2231 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2232 */
2233 
ScheduleMiddle(SCHEDUL * p)2234 private	void	ScheduleMiddle( SCHEDUL *p )
2235 {
2236 int		ph0, ph1;
2237 int		line, mask;
2238 int		i;
2239 
2240 	if ( p->resol == BAND_720 ) {
2241 
2242 		/* 720 DPI printing. See which lines should we print and
2243 		   fill the head array accordingly, then move down a band. */
2244 
2245 		ScheduleBand( p, 1 );
2246 		p->down = BAND_720;
2247 		p->top += BAND_720;
2248 	}
2249 	else {
2250 
2251 		/* 1440 dpi printing. This is a bit more complex than the
2252 		   720 dpi one. First, see how many lines in each phase
2253 		   has already been printed. */
2254 
2255 		ph0 = ph1 = 0;
2256 
2257 		for ( line = p->top, i=0 ; i < NOZZLES ; i++, line += HEAD_SPACING ) {
2258 
2259 			line = p->top + i * HEAD_SPACING;
2260 			ph0 += p->mark[ line % MAX_MARK ] & 1;
2261 			ph1 += p->mark[ line % MAX_MARK ] & 2;
2262 		}
2263 
2264 		ph1 >>= 1;
2265 
2266 		/* Choose the phase which has less lines in it. */
2267 
2268 		if ( ph0 <= ph1 ) {
2269 
2270 			p->offset = 0;
2271 			mask = 1;
2272 		}
2273 		else {
2274 
2275 			p->offset = 1;
2276 			mask = 2;
2277 		}
2278 
2279 		/* Fill the line array and mark the phase.
2280 		   We should check here if moving down the head will leave
2281 		   any line empty, but we do not because we *know* that it
2282 		   won't - the BAND_1440 is selected by finding a value
2283 		   which guarantees that it will cover every line. */
2284 
2285 		ScheduleBand( p, mask );
2286 		p->down = BAND_1440;
2287 		p->top += BAND_1440;
2288 	}
2289 }
2290 
2291 /*
2292 *	Scheduling the last lines of the image
2293 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2294 */
2295 
ScheduleTrailing(SCHEDUL * p)2296 private	void	ScheduleTrailing( SCHEDUL *p )
2297 {
2298 int		mask;
2299 
2300 	if ( p->down > 1 ) {
2301 
2302 		/* This is the first time we came here. */
2303 
2304 		p->offset = 1;
2305 	}
2306 
2307 	if ( p->resol == BAND_720 ) {
2308 
2309 		p->offset = 0;
2310 		p->down   = 1;
2311 		mask	  = 1;
2312 	}
2313 	else {
2314 
2315 		if ( p->offset ) {
2316 
2317 			p->offset = 0;
2318 			p->down	  = 0;
2319 			mask	  = 1;
2320 		}
2321 		else {
2322 
2323 			p->offset = 1;
2324 			p->down	  = 1;
2325 			mask	  = 2;
2326 		}
2327 	}
2328 
2329 	ScheduleBand( p, mask );
2330 	p->top += p->down;
2331 }
2332 
2333 /*
2334 *	Select lines from a given set
2335 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2336 */
2337 
ScheduleBand(SCHEDUL * p,int mask)2338 private	void	ScheduleBand( SCHEDUL *p, int mask )
2339 {
2340 int		i;
2341 int		line;
2342 
2343 	for ( line = p->top, i = 0 ; i < NOZZLES ; i++, line += HEAD_SPACING ) {
2344 
2345 
2346 		if ( p->mark[ line % MAX_MARK ] & mask ) {
2347 
2348 			p->head[ i ] = -1;
2349 		}
2350 		else {
2351 
2352 			p->head[ i ] = line;
2353 			p->mark[ line % MAX_MARK ] |= mask;
2354 		}
2355 	}
2356 }
2357 
2358 /****************************************************************************/
2359 /*						Formatting printer data								*/
2360 /****************************************************************************/
2361 
2362 /*
2363 *	Packs a line to raw device format
2364 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2365 *
2366 *	Reads pixnum pixels and if the pixel is lev_on, then sets the
2367 *	appropriate bit in the resulting datastream. The length of the
2368 *	result is pixnum/8 (rounded up).
2369 */
2370 
PackLine(byte * input,int pixnum,int lev_on,int step,RAWLINE * line)2371 private	void	PackLine( byte *input, int pixnum, int lev_on, int step,
2372 						  RAWLINE *line )
2373 {
2374 byte	bits;
2375 char	*result;
2376 int		i, j, k;
2377 
2378 	result = line->data;
2379 	line->first = MAX_PIXELS;
2380 	line->last  = 0;
2381 
2382 	for ( j = 0x80, bits = k = i = 0 ; i < pixnum ; i += step, input += step ){
2383 
2384 		if ( *input == lev_on ) bits |= j;
2385 
2386 		if ( ! ( j >>= 1 ) ) {
2387 
2388 			if ( bits ) {
2389 
2390 				if ( line->first > k ) line->first = k;
2391 				if ( line->last  < k ) line->last  = k;
2392 			}
2393 
2394 			*result++ = bits;
2395 			j		  = 0x80;
2396 			bits	  = 0;
2397 			k++;
2398 		}
2399 	}
2400 
2401 	if ( j != 0x80 ) {
2402 
2403 		*result = bits;
2404 
2405 		if ( bits ) {
2406 
2407 			if ( line->first > k ) line->first = k;
2408 			if ( line->last  < k ) line->last  = k;
2409 		}
2410 	}
2411 }
2412 
2413 /*
2414 *	Compresses (run-length encodes) a line
2415 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2416 *
2417 *	Returns the length of the RLE data.
2418 */
2419 
RleCompress(RAWLINE * raw,int min,int max,byte * rle_data)2420 private	int		RleCompress( RAWLINE *raw, int min, int max, byte *rle_data )
2421 {
2422 int		i, n;
2423 byte	pbyte;
2424 byte	*start, *rstrt;
2425 int		length;
2426 byte	*input;
2427 int 	len;
2428 
2429 	if ( ! raw ) {
2430 
2431 		/* This is an empty line */
2432 
2433 		for ( n = 0, i = max - min ; i >= 129 ; i -= 129 ) {
2434 
2435 			*rle_data++ = 128;
2436 			*rle_data++ = 0;
2437 			n += 2;
2438 		}
2439 
2440 		if ( i >= 2 ) {
2441 
2442 			*rle_data++ = 257 - i;
2443 			*rle_data++ = 0;
2444 			n += 2;
2445 		}
2446 		else if ( i ) {
2447 
2448 			*rle_data++ = 0;
2449 			*rle_data++ = 0;
2450 			n+= 2;
2451 		}
2452 
2453 		return( n );
2454 	}
2455 
2456 	/* There's data, set up encoding parameters */
2457 
2458 	input = raw->data + min;
2459 	len   = max - min;
2460 
2461 	/* Create a run-length encoded version. We do it even if no pixel
2462 	   was set because it may be that this line is just part of a
2463 	   multi-line band. */
2464 
2465 	length = 0;
2466 	start  = input;
2467 	rstrt  = NULL;
2468 	pbyte  = *input++;
2469 
2470 	for ( i = 1 ; i < len ; i++, input++ ) {
2471 
2472 		if ( *input == pbyte ) {
2473 
2474 			/* This byte is identical to the previous one(s). */
2475 
2476 			if ( ! rstrt ) {
2477 
2478 				/* This is the start of a new repeating sequence */
2479 
2480 				rstrt = input - 1;
2481 			}
2482 		}
2483 		else {
2484 
2485 			/* Different byte than the previous one(s) */
2486 
2487 			if ( rstrt ) {
2488 
2489 				/* There was a repetitive sequence. */
2490 
2491 				if ( rstrt - input < 4 ) {
2492 
2493 					/* For less than four bytes it isn't worth
2494 					   to do RLE, we discard them */
2495 
2496 					rstrt = NULL;
2497 				}
2498 				else {
2499 
2500 					/* We must flush */
2501 
2502 					n = RleFlush( start, rstrt, input, rle_data );
2503 					rle_data  += n;
2504 					length += n;
2505 
2506 					/* Initialise again */
2507 
2508 					start = rle_data;
2509 					rstrt = NULL;
2510 				}
2511 			}
2512 
2513 			pbyte = *rle_data;
2514 		}
2515 	}
2516 
2517 	/* We flush whatever is left over */
2518 
2519 	length += RleFlush( start, rstrt, input, rle_data );
2520 
2521 	return( length );
2522 }
2523 
2524 /*
2525 *	This function flushes the RLE encoding buffer
2526 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2527 *
2528 *	Assumes that it gets a nonrepetitive pattern followed by a repetitive
2529 *	one. 'first' points to the start of the non-repetitive part.
2530 *	'reps' points to the first byte in the repetitive sequence or it
2531 *	may be NULL, if there were no repetitve bytes. 'now' points to
2532 *	one after the last byte in the sequence.
2533 *	It puts the result into 'out' and returns the number of bytes
2534 *	written out.
2535 *
2536 *	There is one possible performance penalty in using this method:
2537 *	If the repetitive sequence is n*128+1 byte long, then the last
2538 *	byte will be written out as single byte. If the following sequence
2539 *	has a nonrepetitive start, this byte could be combined into that
2540 *	but it isn't. This can cause some penalty, however, we will live
2541 *	with that for now.
2542 */
2543 
RleFlush(byte * first,byte * reps,byte * now,byte * out)2544 private	int		RleFlush( byte *first, byte *reps, byte *now, byte *out )
2545 {
2546 int		count;
2547 int		l;
2548 
2549 	if ( ! first ) return( 0 );
2550 
2551 	if ( ! reps ) reps = now;
2552 
2553 	count = 0;
2554 
2555 	/* Write the nonrepetitve pattern first */
2556 
2557 	while ( ( l = reps - first ) ) {
2558 
2559 		if ( l > 128 ) {
2560 
2561 			/* More than 128 consecutive bytes, write out a 128 byte chunk */
2562 
2563 			*out++ = 127;
2564 			memcpy( out, first, 128 );
2565 			out   += 128;
2566 			first += 128;
2567 			count += 129;
2568 		}
2569 		else {
2570 
2571 			/* There are not more than 128 bytes, write them into a
2572 			   single chunk */
2573 
2574 			*out++ = l - 1;
2575 			memcpy( out, first, l );
2576 			count += l + 1;
2577 			first += l;
2578 			out   += l;
2579 		}
2580 	}
2581 
2582 	/* Now write the repeated pattern */
2583 
2584 	while ( ( l = now - reps ) ) {
2585 
2586 		if ( l > 128 ) {
2587 
2588 			/* More than 128 bytes are identical, write out a
2589 			   129 byte chunk */
2590 
2591 			*out++ = 128;
2592 			*out++ = *reps;
2593 			count += 2;
2594 			reps  += 129;
2595 		}
2596 		else {
2597 
2598 			if ( l == 1 ) {
2599 
2600 				/* There is only one byte left, write it out as a
2601 				   nonrepetitive chunk */
2602 
2603 				*out++ = 0;
2604 				*out++ = *reps;
2605 				count += 2;
2606 				reps++;
2607 			}
2608 			else {
2609 
2610 				/* What remains is at least 2 bytes but not larger than what
2611 				   can be written in a single chunk */
2612 
2613 				*out++ = 257 - l;
2614 				*out++ = *reps;
2615 				count += 2;
2616 				reps   = now;
2617 			}
2618 		}
2619 	}
2620 
2621 	return( count );
2622 }
2623 
2624 /****************************************************************************/
2625 /*		Low level procedures to send various commands to the printer		*/
2626 /****************************************************************************/
2627 
SendReset(FILE * stream)2628 private	void	SendReset( FILE *stream )
2629 {
2630 	SendString( stream, ESC "@" );
2631 }
2632 
SendMargin(FILE * stream,int top,int bot)2633 private	void	SendMargin( FILE *stream, int top, int bot )
2634 {
2635 	SendString( stream, ESC "(c" );
2636 	SendWord( stream, 4 );
2637 	SendWord( stream, bot );
2638 	SendWord( stream, top );
2639 }
2640 
SendPaper(FILE * stream,int length)2641 private	void	SendPaper( FILE *stream, int length )
2642 {
2643 	SendString( stream, ESC "(C" );
2644 	SendWord( stream, 2 );
2645 	SendWord( stream, length );
2646 }
2647 
SendGmode(FILE * stream,int on)2648 private	void	SendGmode( FILE *stream, int on )
2649 {
2650 	SendString( stream, ESC "(G" );
2651 	SendWord( stream, 1 );
2652 	SendByte( stream, on );
2653 }
2654 
SendUnit(FILE * stream,int res)2655 private void	SendUnit( FILE *stream, int res )
2656 {
2657 	SendString( stream, ESC "(U" );
2658 	SendWord( stream, 1 );
2659 	SendByte( stream, res );
2660 }
2661 
SendUnidir(FILE * stream,int on)2662 private	void	SendUnidir( FILE *stream, int on )
2663 {
2664 	SendString( stream, ESC "U" );
2665 	SendByte( stream, on );
2666 }
2667 
SendMicro(FILE * stream,int on)2668 private	void	SendMicro( FILE *stream, int on )
2669 {
2670 	SendString( stream, ESC "(i" );
2671 	SendWord( stream, 1 );
2672 	SendByte( stream, on );
2673 }
2674 
SendInk(FILE * stream,int x)2675 private void	SendInk( FILE *stream, int x )
2676 {
2677 	SendString( stream, ESC "(e" );
2678 	SendWord( stream, 2 );
2679 	SendByte( stream, 0 );
2680 	SendByte( stream, x );
2681 }
2682 
SendDown(FILE * stream,int x)2683 private	void	SendDown( FILE *stream, int x )
2684 {
2685 	SendString( stream, ESC "(v" );
2686 	SendWord( stream, 2 );
2687 	SendWord( stream, x );
2688 }
2689 
SendRight(FILE * stream,int amount)2690 private	void	SendRight( FILE *stream, int amount )
2691 {
2692 	SendString( stream, ESC "(\\" );
2693 	SendWord( stream, 4 );
2694 	SendWord( stream, 1440 );
2695 	SendWord( stream, amount );
2696 }
2697 
SendColour(FILE * stream,int col)2698 private	void	SendColour( FILE *stream, int col )
2699 {
2700 static	int	ccode[] = { 0x000, 0x200, 0x100, 0x400, 0x201, 0x101 };
2701 
2702 	SendString( stream, ESC "(r" );
2703 	SendWord( stream, 2 );
2704 	SendWord( stream, ccode[ col ] );
2705 }
2706 
SendData(FILE * stream,int hres,int vres,int noz,int col)2707 private void	SendData( FILE *stream, int hres, int vres, int noz, int col )
2708 {
2709 	SendString( stream, ESC "." );
2710 	SendByte( stream, 1 );				/* Run-length encoded data */
2711 
2712 	/* If we use 1 nozzle, then vertical resolution is what it is.
2713 	   Otherwise it must be set to 90 dpi */
2714 
2715 	if ( noz == 1 )
2716 
2717 		SendByte( stream, RESCODE( vres ) );
2718 	else
2719 		SendByte( stream, RESCODE( 90 ) );
2720 
2721 	/* The horizontal resolution is max. 720 dpi */
2722 
2723 	if ( hres > 720 )
2724 
2725 		SendByte( stream, RESCODE( 720 ) );
2726 	else
2727 		SendByte( stream, RESCODE( hres ) );
2728 
2729 	SendByte( stream, noz );
2730 	SendWord( stream, col );
2731 }
2732 
SendString(FILE * stream,const char * s)2733 private	void	SendString( FILE *stream, const char *s )
2734 {
2735 	while ( *s ) SendByte( stream, *s++ );
2736 }
2737 
2738 /****************************************************************************/
2739 /*					Halftoning wrapper functions							*/
2740 /****************************************************************************/
2741 
2742 /*
2743 *	Calls the start function of the choosen halftoner
2744 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2745 */
2746 
HalftonerStart(RENDER * render,int line)2747 private	void	HalftonerStart( RENDER *render, int line )
2748 {
2749 	(*(htable[ render->dev->halftoner ].hstrt))( render, line );
2750 }
2751 
2752 /*
2753 *	Returns the restart threshold for the given halftoner
2754 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2755 */
2756 
HalftoneThold(RENDER * render)2757 private	int		HalftoneThold( RENDER *render )
2758 {
2759 	return( (*(htable[ render->dev->halftoner ].hthld))( render ) );
2760 }
2761 
2762 /*
2763 *	This function renders a line
2764 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2765 *
2766 *	This function has one fundamental assumption: halftoning of separate
2767 *	colours is independent of each other.
2768 *
2769 *	It calls the mono halftoner with the K, C, M, Y components.
2770 */
2771 
HalftoneLine(RENDER * render,int line,byte * data)2772 private	void	HalftoneLine( RENDER *render, int line, byte *data )
2773 {
2774 void		(*htone)( HTONE *, int );
2775 EDEV		*dev;
2776 int			offs;
2777 HTONE		hdata;
2778 short		*errs[ MAX_ED_LINES ];
2779 int			i;
2780 
2781 	/* Get the rendering function */
2782 
2783 	dev   = render->dev;
2784 	htone = htable[ render->dev->halftoner ].htone;
2785 	offs  = render->mono ? 0 : OFFS_K;
2786 
2787 	if ( dev->mono ) {
2788 
2789 		/* Monochrome, do only the black */
2790 
2791 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
2792 
2793 			errs[ i ] = render->error[ i ][ OFFS_K ];
2794 
2795 		hdata.render = render;
2796 		hdata.data   = data + OFFS_K;
2797 		hdata.step	 = sizeof( byte );
2798 		hdata.res	 = render->res[ OFFS_K ];
2799 		hdata.block  = NULL;
2800 		hdata.err	 = errs;
2801 		hdata.mval	 = 255;
2802 
2803 		(*htone)( &hdata, line );
2804 	}
2805 	else {
2806 
2807 		/* Colour. D black first */
2808 
2809 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
2810 
2811 			errs[ i ] = render->error[ i ][ OFFS_K ];
2812 
2813 		hdata.render = render;
2814 		hdata.step	 = sizeof( long );
2815 		hdata.data   = data + OFFS_K;
2816 		hdata.res	 = render->res[ OFFS_K ];
2817 		hdata.block  = NULL;
2818 		hdata.err	 = errs;
2819 		hdata.mval	 = 255;
2820 
2821 		(*htone)( &hdata, line );
2822 
2823 		/* Yellow has no intermediate ink. The already done black
2824 		   may inhibit it. */
2825 
2826 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
2827 
2828 			errs[ i ] = render->error[ i ][ OFFS_Y ];
2829 
2830 		hdata.render = render;
2831 		hdata.step	 = sizeof( long );
2832 		hdata.data   = data + OFFS_Y;
2833 		hdata.res	 = render->res[ OFFS_Y ];
2834 		hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
2835 		hdata.err	 = errs;
2836 		hdata.mval	 = 255;
2837 
2838 		(*htone)( &hdata, line );
2839 
2840 		/* Cyan and magenta has intermediate colour ink, black may inhibit */
2841 
2842 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
2843 
2844 			errs[ i ] = render->error[ i ][ OFFS_C ];
2845 
2846 		hdata.data   = data + OFFS_C;
2847 		hdata.res	 = render->res[ OFFS_C ];
2848 		hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
2849 		hdata.mval	 = dev->midcyan;
2850 
2851 		(*htone)( &hdata, line );
2852 
2853 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
2854 
2855 			errs[ i ] = render->error[ i ][ OFFS_M ];
2856 
2857 		hdata.data   = data + OFFS_M;
2858 		hdata.res	 = render->res[ OFFS_M ];
2859 		hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
2860 		hdata.mval	 = dev->midmagenta;
2861 
2862 		(*htone)( &hdata, line );
2863 	}
2864 
2865 	/* Here we have create the raw device format scanlines */
2866 
2867 	if ( dev->mono ) {
2868 
2869 		if ( render->xres == 1440 ) {
2870 
2871 			PackLine( render->res[ OFFS_K ], render->width, 255, 2,
2872 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
2873 
2874 			PackLine( render->res[ OFFS_K ]+1, render->width-1, 255, 2,
2875 					  render->raw[ 1 ][ DEV_BLACK ]+ line % MAX_MARK );
2876 		}
2877 		else {
2878 
2879 			PackLine( render->res[ OFFS_K ], render->width, 255, 1,
2880 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
2881 		}
2882 	}
2883 	else {
2884 
2885 		if ( render->xres == 1440 ) {
2886 
2887 			PackLine( render->res[ OFFS_K ], render->width, 255, 2,
2888 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
2889 
2890 			PackLine( render->res[ OFFS_K ]+1, render->width-1, 255, 2,
2891 					  render->raw[ 1 ][ DEV_BLACK ]+ line % MAX_MARK );
2892 
2893 			PackLine( render->res[ OFFS_C ], render->width, 255, 2,
2894 					  render->raw[ 0 ][ DEV_CYAN ]+ line % MAX_MARK );
2895 
2896 			PackLine( render->res[ OFFS_C ]+1, render->width-1, 255, 2,
2897 					  render->raw[ 1 ][ DEV_CYAN ]+ line % MAX_MARK );
2898 
2899 			PackLine( render->res[ OFFS_M ], render->width, 255, 2,
2900 					  render->raw[ 0 ][ DEV_MAGENTA ]+ line % MAX_MARK);
2901 
2902 			PackLine( render->res[ OFFS_M ]+1, render->width-1, 255, 2,
2903 					  render->raw[ 1 ][ DEV_MAGENTA ]+ line % MAX_MARK);
2904 
2905 			PackLine( render->res[ OFFS_Y ], render->width, 255, 2,
2906 					  render->raw[ 0 ][ DEV_YELLOW ]+ line % MAX_MARK );
2907 
2908 			PackLine( render->res[ OFFS_Y ]+1, render->width-1, 255, 2,
2909 					  render->raw[ 1 ][ DEV_YELLOW ]+ line % MAX_MARK );
2910 
2911 			PackLine( render->res[ OFFS_C ], render->width, dev->midcyan,
2912 					  2, render->raw[ 0 ][ DEV_LCYAN ]+ line % MAX_MARK );
2913 
2914 			PackLine( render->res[ OFFS_C ]+1, render->width-1, dev->midcyan,
2915 					  2, render->raw[ 1 ][ DEV_LCYAN ]+ line % MAX_MARK );
2916 
2917 			PackLine( render->res[ OFFS_M ], render->width, dev->midmagenta,
2918 					  2, render->raw[0][ DEV_LMAGENTA ]+ line % MAX_MARK );
2919 
2920 			PackLine( render->res[ OFFS_M ]+1, render->width-1,dev->midmagenta,
2921 					  2, render->raw[1][ DEV_LMAGENTA ]+ line % MAX_MARK );
2922 		}
2923 		else {
2924 
2925 			PackLine( render->res[ OFFS_K ], render->width, 255, 1,
2926 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
2927 
2928 			PackLine( render->res[ OFFS_C ], render->width, 255, 1,
2929 					  render->raw[ 0 ][ DEV_CYAN ]+ line % MAX_MARK );
2930 
2931 			PackLine( render->res[ OFFS_M ], render->width, 255, 1,
2932 					  render->raw[ 0 ][ DEV_MAGENTA ]+ line % MAX_MARK);
2933 
2934 			PackLine( render->res[ OFFS_Y ], render->width, 255, 1,
2935 					  render->raw[ 0 ][ DEV_YELLOW ]+ line % MAX_MARK );
2936 
2937 			PackLine( render->res[ OFFS_C ], render->width, dev->midcyan,
2938 					  1, render->raw[ 0 ][ DEV_LCYAN ]+ line % MAX_MARK );
2939 
2940 			PackLine( render->res[ OFFS_M ], render->width, dev->midmagenta,
2941 					  1, render->raw[0][ DEV_LMAGENTA ]+ line % MAX_MARK );
2942 		}
2943 	}
2944 
2945 	/* Call the halftoner specific end-of-line function */
2946 
2947 	(*htable[ render->dev->halftoner ].hteol)( render, line );
2948 }
2949 
2950 /****************************************************************************/
2951 /*					Floyd - Steinberg error diffusion						*/
2952 /****************************************************************************/
2953 
2954 /*
2955 *	This function returns the empty range threshold
2956 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2957 */
2958 
FloydSThold(RENDER * p)2959 private	int		FloydSThold( RENDER *p )
2960 {
2961 	return( 5 );
2962 }
2963 
2964 /*
2965 *	This function initialises the halftoner
2966 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2967 */
2968 
FloydSStart(RENDER * p,int line)2969 private	void	FloydSStart( RENDER *p, int line )
2970 {
2971 	memset( p->err, 0, ICOLN * MAX_PIXELS*2 );
2972 	p->error[ 0 ] = p->err[ 0 ];
2973 }
2974 
2975 /*
2976 *	This function does the end-of-line processing
2977 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2978 */
2979 
FloydSEol(RENDER * p,int line)2980 private	void	FloydSEol( RENDER *p, int line )
2981 {
2982 	/* Since we use single error buffering, nothing to do */
2983 }
2984 
2985 /*
2986 *	This is the classical Floyd-Steinberg error diffusion.
2987 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2988 *
2989 *	The matrix is the following:
2990 *
2991 *          *    7/16	r
2992 *   3/16  5/16  1/16
2993 *
2994 *	r is the residual (0, in theory).
2995 *	Absolutely nothing fancy is done here.
2996 *
2997 */
2998 
FloydSLine(HTONE * htone,int y)2999 private	void   FloydSLine( HTONE *htone, int y )
3000 {
3001 int		x;							/* Counts the pixels					*/
3002 int		pixel;						/* Current pixel value					*/
3003 int		pixerr;						/* Error value							*/
3004 int		length;						/* Number of pixels to process			*/
3005 byte	*res;						/* Result								*/
3006 byte	*data;						/* Input data							*/
3007 byte	*block;						/* Block pixel							*/
3008 int		lim1, lim2;					/* Limits								*/
3009 short	e0, e1;						/* Propagating errors in current line	*/
3010 short	*l0;						/* Error buffer pointer					*/
3011 
3012 	length  = htone->render->width;
3013 
3014 	res		= htone->res;
3015 	data	= htone->data;
3016 	block	= htone->block;
3017 
3018 	lim1	= htone->mval / 2;
3019 	lim2	= ( htone->mval + 256 ) / 2;
3020 
3021 	l0		= htone->err[ 0 ];
3022 
3023 	e0		= l0[ 1 ];
3024 	e1		= l0[ 2 ];
3025 
3026 	l0[ 1 ] = 0;
3027 	l0[ 2 ] = 0;
3028 
3029 	for ( x = 0 ; x < length ; x++ ) {
3030 
3031 		/* First, clear the res byte. It is needed for the black */
3032 
3033 		*res = 0;
3034 
3035 		/* Add the actual error to the pixel, normalise, init, whatever. */
3036 
3037 		pixel = ( ( *data << 4 ) + e0 );
3038 		e0 = e1;
3039 		e1 = l0[ 3 ] + ( pixel & 15 );			/* This is the residual */
3040 
3041 		l0[ 3 ] = 0;
3042 		pixel >>= 4;
3043 
3044 		if ( ( block && *block ) || ( pixel < lim1 ) )
3045 
3046 			*res = 0;
3047 
3048 		else if ( pixel >= lim2 )
3049 
3050 			*res = 255;
3051 		else
3052 			*res = htone->mval;
3053 
3054 		/* Calculate the err */
3055 
3056 		pixerr = pixel - *res;
3057 
3058 		/* Diffuse the err */
3059 
3060 		e0		+= ( pixerr << 3 ) - pixerr;	/* 7/16		*/
3061 		l0[ 0 ] += ( pixerr << 2 ) - pixerr;	/* 3/16		*/
3062 		l0[ 1 ] += ( pixerr << 2 ) + pixerr;	/* 5/16		*/
3063 		l0[ 2 ] += pixerr;						/* 1/16		*/
3064 
3065 		/* We have done everything, move the pointers */
3066 
3067 		res++;
3068 		if ( block ) block++;
3069 		data += htone->step;
3070 		l0++;
3071 	}
3072 }
3073 
3074 /****************************************************************************/
3075 /*							Ordered dither									*/
3076 /****************************************************************************/
3077 
3078 /*
3079 *	This function returns the empty range threshold
3080 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3081 */
3082 
DitherThold(RENDER * p)3083 private	int		DitherThold( RENDER *p )
3084 {
3085 	return( 0 );
3086 }
3087 
3088 /*
3089 *	This function initialises the halftoner
3090 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3091 */
3092 
DitherStart(RENDER * p,int line)3093 private	void	DitherStart( RENDER *p, int line )
3094 {
3095 	/* Nothing to initialise */
3096 }
3097 
3098 /*
3099 *	This function does the end-of-line processing
3100 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3101 */
3102 
DitherEol(RENDER * p,int line)3103 private	void	DitherEol( RENDER *p, int line )
3104 {
3105 	/* Nothing to do - dithering has no memory */
3106 }
3107 
3108 /*
3109 *	Clustered dither of a particular colour of a line
3110 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3111 */
3112 
DitherLine(HTONE * htone,int y)3113 private	void   DitherLine( HTONE *htone, int y )
3114 {
3115 int		x;							/* Counts the pixels					*/
3116 int		pixel;						/* Current pixel value					*/
3117 int		length;						/* Number of pixels to process			*/
3118 byte	*res;						/* Result								*/
3119 byte	*data;						/* Input data							*/
3120 byte	*block;						/* Block pixel							*/
3121 byte	*matrix;					/* Dither matrix's current line			*/
3122 int		mx;							/* Matrix index							*/
3123 int		lval, hval;					/* Halftoned high/low values			*/
3124 
3125 	length  = htone->render->width;
3126 
3127 	res		= htone->res;
3128 	data	= htone->data;
3129 	block	= htone->block;
3130 
3131 	matrix	= dmatrix[ y % DMATRIX_Y ];
3132 
3133 	for ( mx = x = 0 ; x < length ; x++ ) {
3134 
3135 		/* First, clear the res byte. It is needed for the black */
3136 
3137 		*res = 0;
3138 
3139 		/* Next, see if the pixel is above the mval */
3140 
3141 		if ( ( pixel = *data ) > htone->mval ) {
3142 
3143 			lval = htone->mval;
3144 			hval = 255;
3145 
3146 			if ( htone->mval == 127 )
3147 
3148 				pixel = ( ( pixel - htone->mval ) * 2 - 1 ) / 2;
3149 			else
3150 				pixel = ( pixel - htone->mval ) * 255 / ( 255 - htone->mval );
3151 		}
3152 		else {
3153 
3154 			lval = 0;
3155 			hval = htone->mval;
3156 
3157 			if ( htone->mval != 255 ) {
3158 
3159 				if ( htone->mval == 127 )
3160 
3161 					pixel = ( pixel * 4 + 1 ) / 2;
3162 				else
3163 					pixel = pixel * 255 / htone->mval;
3164 			}
3165 		}
3166 
3167 		if ( block && *block ) {
3168 
3169 			*res = 0;
3170 		}
3171 		else {
3172 
3173 			if ( pixel >= matrix[ mx ] )
3174 
3175 				*res = hval;
3176 			else
3177 				*res = lval;
3178 		}
3179 
3180 		res++;
3181 		if ( ++mx == DMATRIX_X ) mx = 0;
3182 		if ( block ) block++;
3183 		data += htone->step;
3184 	}
3185 }
3186 
3187 /****************************************************************************/
3188 /*					Bendor's error diffusion								*/
3189 /****************************************************************************/
3190 
3191 /*
3192 *	This function returns the empty range threshold
3193 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3194 */
3195 
BendorThold(RENDER * p)3196 private	int		BendorThold( RENDER *p )
3197 {
3198 	return( 5 );
3199 }
3200 
3201 /*
3202 *	This function initialises the halftoner
3203 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3204 */
3205 
BendorStart(RENDER * p,int line)3206 private	void	BendorStart( RENDER *p, int line )
3207 {
3208 	memset( p->err, 0, 2 * ICOLN * MAX_PIXELS*2 );
3209 	p->error[ 0 ] = p->err[ 0 ];
3210 	p->error[ 1 ] = p->err[ 1 ];
3211 }
3212 
3213 /*
3214 *	This function does the end-of-line processing
3215 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3216 */
3217 
BendorEol(RENDER * p,int line)3218 private	void	BendorEol( RENDER *p, int line )
3219 {
3220 void	*x;
3221 
3222 	x = p->error[ 0 ];
3223 	p->error[ 0 ] = p->error[ 1 ];
3224 	p->error[ 1 ] = x;
3225 }
3226 
3227 /*
3228 *	Error diffusion of a particular colour of a line
3229 *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3230 *
3231 *	This is not yet finished (the matrix is bad, actually).
3232 *
3233 *	The matrix is the following (the normalisation factor is 1/128,
3234 *	'*' represents the current pixel, r is the truncation residual):
3235 *
3236 *				 *	20	10  r
3237 *		8	14	20	14	 8
3238 *		4	 8	10	 8	 4
3239 *
3240 *	We also try to take the splashing effect into account (the ink disperses
3241 *	when it hits the paper so it partially covers surrounding pixels).
3242 *	We use an other matrix for that, which is very simple:
3243 *
3244 *			*	3
3245 *		2	3	2
3246 *
3247 *	and the normalisation factor can be set by the user.
3248 *	The splash matrix is only applied if we have actually deposited
3249 *	ink and the amount added to the errors is independent that of the
3250 *	actual image value, it only depends on the ink applied.
3251 *	Of course, the ink spreads up and left as well and we could compensate
3252 *	for this for a certain extent by keeping track of the errors caused in
3253 *	previous pixels and lines and modifying them accordingly but it
3254 *	would lead to a horrible code mess and it wouldn't be worth the effort.
3255 *
3256 *	A further enhancement that we allow the error to 'leak'. Experimental
3257 *	results show that with a 5-15% loss of error the image quality
3258 *	increases and the colour distortion remains very low. If you think
3259 *	about it, this, in effect stops the error to spread its effect over
3260 *	large areas but it will have almost undisturbed effect on neighbouring
3261 *	areas (you allow for an exponential error decay).
3262 *	This parameter is user definable, too.
3263 */
3264 
BendorLine(HTONE * htone,int y)3265 private	void   BendorLine( HTONE *htone, int y )
3266 {
3267 int		x;							/* Counts the pixels					*/
3268 int		pixel;						/* Current pixel value					*/
3269 int		pixerr;						/* Error value							*/
3270 int		pixe14;						/* 14 * err value						*/
3271 int		sval;						/* Splash correction value				*/
3272 int		splash;						/* Splash factor						*/
3273 int		leakage;					/* Leakage factor						*/
3274 int		length;						/* Number of pixels to process			*/
3275 byte	*res;						/* Result								*/
3276 byte	*data;						/* Input data							*/
3277 byte	*block;						/* Block pixel							*/
3278 int		lim1, lim2;					/* Limits								*/
3279 short	e0, e1;						/* Propagating errors in current line	*/
3280 short	*l0, *l1;					/* Error buffer pointers				*/
3281 
3282 	splash  = htone->render->dev->splash;
3283 	leakage = htone->render->dev->splash;
3284 	length  = htone->render->width;
3285 
3286 	res		= htone->res;
3287 	data	= htone->data;
3288 	block	= htone->block;
3289 
3290 	lim1	= htone->mval / 2;
3291 	lim2	= ( htone->mval + 256 ) / 2;
3292 
3293 	l0		= htone->err[ 0 ];
3294 	l1		= htone->err[ 1 ];
3295 
3296 	e0		= l0[ 2 ];
3297 	e1		= l0[ 3 ];
3298 
3299 	l0[ 2 ] = 0;
3300 	l0[ 3 ] = 0;
3301 
3302 	for ( x = 0 ; x < length ; x++ ) {
3303 
3304 		/* First, clear the res byte. It is needed for the black */
3305 
3306 		*res = 0;
3307 
3308 		/* Add the actual error to the pixel, normalise, init, whatever. */
3309 
3310 		pixel = ( ( *data << 7 ) + e0 );
3311 		e0 = e1;
3312 		e1 = l0[ 4 ] + ( pixel & 127 );			/* This is the residual */
3313 
3314 		l0[ 4 ] = 0;
3315 		pixel >>= 7;
3316 
3317 		if ( ( block && *block ) || ( pixel < lim1 ) )
3318 
3319 			*res = 0;
3320 
3321 		else if ( pixel >= lim2 )
3322 
3323 			*res = 255;
3324 		else
3325 			*res = htone->mval;
3326 
3327 		/* Calculate the err */
3328 
3329 		pixerr = pixel - *res;
3330 
3331 		/* If leakage is defined, apply it */
3332 
3333 		if ( leakage ) pixerr -= ( pixerr * leakage ) / 100;
3334 
3335 		/* Diffuse the err */
3336 
3337 		pixerr <<= 1;							/* Multiplier is 2	*/
3338 		pixe14 = pixerr;						/* pixe14 now 2		*/
3339 		pixerr <<= 1;							/* Multiplier is 4	*/
3340 		pixe14 += pixerr;						/* pixe14 now 6		*/
3341 
3342 		l0[ 0 ] += pixerr;
3343 		l0[ 4 ] += pixerr;
3344 
3345 		pixerr <<= 1;							/* Multiplier is 8	*/
3346 		pixe14 += pixerr;						/* pixe14 now 14	*/
3347 
3348 		l0[ 1 ] += pixerr;
3349 		l0[ 3 ] += pixerr;
3350 		l1[ 0 ] += pixerr;
3351 		l1[ 4 ] += pixerr;
3352 
3353 		pixerr += pixerr >> 2;					/* Multiplier is 10	*/
3354 
3355 		l0[ 2 ] += pixerr;
3356 		e1		+= pixerr;
3357 
3358 		pixerr <<= 1;							/* Multiplier is 20 */
3359 
3360 		l1[ 2 ] += pixerr;
3361 		e0		+= pixerr;
3362 
3363 		/* pixe14 already contains 14 * err */
3364 
3365 		l1[ 1 ] += pixe14;
3366 		l1[ 3 ] += pixe14;
3367 
3368 		/* If splashing is defined, apply the splash matrix.
3369 		   The splash value is normalised to the same level as the err */
3370 
3371 		if ( splash && *res ) {
3372 
3373 			sval = splash * *res;				/* This is the 2x value	*/
3374 
3375 			l1[ 1 ] -= sval;
3376 			l1[ 3 ] -= sval;
3377 
3378 			sval += sval >> 1;					/* This represents 3x	*/
3379 
3380 			e0		-= sval;
3381 			l1[ 2 ] -= sval;
3382 		}
3383 
3384 		/* We have done everything, move the pointers */
3385 
3386 		res++;
3387 		if ( block ) block++;
3388 		data += htone->step;
3389 		l0++, l1++;
3390 	}
3391 }
3392