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