xref: /plan9-contrib/sys/src/cmd/gs/src/gdevphex.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevphex.c,v 1.7 2004/08/10 13:02:36 stefan Exp $ */
18*593dc095SDavid du Colombier 
193ff48bf5SDavid du Colombier /****************************************************************************/
203ff48bf5SDavid du Colombier /*	Ghostscript printer driver for Epson Color Photo, Photo EX, Photo 700	*/
213ff48bf5SDavid du Colombier /****************************************************************************/
223ff48bf5SDavid du Colombier 
233ff48bf5SDavid du Colombier #include "gdevprn.h"
243ff48bf5SDavid du Colombier #include <math.h>
253ff48bf5SDavid du Colombier 
263ff48bf5SDavid du Colombier /****************************************************************************/
273ff48bf5SDavid du Colombier /*								Legend										*/
283ff48bf5SDavid du Colombier /****************************************************************************/
293ff48bf5SDavid du Colombier 
303ff48bf5SDavid du Colombier /*
313ff48bf5SDavid du Colombier 
323ff48bf5SDavid du Colombier HISTORY
333ff48bf5SDavid du Colombier ~~~~~~~
343ff48bf5SDavid du Colombier 
353ff48bf5SDavid du Colombier 8 June 1999 Zolt�n K�csi (aka Kocsonya) zoltan@bendor.com.au
363ff48bf5SDavid du Colombier 
373ff48bf5SDavid du Colombier 	Initial revision.
383ff48bf5SDavid du Colombier 	No shingling, depletion.
393ff48bf5SDavid du Colombier 	Colour only.
403ff48bf5SDavid du Colombier 	Dither matrix is blatantly copied from gslib.c.
413ff48bf5SDavid du Colombier 
423ff48bf5SDavid du Colombier 17 April 2000 Zolt�n K�csi
433ff48bf5SDavid du Colombier 
443ff48bf5SDavid du Colombier 	After much play worked out a reasonably simple colour mapping
453ff48bf5SDavid du Colombier 	that gives fairly good results. It has some very hairy things
463ff48bf5SDavid du Colombier 	in it but ot seems to work reasonably well on a variety of natural
473ff48bf5SDavid du Colombier 	as well as artificial images.
483ff48bf5SDavid du Colombier 
493ff48bf5SDavid du Colombier 
503ff48bf5SDavid du Colombier LEGALISE
513ff48bf5SDavid du Colombier ~~~~~~~~
523ff48bf5SDavid du Colombier 
533ff48bf5SDavid du Colombier The usual disclaimer applies, neither me (Zolt�n K�csi) nor
543ff48bf5SDavid du Colombier Bendor Research Pty. Ltd. assume any liability whatsoever in
553ff48bf5SDavid du Colombier relation to events arising out of or related to the use of
563ff48bf5SDavid du Colombier the software or the included documentation in any form, way
573ff48bf5SDavid du Colombier or purpose. This software is not guaranteed to work, you
583ff48bf5SDavid du Colombier get it "as is" and use it for your own risk.
593ff48bf5SDavid du Colombier 
603ff48bf5SDavid du Colombier This code has been donated to Aladdin Enterprises, see their
613ff48bf5SDavid du Colombier license for details.
623ff48bf5SDavid du Colombier 
633ff48bf5SDavid du Colombier CREDIT
643ff48bf5SDavid du Colombier ~~~~~~
653ff48bf5SDavid du Colombier This driver was written from scratch, however, I have used the
663ff48bf5SDavid du Colombier HP/BJ driver very heavily as a reference (GhostScript's documentation
673ff48bf5SDavid du Colombier needs some working :-). In addition, I got some help in understanding
683ff48bf5SDavid du Colombier the more arcane features of the printer by digging into the colour
693ff48bf5SDavid du Colombier Epson driver and its documentation (documentation for the Photo EX
703ff48bf5SDavid du Colombier did not exist). I thank to the authors of these drivers and the
713ff48bf5SDavid du Colombier related docs.
723ff48bf5SDavid du Colombier 
733ff48bf5SDavid du Colombier I do also hereby express my despising Epson, Inc. who try to enlarge
743ff48bf5SDavid du Colombier Microsoft's monopoly by witholding programming information about such
753ff48bf5SDavid du Colombier a commodity item as a printer.
763ff48bf5SDavid du Colombier 
773ff48bf5SDavid du Colombier KNOWN BUGS/LIMITATIONS
783ff48bf5SDavid du Colombier ~~~~~~~~~~~~~~~~~~~~~~
793ff48bf5SDavid du Colombier - Monochrome driver is not finished yet
803ff48bf5SDavid du Colombier - The driver is not optimised for speed
813ff48bf5SDavid du Colombier - The driver does not support TIFF compression
823ff48bf5SDavid du Colombier - Shingling and depletion is not implemented
833ff48bf5SDavid du Colombier - The colour correction and ink transfer curve are hardcoded
843ff48bf5SDavid du Colombier - The dither matrix is straight stolen from Ghostscript
853ff48bf5SDavid du Colombier - The alternative error diffusion included but does not work (yet)
863ff48bf5SDavid du Colombier 
873ff48bf5SDavid du Colombier I plan to attend these issues later, however, I don't promise any timeframe
883ff48bf5SDavid du Colombier for I have a lot else to do for bread & butter too.
893ff48bf5SDavid du Colombier 
903ff48bf5SDavid du Colombier PREFACE
913ff48bf5SDavid du Colombier ~~~~~~~
923ff48bf5SDavid du Colombier The Epson Stylus Photo EX is a colour ink-jet printer.
933ff48bf5SDavid du Colombier It can handle papers up to A3. It uses 6 inks, black in one cartridge
943ff48bf5SDavid du Colombier and cyan, magenta, yellow, light cyan and light magenta in an other
953ff48bf5SDavid du Colombier cartridge. The head has 32 nozzles, with 1/90" spacing.
963ff48bf5SDavid du Colombier The maximal resolution is 1440 dpi horizontal 720 dpi vertical.
973ff48bf5SDavid du Colombier In 720x720 and 360x360 dpi it supports microweave. To achieve
983ff48bf5SDavid du Colombier 1440x720 you must use software weaving. It has only one built-in font,
993ff48bf5SDavid du Colombier namely 12pt Courier; the printer in general havily relies on the
1003ff48bf5SDavid du Colombier driver software. It comes with (what else ?) Windows 9x and Mac drivers.
1013ff48bf5SDavid du Colombier 
1023ff48bf5SDavid du Colombier The printer uses the ESC/P Raster protocol. This protocol is somewhat
1033ff48bf5SDavid du Colombier similar to the ESC/P2 one. Initially Epson refused to give any info
1043ff48bf5SDavid du Colombier about it. Later (unfortunately after I had already spent lot of time
1053ff48bf5SDavid du Colombier to reverse engineer it) they released its definition. It could be
1063ff48bf5SDavid du Colombier found on their website (http://www.ercipd.com/isv/level1/6clr_98b.pdf).
1073ff48bf5SDavid du Colombier Alas, they removed it, so at the moment I do not know about any existing
1083ff48bf5SDavid du Colombier docs of the printer.
1093ff48bf5SDavid du Colombier There are still a few commands which are not covered by the docs
1103ff48bf5SDavid du Colombier and for example the Windows driver uses them. There are others which
1113ff48bf5SDavid du Colombier are in the docs, saying that you can find them in other docs but you
1123ff48bf5SDavid du Colombier can't. Fortunately, these commands apparently have no effect on the
1133ff48bf5SDavid du Colombier printing process so this driver simply ignores them. Tricky business.
1143ff48bf5SDavid du Colombier 
1153ff48bf5SDavid du Colombier By the way, my personal experience is that Epson tech support is
1163ff48bf5SDavid du Colombier a joke, or in Usenet lingvo it sucks big time - they know absolutely
1173ff48bf5SDavid du Colombier nothing about the product they supposed to support. Epson's webpage
1183ff48bf5SDavid du Colombier contains false info as well (they state that the Photo EX uses ESC/P2,
1193ff48bf5SDavid du Colombier which is simply not true).
1203ff48bf5SDavid du Colombier 
1213ff48bf5SDavid du Colombier This driver should in theory support the Stylus 700 and the Stylus Photo
1223ff48bf5SDavid du Colombier as well but I have not tested it on them.
1233ff48bf5SDavid du Colombier 
1243ff48bf5SDavid du Colombier If you think that you can get some useful info from me above of what you
1253ff48bf5SDavid du Colombier can find below, feel free to email me at zoltan@bendor.com.au.
1263ff48bf5SDavid du Colombier If you enhance the driver or find a bug *please* send me info about
1273ff48bf5SDavid du Colombier it.
1283ff48bf5SDavid du Colombier 
1293ff48bf5SDavid du Colombier DRIVER
1303ff48bf5SDavid du Colombier ~~~~~~
1313ff48bf5SDavid du Colombier The driver was written under Ghostscript 5.10.
1323ff48bf5SDavid du Colombier This file should contain two drivers, one for colour mode and one for B&W.
1333ff48bf5SDavid du Colombier The devices are "photoex" and "photoexm". The mono device driver is
1343ff48bf5SDavid du Colombier catered for (that is, the rendering part knows how to render for B&W)
1353ff48bf5SDavid du Colombier but it is not finished yet (no device structure and gray colour mapping
1363ff48bf5SDavid du Colombier procedures) mainly because all my B&W needs are fairly well satisfied
1373ff48bf5SDavid du Colombier by our laser printer.
1383ff48bf5SDavid du Colombier 
1393ff48bf5SDavid du Colombier The driver features the following:
1403ff48bf5SDavid du Colombier 
1413ff48bf5SDavid du Colombier Supported resolutions
1423ff48bf5SDavid du Colombier 
1433ff48bf5SDavid du Colombier 	 360x360	Y weaving (not that micro :-) by the printer
1443ff48bf5SDavid du Colombier 	 720x720	Y microweave by the driver (quicker than the printer)
1453ff48bf5SDavid du Colombier 	1440x720	Y and X microweave by the driver
1463ff48bf5SDavid du Colombier 
1473ff48bf5SDavid du Colombier 	Resolutions other than these will result in a rangecheck error.
1483ff48bf5SDavid du Colombier 
1493ff48bf5SDavid du Colombier Papersize:
1503ff48bf5SDavid du Colombier 
1513ff48bf5SDavid du Colombier 	Whatever Ghostscript supports. The printer docs say that if you load
1523ff48bf5SDavid du Colombier 	multiple sheets of transparencies into the tray you should at least
1533ff48bf5SDavid du Colombier 	have 30mm or 1.2" top margin. The driver always sets the smallest
1543ff48bf5SDavid du Colombier 	possible top margin (3mm or 0.12"), it's up to you to comply.
1553ff48bf5SDavid du Colombier 
1563ff48bf5SDavid du Colombier 	In addition, the printer says that the bottom margin is at least
1573ff48bf5SDavid du Colombier 	14mm or 0.54". I violate it by setting it to 0.5" or 12.7mm.
1583ff48bf5SDavid du Colombier 	0.5" seems to be a common margin value for documents and you
1593ff48bf5SDavid du Colombier 	would hate it when the last line of your page gets printed on the
1603ff48bf5SDavid du Colombier 	top of the next sheet ...
1613ff48bf5SDavid du Colombier 
1623ff48bf5SDavid du Colombier Options:
1633ff48bf5SDavid du Colombier 
1643ff48bf5SDavid du Colombier 	-dDotSize=n
1653ff48bf5SDavid du Colombier 
1663ff48bf5SDavid du Colombier 		n = 0		Let the driver choose a dotsize
1673ff48bf5SDavid du Colombier 		n = 1		small dots
1683ff48bf5SDavid du Colombier 		n = 2		more ink
1693ff48bf5SDavid du Colombier 		n = 3		ink flood
1703ff48bf5SDavid du Colombier 		n = 4		'super microdots' (whatever they are, they are *big*)
1713ff48bf5SDavid du Colombier 
1723ff48bf5SDavid du Colombier 		The default is 0 which is n=1 for 1440x720, 2 for 720x720 and
1733ff48bf5SDavid du Colombier 		3 for 360x360. Do not use large dots if you don't have to, you
1743ff48bf5SDavid du Colombier 		will soak the paper. If you print 720x720 on normal paper, try
1753ff48bf5SDavid du Colombier 		using n=1.
1763ff48bf5SDavid du Colombier 
1773ff48bf5SDavid du Colombier 	-dRender=n
1783ff48bf5SDavid du Colombier 
1793ff48bf5SDavid du Colombier 		n = 0		Floyd-Steinbeck error diffusion
1803ff48bf5SDavid du Colombier 		n = 1		Clustered dither
1813ff48bf5SDavid du Colombier 		n = 2		Bendor's error diffusion (experimental, do not use)
1823ff48bf5SDavid du Colombier 
1833ff48bf5SDavid du Colombier 		Default is Floyd-Steinbeck error diffusion
1843ff48bf5SDavid du Colombier 
1853ff48bf5SDavid du Colombier 	-dLeakage=nn
1863ff48bf5SDavid du Colombier 
1873ff48bf5SDavid du Colombier 		nn is between 0 and 25. It only effects Bendor's error diffusion.
1883ff48bf5SDavid du Colombier 		It sets the percentage of the error which is left to 'leak', that
1893ff48bf5SDavid du Colombier 		is it is the coefficient of an exponential decay of the error.
1903ff48bf5SDavid du Colombier 		Experiments show that it can be beneficial on image quality.
1913ff48bf5SDavid du Colombier 		Default is 0 (no leakage).
1923ff48bf5SDavid du Colombier 
1933ff48bf5SDavid du Colombier 	-dSplash=nn
1943ff48bf5SDavid du Colombier 
1953ff48bf5SDavid du Colombier 		nn is between 0 and 100. It only affects Bendor's error diffusion.
1963ff48bf5SDavid du Colombier 		The ED routine tries to take the increase of dot diameter on certain
1973ff48bf5SDavid du Colombier 		paper types into account.
1983ff48bf5SDavid du Colombier 		It sets the percentage of the ink dot size increase as it splashes
1993ff48bf5SDavid du Colombier 		onto the paper and spreads. 0 means no splashing, 100 means that
2003ff48bf5SDavid du Colombier 		the dot is twice as large as it should be.
2013ff48bf5SDavid du Colombier 		Default is 0.
2023ff48bf5SDavid du Colombier 
2033ff48bf5SDavid du Colombier 	-dBinhibit=n
2043ff48bf5SDavid du Colombier 
2053ff48bf5SDavid du Colombier 		If n is 1, then if black ink is deposited to a pixel, it will
2063ff48bf5SDavid du Colombier 		inhibit the deposition of any other ink to the same pixel.
2073ff48bf5SDavid du Colombier 		If 0, black ink may be deposited together with other inks.
2083ff48bf5SDavid du Colombier 		Default is on (1).
2093ff48bf5SDavid du Colombier 
2103ff48bf5SDavid du Colombier ESC/P RASTER DOCS
2113ff48bf5SDavid du Colombier ~~~~~~~~~~~~~~~~~
2123ff48bf5SDavid du Colombier The parts of the ESC/P Raster protocol which I've managed to decipher,
2133ff48bf5SDavid du Colombier and which are actually used in this driver can be found below.
2143ff48bf5SDavid du Colombier nn, mm, xx, etc. represent a single byte with a binary value in it.
2153ff48bf5SDavid du Colombier nnnn, xxxx etc. represent a 16-bit binary number, sent in two bytes,
2163ff48bf5SDavid du Colombier in little endian order (low byte first). 2-digit numbers are a single
2173ff48bf5SDavid du Colombier byte in hex. Other chars are themselves.
2183ff48bf5SDavid du Colombier Quite a few commands are identical to the ESC/P2 commands, these are
2193ff48bf5SDavid du Colombier marked with (P2).
2203ff48bf5SDavid du Colombier 
2213ff48bf5SDavid du Colombier ESC @								(P2)
2223ff48bf5SDavid du Colombier 
2233ff48bf5SDavid du Colombier 	Resets the printer.
2243ff48bf5SDavid du Colombier 
2253ff48bf5SDavid du Colombier 
2263ff48bf5SDavid du Colombier ESC ( U 01 00 nn					(P2)
2273ff48bf5SDavid du Colombier 
2283ff48bf5SDavid du Colombier 	Sets the unit to 3600/nn dpi. Note that 1440 can not be set !
2293ff48bf5SDavid du Colombier 
2303ff48bf5SDavid du Colombier 
2313ff48bf5SDavid du Colombier ESC ( C 02 00 nnnn					(P2)
2323ff48bf5SDavid du Colombier 
2333ff48bf5SDavid du Colombier 	Sets the page (paper) length to nnnn units
2343ff48bf5SDavid du Colombier 
2353ff48bf5SDavid du Colombier 
2363ff48bf5SDavid du Colombier ESC ( c 04 00 bbbb tttt				(P2)
2373ff48bf5SDavid du Colombier 
2383ff48bf5SDavid du Colombier 	Sets the top margin to tttt units, the bottom margin to
2393ff48bf5SDavid du Colombier 	bbbb units. The bottom margin is measured from the top
2403ff48bf5SDavid du Colombier 	of the page not from the bottom of the page !
2413ff48bf5SDavid du Colombier 
2423ff48bf5SDavid du Colombier 
2433ff48bf5SDavid du Colombier ESC	U nn							(P2)
2443ff48bf5SDavid du Colombier 
2453ff48bf5SDavid du Colombier 	Unidirectional printing
2463ff48bf5SDavid du Colombier 
2473ff48bf5SDavid du Colombier 	nn
2483ff48bf5SDavid du Colombier 	00	off
2493ff48bf5SDavid du Colombier 	01	on
2503ff48bf5SDavid du Colombier 	30	off (this is ASCII 0)
2513ff48bf5SDavid du Colombier 	31	on	(this is ASCII 1)
2523ff48bf5SDavid du Colombier 
2533ff48bf5SDavid du Colombier 
2543ff48bf5SDavid du Colombier ESC	( i 01 00 nn					(P2)
2553ff48bf5SDavid du Colombier 
2563ff48bf5SDavid du Colombier 	Microweave
2573ff48bf5SDavid du Colombier 
2583ff48bf5SDavid du Colombier 	nn
2593ff48bf5SDavid du Colombier 	00	off
2603ff48bf5SDavid du Colombier 	01	on
2613ff48bf5SDavid du Colombier 	30	off (this is ASCII 0)
2623ff48bf5SDavid du Colombier 	31	on	(this is ASCII 1)
2633ff48bf5SDavid du Colombier 
2643ff48bf5SDavid du Colombier 	Turns microweave on for 720x720 dpi printing.
2653ff48bf5SDavid du Colombier 
2663ff48bf5SDavid du Colombier ESC r nn							(P2)
2673ff48bf5SDavid du Colombier 
2683ff48bf5SDavid du Colombier 	Select colour
2693ff48bf5SDavid du Colombier 
2703ff48bf5SDavid du Colombier 	nn
2713ff48bf5SDavid du Colombier 	01		Cyan
2723ff48bf5SDavid du Colombier 	02		Magenta
2733ff48bf5SDavid du Colombier 	04		Yellow
2743ff48bf5SDavid du Colombier 	08		Black
2753ff48bf5SDavid du Colombier 
2763ff48bf5SDavid du Colombier 
2773ff48bf5SDavid du Colombier ESC ( G 01 00 nn					(P2)
2783ff48bf5SDavid du Colombier 
2793ff48bf5SDavid du Colombier 	Selects graphics mode:
2803ff48bf5SDavid du Colombier 
2813ff48bf5SDavid du Colombier 	nn
2823ff48bf5SDavid du Colombier 	00		Off
2833ff48bf5SDavid du Colombier 	01		On
2843ff48bf5SDavid du Colombier 	30		Off
2853ff48bf5SDavid du Colombier 	31		On
2863ff48bf5SDavid du Colombier 
2873ff48bf5SDavid du Colombier 
2883ff48bf5SDavid du Colombier ESC ( v 02 00 dddd					(P2)
2893ff48bf5SDavid du Colombier 
2903ff48bf5SDavid du Colombier 	Advance the paper by dddd units defined by ESC ( U
2913ff48bf5SDavid du Colombier 
2923ff48bf5SDavid du Colombier 
2933ff48bf5SDavid du Colombier ESC . cc vv hh nn mmmm <data>		(P2)
2943ff48bf5SDavid du Colombier 
2953ff48bf5SDavid du Colombier 	Sends graphics data to the printer.
2963ff48bf5SDavid du Colombier 
2973ff48bf5SDavid du Colombier 	cc	Encoding mode
2983ff48bf5SDavid du Colombier 
2993ff48bf5SDavid du Colombier 		00	Raw data
3003ff48bf5SDavid du Colombier 		01	Run-length encoded data
3013ff48bf5SDavid du Colombier 
3023ff48bf5SDavid du Colombier 	vv	Vertical resolution
3033ff48bf5SDavid du Colombier 
3043ff48bf5SDavid du Colombier 		28	  90 dpi	*interleave*
3053ff48bf5SDavid du Colombier 		14	 180 dpi	*interleave*
3063ff48bf5SDavid du Colombier 		0a	 360 dpi
3073ff48bf5SDavid du Colombier 		05	 720 dpi
3083ff48bf5SDavid du Colombier 
3093ff48bf5SDavid du Colombier 	hh	Horizontal resolution
3103ff48bf5SDavid du Colombier 
3113ff48bf5SDavid du Colombier 		0a	 360 dpi
3123ff48bf5SDavid du Colombier 		05	 720 dpi
3133ff48bf5SDavid du Colombier 
3143ff48bf5SDavid du Colombier 	nn	Number of nozzles
3153ff48bf5SDavid du Colombier 
3163ff48bf5SDavid du Colombier 		It should be set to 32 (normal printing) or 1 (microweave)
3173ff48bf5SDavid du Colombier 
3183ff48bf5SDavid du Colombier 	mmmm Number of collumns of data (not number of data bytes !)
3193ff48bf5SDavid du Colombier 
3203ff48bf5SDavid du Colombier 	<data>
3213ff48bf5SDavid du Colombier 
3223ff48bf5SDavid du Colombier 		The data should contain as many bytes as needed to fill the
3233ff48bf5SDavid du Colombier 		mmmm * nn pixels. Data is presented horizontally, that is,
3243ff48bf5SDavid du Colombier 		the bits of a byte will be represented by eight pixels in
3253ff48bf5SDavid du Colombier 		a row. If the number of collumns is not an integer multiple
3263ff48bf5SDavid du Colombier 		of eight, then some bits from the last byte belonging to the
3273ff48bf5SDavid du Colombier 		row will be discarded and the next row starts on a byte boundary.
3283ff48bf5SDavid du Colombier 		If a bit in a byte is '1' ink is deposited, if '0' not.
3293ff48bf5SDavid du Colombier 		The leftmost pixel is represented by the MSB, rightmost by LSB.
3303ff48bf5SDavid du Colombier 		In case of raw data that's about it.
3313ff48bf5SDavid du Colombier 
3323ff48bf5SDavid du Colombier 		In case of run-length encoded data, the following is done:
3333ff48bf5SDavid du Colombier 		The first byte is a counter. If the counter is <= 127 then
3343ff48bf5SDavid du Colombier 		the following counter+1 bytes are uncompressed data.
3353ff48bf5SDavid du Colombier 		If the counter is >= 128 then the following single byte should
3363ff48bf5SDavid du Colombier 		be repeated 257-counter times.
3373ff48bf5SDavid du Colombier 
3383ff48bf5SDavid du Colombier 	There are resolution restrictions:
3393ff48bf5SDavid du Colombier 
3403ff48bf5SDavid du Colombier 		360x360 nozzle= 1 microweave on
3413ff48bf5SDavid du Colombier 		360x360 nozzle=32 microweave off
3423ff48bf5SDavid du Colombier 		720x 90 nozzle=32 microweave off
3433ff48bf5SDavid du Colombier 		720x720	nozzle= 1 microweave on
3443ff48bf5SDavid du Colombier 
3453ff48bf5SDavid du Colombier 	Other combinations are not supported.
3463ff48bf5SDavid du Colombier 
3473ff48bf5SDavid du Colombier ESC ( e 02 00 00 nn
3483ff48bf5SDavid du Colombier 
3493ff48bf5SDavid du Colombier 	Sets the amount of ink spat onto the paper.
3503ff48bf5SDavid du Colombier 
3513ff48bf5SDavid du Colombier 	nn
3523ff48bf5SDavid du Colombier 	01		microdots (faint printing)
3533ff48bf5SDavid du Colombier 	02		normal dots (not so faint printing)
3543ff48bf5SDavid du Colombier 	03		double dots (full inking)
3553ff48bf5SDavid du Colombier 	04		super microdots (ink is continuously dripping :-)
3563ff48bf5SDavid du Colombier 
3573ff48bf5SDavid du Colombier 	Values other than that have apparently no effect.
3583ff48bf5SDavid du Colombier 
3593ff48bf5SDavid du Colombier ESC ( K 02 00 xxxx
3603ff48bf5SDavid du Colombier 
3613ff48bf5SDavid du Colombier 	This command is sent by the Windows driver but it is not used
3623ff48bf5SDavid du Colombier 	in the Epson test images. I have not found it having any effect
3633ff48bf5SDavid du Colombier 	whatsoever. The driver does not use it. The Epson docs don't
3643ff48bf5SDavid du Colombier 	mention it.
3653ff48bf5SDavid du Colombier 
3663ff48bf5SDavid du Colombier ESC ( r 02 00 nn mm
3673ff48bf5SDavid du Colombier 
3683ff48bf5SDavid du Colombier 	Selects the ink according to this:
3693ff48bf5SDavid du Colombier 
3703ff48bf5SDavid du Colombier 	nn mm
3713ff48bf5SDavid du Colombier 	00 00	black
3723ff48bf5SDavid du Colombier 	00 01	magenta
3733ff48bf5SDavid du Colombier 	00 02	cyan
3743ff48bf5SDavid du Colombier 	00 04	yellow
3753ff48bf5SDavid du Colombier 	01 01	light magenta
3763ff48bf5SDavid du Colombier 	01 02	light yellow
3773ff48bf5SDavid du Colombier 
3783ff48bf5SDavid du Colombier 
3793ff48bf5SDavid du Colombier ESC ( \ 04 00 xxxx llll
3803ff48bf5SDavid du Colombier 
3813ff48bf5SDavid du Colombier 	Horizontal positioning of the head.
3823ff48bf5SDavid du Colombier 
3833ff48bf5SDavid du Colombier 	Moves the head to the position llll times 1/xxxx inches from
3843ff48bf5SDavid du Colombier 	the left margin.
3853ff48bf5SDavid du Colombier 	On the example images xxxx was always set to 1440.
3863ff48bf5SDavid du Colombier 	I tried other values in which case the command was ignored,
3873ff48bf5SDavid du Colombier 	so stick to 1440.
3883ff48bf5SDavid du Colombier 
3893ff48bf5SDavid du Colombier 
3903ff48bf5SDavid du Colombier ESC ( R ll 00 00 <text> <cc> xxxx nn .. nn
3913ff48bf5SDavid du Colombier ESC 00 00 00
3923ff48bf5SDavid du Colombier 
3933ff48bf5SDavid du Colombier 	This is supposedly sets the printer into 'remote' mode.
3943ff48bf5SDavid du Colombier 	ll is the length of the <text> + 1 which consists of ASCII
3953ff48bf5SDavid du Colombier 	characters (e.g. REMOTE1).
3963ff48bf5SDavid du Colombier 	<cc> is a two-character code, for example "SN" or "LD".
3973ff48bf5SDavid du Colombier 	xxxx is the number of bytes (nn -s) which will follow.
3983ff48bf5SDavid du Colombier 	After that there's either a new <cc> xxxx nn .. nn sequence or
3993ff48bf5SDavid du Colombier 	the ESC 00 00 00.
4003ff48bf5SDavid du Colombier 	I have absolutely no idea about this command and the Epson document
4013ff48bf5SDavid du Colombier 	says that it's in an other document. It's not in that other one.
4023ff48bf5SDavid du Colombier 	The driver does not use it. The printer does not miss it.
4033ff48bf5SDavid du Colombier 	The Epson test images use it and the Windows driver uses it too.
4043ff48bf5SDavid du Colombier 	They send different <cc>-s and different values for identical <cc>-s.
4053ff48bf5SDavid du Colombier 	Go figure.
4063ff48bf5SDavid du Colombier 
4073ff48bf5SDavid du Colombier DRIVER INTERNALS
4083ff48bf5SDavid du Colombier ~~~~~~~~~~~~~~~~
4093ff48bf5SDavid du Colombier First, some comments.
4103ff48bf5SDavid du Colombier Anything I know about the printer can be found above.
4113ff48bf5SDavid du Colombier Anything I know about Ghostscript internals (not much) can be
4123ff48bf5SDavid du Colombier found in the comments in the code. I do not believe in the 'it was hard
4133ff48bf5SDavid du Colombier to write, it should be hard to read' principle since I once had to
4143ff48bf5SDavid du Colombier understand my own code.
4153ff48bf5SDavid du Colombier Therefore, the code has lots of comments in it, sometimes apparently
4163ff48bf5SDavid du Colombier superfluous but I find it easier to understand the program 6 months
4173ff48bf5SDavid du Colombier later that way.
4183ff48bf5SDavid du Colombier I did not follow the Ghostscript or GNU style guide, I write code the way
4193ff48bf5SDavid du Colombier I like it - I'm a lazy dog :-) I use hard tabs at every 4th position,
4203ff48bf5SDavid du Colombier I use a *lot* of whitespace (as recommended by K&R in their original
4213ff48bf5SDavid du Colombier C book) and I have a formatting style similar to the K&R with the
4223ff48bf5SDavid du Colombier notable exception that I do not indent variable declarations that follow
4233ff48bf5SDavid du Colombier the curly. Anyway, you can run your favourite C formatter through the
4243ff48bf5SDavid du Colombier source.
4253ff48bf5SDavid du Colombier 
4263ff48bf5SDavid du Colombier In addition to the above, the driver is not hand-optimised, it assumes
4273ff48bf5SDavid du Colombier that it is compiled with a good optimising compiler which will handle
4283ff48bf5SDavid du Colombier common subexpression ellimination, move loop independent code out of
4293ff48bf5SDavid du Colombier the loop, transform repeated array accesses to cached pointer arithmetics
4303ff48bf5SDavid du Colombier and so on. The code is much more readable this way and gcc is fairly
4313ff48bf5SDavid du Colombier good at doing optimisation. Feel free to hand-optimise it.
4323ff48bf5SDavid du Colombier 
4333ff48bf5SDavid du Colombier So, the driver works the following way:
4343ff48bf5SDavid du Colombier 
4353ff48bf5SDavid du Colombier When it has to render a page, first it sets up the basics such as margins
4363ff48bf5SDavid du Colombier and papersize and alike.
4373ff48bf5SDavid du Colombier 
4383ff48bf5SDavid du Colombier Line scheduling
4393ff48bf5SDavid du Colombier ---------------
4403ff48bf5SDavid du Colombier 
4413ff48bf5SDavid du Colombier Then it calls the line scheduler. To see why do we have a scheduler, you
4423ff48bf5SDavid du Colombier have to understand weaving. The printer head has 32 nozzles which are
4433ff48bf5SDavid du Colombier spaced at 8 line intervals. Therefore, it prints 32 lines at a time but they
4443ff48bf5SDavid du Colombier are distributed over a 256 line high area. Obviously, if you want to print
4453ff48bf5SDavid du Colombier all the lines under the head, you should pass over the paper 8 times.
4463ff48bf5SDavid du Colombier You can do it the obvious way:
4473ff48bf5SDavid du Colombier Print, move down by one line, print ... repeat 8 times then move down
4483ff48bf5SDavid du Colombier by 256 - 8 lines and start again. Unfortunately, this would result in
4493ff48bf5SDavid du Colombier stripy images due to the differences between individual nozzles.
4503ff48bf5SDavid du Colombier Lines 0-7 would be printed by nozzle 0, 8-15 by nozzle 1 and so on. An
4513ff48bf5SDavid du Colombier 8 line band has a visible height, so difference between nozzles will
4523ff48bf5SDavid du Colombier cause 8-line high bands to appear on the image.
4533ff48bf5SDavid du Colombier 
4543ff48bf5SDavid du Colombier The solution is 'microweave', a funny way of doing interlaced printing.
4553ff48bf5SDavid du Colombier Instead of moving down 1, 1, 1, 1, .. 1, 248, 1, 1 .. you move down
4563ff48bf5SDavid du Colombier a constant, larger amount (called a band). This amount must be chosen
4573ff48bf5SDavid du Colombier in such a way that each line will be printed and preferably it will be
4583ff48bf5SDavid du Colombier printed only once.
4593ff48bf5SDavid du Colombier 
4603ff48bf5SDavid du Colombier Let for example the move down amount (the band) be 31. Let's say,
4613ff48bf5SDavid du Colombier in band N nozzle 31 is over line 300, in which case nozzle 30 is over
4623ff48bf5SDavid du Colombier line 292. We move the head down by 31 lines, then line 299 will be
4633ff48bf5SDavid du Colombier under nozzle 27 and line 307 under nozzle 28.
4643ff48bf5SDavid du Colombier Next move, nozzle 23 will print line 298 and nozzle 24 line 306, then
4653ff48bf5SDavid du Colombier 19/297 20/305, 15/296 16/304, 11/295 12/303, 7/294 8/302, 3/293 4/302,
4663ff48bf5SDavid du Colombier 0/292 3/301 which covers the entire area between 292 and 307.
4673ff48bf5SDavid du Colombier The same will apply to any other area on the page. Also note that
4683ff48bf5SDavid du Colombier adjacent lines are always printed by different nozzles.
4693ff48bf5SDavid du Colombier You probably have realised that line 292 was printed in the first pass
4703ff48bf5SDavid du Colombier and in the last one. In this case, of course, the line must not be printed
4713ff48bf5SDavid du Colombier twice, one or the other pass should not deliver data to the nozzle which
4723ff48bf5SDavid du Colombier passes over this line.
4733ff48bf5SDavid du Colombier 
4743ff48bf5SDavid du Colombier Now there's a twist. When the horizontal resolution is 1440 dpi you have
4753ff48bf5SDavid du Colombier to print each line twice, first depositing all even pixels then offset
4763ff48bf5SDavid du Colombier the head by 1/1440" and deposit all odd pixels (the printer can only
4773ff48bf5SDavid du Colombier print with 720 dpi but you can initially position the head with 1440 dpi
4783ff48bf5SDavid du Colombier resolution). You could do it the easy way, passing over the same area
4793ff48bf5SDavid du Colombier twice but you can do better. You can find a band size which will result
4803ff48bf5SDavid du Colombier each line being printed twice. Instead of suppressing the double print,
4813ff48bf5SDavid du Colombier you use this mechanism to print the odd and the even pixels.
4823ff48bf5SDavid du Colombier Now if you print one line's odd pixels, obviously, all lines belonging
4833ff48bf5SDavid du Colombier to the 31 other nozzles of the head will have their odd pixels printed too.
4843ff48bf5SDavid du Colombier Therefore, you have to keep track which lines have been printed in which
4853ff48bf5SDavid du Colombier phase and try to find an odd-even phase assignment to bands so that each line
4863ff48bf5SDavid du Colombier has both groups printed (and each group only once).
4873ff48bf5SDavid du Colombier The added bonus is that even the same line will be printed by two different
4883ff48bf5SDavid du Colombier nozzles thus effects of nozzle differences can be decreased further.
4893ff48bf5SDavid du Colombier 
4903ff48bf5SDavid du Colombier The whole issue is further complicated with the beginning of the page and
4913ff48bf5SDavid du Colombier the end of the page. When you print the first 8 lines you *must* use the
4923ff48bf5SDavid du Colombier print, down by 1, print ... method but then you have to switch over to the
4933ff48bf5SDavid du Colombier banding method. To do it well, you should minimise the number of lines which
4943ff48bf5SDavid du Colombier are printed out of band. This optimisation is not complex but not trivial
4953ff48bf5SDavid du Colombier either. Our solution is to employ precalculated tables for the first 8 lines.
4963ff48bf5SDavid du Colombier (Epson's solution is not to print the 'problematic' lines at all - they
4973ff48bf5SDavid du Colombier warn you in the manual that at the top and bottom you may have "slight
4983ff48bf5SDavid du Colombier distortions". Analyzing their output reveals the reason ... ).
4993ff48bf5SDavid du Colombier The bottom is different. It is easier, because you are already banding, so
5003ff48bf5SDavid du Colombier you can't screw up the rest of the image. On the other hand, you can't use
5013ff48bf5SDavid du Colombier tables because these tables would depend on the page height which you don't
5023ff48bf5SDavid du Colombier know a priori. Our solution is to switch to single line mode when we can
5033ff48bf5SDavid du Colombier not do the banding any more and try to finish the page with the minimal
5043ff48bf5SDavid du Colombier amount of passes.
5053ff48bf5SDavid du Colombier 
5063ff48bf5SDavid du Colombier So, first the driver calls the scheduler which returns a list of lines which
5073ff48bf5SDavid du Colombier it dispatched to print in the current band. Then the driver checks if it has
5083ff48bf5SDavid du Colombier all these lines halftoned. Since the head covers an area of 256 lines, we
5093ff48bf5SDavid du Colombier have to buffer that many lines (actually, 256-7). As the head moves down,
5103ff48bf5SDavid du Colombier we can flush lines which it has left and halftone the new ones.
5113ff48bf5SDavid du Colombier 
5123ff48bf5SDavid du Colombier 
5133ff48bf5SDavid du Colombier Colour transformations
5143ff48bf5SDavid du Colombier ----------------------
5153ff48bf5SDavid du Colombier 
5163ff48bf5SDavid du Colombier The next important issue is the colour transformation. The reason for doing
5173ff48bf5SDavid du Colombier this is that the ink is not perfect. Ideally, you have 3 inks, namely cyan
5183ff48bf5SDavid du Colombier magenta and yellow. Mixing these you can have all colours. Now the inks
5193ff48bf5SDavid du Colombier are not pure, that is the cyan ink contains some particles that have a
5203ff48bf5SDavid du Colombier colour other than the ideal cyan and so on. In addition, the inks are
5213ff48bf5SDavid du Colombier not exactly cyan, magenta and yellow. Therefore, you have to do some
5223ff48bf5SDavid du Colombier transformations that will map the ideal C, M, Y values to amounts of
5233ff48bf5SDavid du Colombier ink of the real kind. You also have a black ink. Although in theory
5243ff48bf5SDavid du Colombier mixing C, M, Y in equal amount will give you black, it doesn't exactly
5253ff48bf5SDavid du Colombier work that way. In addition, black ink is cheap compared to the colour
5263ff48bf5SDavid du Colombier so if you can use black, you rather use that. On top of all that,
5273ff48bf5SDavid du Colombier because of other effects (ink splashing on the paper and things like that)
5283ff48bf5SDavid du Colombier you have to apply some non-linear functions to get reasonable colours.
5293ff48bf5SDavid du Colombier 
5303ff48bf5SDavid du Colombier Halftoning
5313ff48bf5SDavid du Colombier ----------
5323ff48bf5SDavid du Colombier 
5333ff48bf5SDavid du Colombier The driver has different halftoning methods.
5343ff48bf5SDavid du Colombier There is the classic Floyd-Stenberg error diffusion. There is an other
5353ff48bf5SDavid du Colombier ED, of which I'm hammering the matrix. The matrix is larger than the
5363ff48bf5SDavid du Colombier FS one and IMHO results in somewhat lower halftoning noise. However,
5373ff48bf5SDavid du Colombier it completely screws up some flat colours so don't use it.
5383ff48bf5SDavid du Colombier There is also dithering, which is quick but noisy.
5393ff48bf5SDavid du Colombier 
5403ff48bf5SDavid du Colombier For any halftoning method, it is assumed that the haltoning can be
5413ff48bf5SDavid du Colombier done on the 4 colours (CMYK) separately and all interdependencies are
5423ff48bf5SDavid du Colombier already handled. It is an optimistic assumption, however, close enough.
5433ff48bf5SDavid du Colombier 
5443ff48bf5SDavid du Colombier You can add any halftoning method you like by writing a halftoner
5453ff48bf5SDavid du Colombier module. A halftoner module consists of 4 functions:
5463ff48bf5SDavid du Colombier 
5473ff48bf5SDavid du Colombier - Init, which is called before halftoning starts.
5483ff48bf5SDavid du Colombier - Threshold, which should return a number which tells the driver how many
5493ff48bf5SDavid du Colombier   empty lines needed before halftoning can be stopped (i.e. for how many
5503ff48bf5SDavid du Colombier   lines will a line affect halftoning of subsequent lines).
5513ff48bf5SDavid du Colombier - Halftone, which halftones one colour of one line
5523ff48bf5SDavid du Colombier - EndOfLine which is called when all colours of a scanline are halftoned,
5533ff48bf5SDavid du Colombier   you can do your housekeeping functions here.
5543ff48bf5SDavid du Colombier 
5553ff48bf5SDavid du Colombier For example, in the case of ED init() clears the error buffers, threshold()
5563ff48bf5SDavid du Colombier returns ~5 (5 empty lines are enough for the accumulated error to go to
5573ff48bf5SDavid du Colombier almost zero), endofline() shuffles the error buffers and halftone() itself
5583ff48bf5SDavid du Colombier does the error diffusion. In case of dithering, threshold is 0 (dithering
5593ff48bf5SDavid du Colombier has no memory), init and endofline do nothing and halftone simply
5603ff48bf5SDavid du Colombier dithers a line.
5613ff48bf5SDavid du Colombier 
5623ff48bf5SDavid du Colombier A few options are available for all halftoners:
5633ff48bf5SDavid du Colombier 
5643ff48bf5SDavid du Colombier - the black is rendered first. Now this black line is presented to all
5653ff48bf5SDavid du Colombier   further passes. If a pixel is painted black, there's no point to
5663ff48bf5SDavid du Colombier   deposit any other colour on it, even if the halftoning itself would do.
5673ff48bf5SDavid du Colombier   Therefore, an already set black pixel can block the halftoning of colours
5683ff48bf5SDavid du Colombier   for that pixel. Whether this thing is activated or not is a command line
5693ff48bf5SDavid du Colombier   switch (default is on). Your halftoner may choose to ignore this flag.
5703ff48bf5SDavid du Colombier 
5713ff48bf5SDavid du Colombier - the intensity value of the light-cyan and light-magenta ink can be
5723ff48bf5SDavid du Colombier   set from the command line. My experience is that the default 127 is
5733ff48bf5SDavid du Colombier   good enough, but you can override it if you want to.
5743ff48bf5SDavid du Colombier 
5753ff48bf5SDavid du Colombier Apart from these features, each halftoner can have all sorts of other
5763ff48bf5SDavid du Colombier switches. Currently there are switches for the Bendor ED, see the
5773ff48bf5SDavid du Colombier comments in front of the BendorLine() function to see what they are.
5783ff48bf5SDavid du Colombier 
5793ff48bf5SDavid du Colombier Postprocessing
5803ff48bf5SDavid du Colombier --------------
5813ff48bf5SDavid du Colombier 
5823ff48bf5SDavid du Colombier After lines are halftoned, they are packed into bitstreams. If you use
5833ff48bf5SDavid du Colombier 1440x720 then the 2 passes for the horizontal interleave are separated.
5843ff48bf5SDavid du Colombier Postprocessing should also do the shingling/depletion, but it is not
5853ff48bf5SDavid du Colombier yet done.
5863ff48bf5SDavid du Colombier 
5873ff48bf5SDavid du Colombier Compression
5883ff48bf5SDavid du Colombier -----------
5893ff48bf5SDavid du Colombier 
5903ff48bf5SDavid du Colombier The driver, before it sends the data to the printer, compresses it using
5913ff48bf5SDavid du Colombier RLE (run-length encoding) compression. It is not very effective but still
5923ff48bf5SDavid du Colombier more than nothing. I have not yet ventured into using TIFF as output format,
5933ff48bf5SDavid du Colombier it may come later.
5943ff48bf5SDavid du Colombier 
5953ff48bf5SDavid du Colombier */
5963ff48bf5SDavid du Colombier 
5973ff48bf5SDavid du Colombier /****************************************************************************/
5983ff48bf5SDavid du Colombier /*						Device specific definitions							*/
5993ff48bf5SDavid du Colombier /****************************************************************************/
6003ff48bf5SDavid du Colombier 
6013ff48bf5SDavid du Colombier /*
6023ff48bf5SDavid du Colombier *	Device limits
6033ff48bf5SDavid du Colombier */
6043ff48bf5SDavid du Colombier 
6053ff48bf5SDavid du Colombier #define	MAX_WIDTH	11.46			/* Maximum printable width, 8250 dots	*/
6063ff48bf5SDavid du Colombier #define	MAX_PIXELS	8250
6073ff48bf5SDavid du Colombier #define	MAX_BYTES	(MAX_PIXELS+7)/8
6083ff48bf5SDavid du Colombier 
6093ff48bf5SDavid du Colombier /*
6103ff48bf5SDavid du Colombier *	Margins (in inch)
6113ff48bf5SDavid du Colombier */
6123ff48bf5SDavid du Colombier 
6133ff48bf5SDavid du Colombier #define	MARGIN_L	0.12			/* Left margin							*/
6143ff48bf5SDavid du Colombier #define	MARGIN_R	0.12			/* Right margin							*/
6153ff48bf5SDavid du Colombier #define	MARGIN_T	0.12			/* Top margin							*/
6163ff48bf5SDavid du Colombier #define	MARGIN_B	0.50			/* Bottom margin (should be 0.54 !)		*/
6173ff48bf5SDavid du Colombier 
6183ff48bf5SDavid du Colombier /*
6193ff48bf5SDavid du Colombier *	We default to 720x720 dpi
6203ff48bf5SDavid du Colombier */
6213ff48bf5SDavid du Colombier 
6223ff48bf5SDavid du Colombier #define	Y_DPI		720				/* Default vertical resolution	[dpi]	*/
6233ff48bf5SDavid du Colombier #define	X_DPI		720				/* Default horizontal resolution [dpi]	*/
6243ff48bf5SDavid du Colombier 
6253ff48bf5SDavid du Colombier /*
6263ff48bf5SDavid du Colombier *	Encoding of resolutions. Does *not* work with 1440 dpi !
6273ff48bf5SDavid du Colombier */
6283ff48bf5SDavid du Colombier 
6293ff48bf5SDavid du Colombier #define	RESCODE( x )	(3600/(x))
6303ff48bf5SDavid du Colombier 
6313ff48bf5SDavid du Colombier /*
6323ff48bf5SDavid du Colombier *	The device has 6 different inks
6333ff48bf5SDavid du Colombier */
6343ff48bf5SDavid du Colombier 
6353ff48bf5SDavid du Colombier #define	DCOLN			6
6363ff48bf5SDavid du Colombier 
6373ff48bf5SDavid du Colombier /*
6383ff48bf5SDavid du Colombier *	Device colour codes
6393ff48bf5SDavid du Colombier *	CAVEAT: if you change them change the SendColour() procedure too !
6403ff48bf5SDavid du Colombier */
6413ff48bf5SDavid du Colombier 
6423ff48bf5SDavid du Colombier #define	DEV_BLACK		0
6433ff48bf5SDavid du Colombier #define	DEV_CYAN		1
6443ff48bf5SDavid du Colombier #define	DEV_MAGENTA		2
6453ff48bf5SDavid du Colombier #define	DEV_YELLOW		3
6463ff48bf5SDavid du Colombier #define	DEV_LCYAN		4
6473ff48bf5SDavid du Colombier #define	DEV_LMAGENTA	5
6483ff48bf5SDavid du Colombier 
6493ff48bf5SDavid du Colombier /*
6503ff48bf5SDavid du Colombier *	The head has 32 nozzles, with 8 x 1/720" spacing
6513ff48bf5SDavid du Colombier */
6523ff48bf5SDavid du Colombier 
6533ff48bf5SDavid du Colombier #define	NOZZLES			32
6543ff48bf5SDavid du Colombier #define	HEAD_SPACING	8
6553ff48bf5SDavid du Colombier 
6563ff48bf5SDavid du Colombier /*
6573ff48bf5SDavid du Colombier *	Some ASCII control characters
6583ff48bf5SDavid du Colombier */
6593ff48bf5SDavid du Colombier 
6603ff48bf5SDavid du Colombier #define	CR				13			/* Carriage return						*/
6613ff48bf5SDavid du Colombier #define	FF				12			/* Form feed							*/
6623ff48bf5SDavid du Colombier #define	ESC				"\033"		/* Escape								*/
6633ff48bf5SDavid du Colombier 
6643ff48bf5SDavid du Colombier /****************************************************************************/
6653ff48bf5SDavid du Colombier /*						Internally used definitions							*/
6663ff48bf5SDavid du Colombier /****************************************************************************/
6673ff48bf5SDavid du Colombier 
6683ff48bf5SDavid du Colombier #ifndef	TRUE
6693ff48bf5SDavid du Colombier #define	TRUE	1
6703ff48bf5SDavid du Colombier #endif
6713ff48bf5SDavid du Colombier 
6723ff48bf5SDavid du Colombier #ifndef	FALSE
6733ff48bf5SDavid du Colombier #define	FALSE	0
6743ff48bf5SDavid du Colombier #endif
6753ff48bf5SDavid du Colombier 
6763ff48bf5SDavid du Colombier /*
6773ff48bf5SDavid du Colombier *	Since the printer is CMYK, we use 4 colours internally
6783ff48bf5SDavid du Colombier */
6793ff48bf5SDavid du Colombier 
6803ff48bf5SDavid du Colombier #define	ICOLN			4
6813ff48bf5SDavid du Colombier 
6823ff48bf5SDavid du Colombier /*
6833ff48bf5SDavid du Colombier *	This is the maximum number of error lines needed by any
6843ff48bf5SDavid du Colombier *	currently implemented rendering function.
6853ff48bf5SDavid du Colombier *	If you need more, increase it.
6863ff48bf5SDavid du Colombier */
6873ff48bf5SDavid du Colombier 
6883ff48bf5SDavid du Colombier #define	MAX_ED_LINES	3
6893ff48bf5SDavid du Colombier 
6903ff48bf5SDavid du Colombier /*
6913ff48bf5SDavid du Colombier *	If this is defined to !0 then we use Adobe's CMYK -> RGB mapping,
6923ff48bf5SDavid du Colombier *	Ghostscript's otherwise. Ghostscript claims that their mapping
6933ff48bf5SDavid du Colombier *	is better. The mapping of CMYK to RGB according to Adobe is:
6943ff48bf5SDavid du Colombier *
6953ff48bf5SDavid du Colombier *		R = 1.0 - min( 1.0, C + K )
6963ff48bf5SDavid du Colombier *		G = 1.0 - min( 1.0, M + K )
6973ff48bf5SDavid du Colombier *		B = 1.0 - min( 1.0, Y + K )
6983ff48bf5SDavid du Colombier *
6993ff48bf5SDavid du Colombier *	while Ghostscript uses this:
7003ff48bf5SDavid du Colombier *
7013ff48bf5SDavid du Colombier *		R = ( 1.0 - C ) * ( 1.0 - K )
7023ff48bf5SDavid du Colombier *		G = ( 1.0 - M ) * ( 1.0 - K )
7033ff48bf5SDavid du Colombier *		B = ( 1.0 - Y ) * ( 1.0 - K )
7043ff48bf5SDavid du Colombier */
7053ff48bf5SDavid du Colombier 
7063ff48bf5SDavid du Colombier #define	MAP_RGB_ADOBE	0
7073ff48bf5SDavid du Colombier 
7083ff48bf5SDavid du Colombier /*
7093ff48bf5SDavid du Colombier *	We store a CMYK value in a 32 bit entity, each component being 8 bit.
7103ff48bf5SDavid du Colombier *	These macros pack and unpack these blocks.
7113ff48bf5SDavid du Colombier *	Ghostscript guarantees that when we get them back the unsigned long
7123ff48bf5SDavid du Colombier *	will be placed in memory in a big-endian format (regardless of the
7133ff48bf5SDavid du Colombier *	actual architecture it's running on), so we declare the colour offsets
7143ff48bf5SDavid du Colombier *	accordingly.
7153ff48bf5SDavid du Colombier */
7163ff48bf5SDavid du Colombier 
7173ff48bf5SDavid du Colombier #define	OFFS_C		0
7183ff48bf5SDavid du Colombier #define	OFFS_M		1
7193ff48bf5SDavid du Colombier #define	OFFS_Y		2
7203ff48bf5SDavid du Colombier #define	OFFS_K		3
7213ff48bf5SDavid du Colombier 
7223ff48bf5SDavid du Colombier #define	DECOMPOSE_CMYK( index, c, m, y, k ) \
7233ff48bf5SDavid du Colombier 	{										\
7243ff48bf5SDavid du Colombier 		(k) = (index) & 255;				\
7253ff48bf5SDavid du Colombier 		(y) = ( (index) >> 8 ) & 255;		\
7263ff48bf5SDavid du Colombier 		(m) = ( (index) >> 16 ) & 255;		\
7273ff48bf5SDavid du Colombier 		(c) = ( (index) >> 24 ) & 255; 		\
7283ff48bf5SDavid du Colombier 	}
7293ff48bf5SDavid du Colombier 
7303ff48bf5SDavid du Colombier #define	BUILD_CMYK( c, m, y, k ) \
7313ff48bf5SDavid du Colombier 	((((long)(c)&255)<<24)|(((long)(m)&255)<<16)|\
7323ff48bf5SDavid du Colombier 	(((long)(y)&255)<<8)|((long)(k)&255))
7333ff48bf5SDavid du Colombier 
7343ff48bf5SDavid du Colombier /*
7353ff48bf5SDavid du Colombier *	This structure is for colour compensation
7363ff48bf5SDavid du Colombier */
7373ff48bf5SDavid du Colombier 
7383ff48bf5SDavid du Colombier typedef	struct {
7393ff48bf5SDavid du Colombier 
7403ff48bf5SDavid du Colombier 	int		ra;						/* Real colour angle (hue)				*/
7413ff48bf5SDavid du Colombier 	int		ia;						/* Theoretical ink colour angle 		*/
7423ff48bf5SDavid du Colombier 	int		c;						/* Cyan component						*/
7433ff48bf5SDavid du Colombier 	int		m;						/* Magenta component					*/
7443ff48bf5SDavid du Colombier 	int		y;						/* Yellow component						*/
7453ff48bf5SDavid du Colombier 
7463ff48bf5SDavid du Colombier } CCOMP;
7473ff48bf5SDavid du Colombier 
7483ff48bf5SDavid du Colombier /*
7493ff48bf5SDavid du Colombier *	Our device structure has some extensions
7503ff48bf5SDavid du Colombier */
7513ff48bf5SDavid du Colombier 
7523ff48bf5SDavid du Colombier typedef	struct gx_photoex_device_s {
7533ff48bf5SDavid du Colombier 
7543ff48bf5SDavid du Colombier 	gx_device_common;				/* This macro defines a graphics dev.	*/
7553ff48bf5SDavid du Colombier 	gx_prn_device_common;			/* This macro extends for printer dev.	*/
7563ff48bf5SDavid du Colombier 	int		shingling;				/* Shingling (multipass, overlap) mode	*/
7573ff48bf5SDavid du Colombier 	int		depletion;				/* Excess dot removal					*/
7583ff48bf5SDavid du Colombier 	int		halftoner;				/* Rendering type						*/
7593ff48bf5SDavid du Colombier 	int		splash;					/* Splashing compensation factor		*/
7603ff48bf5SDavid du Colombier 	int		leakage;				/* Error leakage (percentage)			*/
7613ff48bf5SDavid du Colombier 	int		mono;					/* Monochrome mode (black only)			*/
7623ff48bf5SDavid du Colombier 	int		pureblack;				/* Black ink blocks others				*/
7633ff48bf5SDavid du Colombier 	int		midcyan;				/* Light cyan ink value					*/
7643ff48bf5SDavid du Colombier 	int		midmagenta;				/* Light magenta ink value				*/
7653ff48bf5SDavid du Colombier 	int		dotsize;				/* Size of the ink dot					*/
7663ff48bf5SDavid du Colombier 
7673ff48bf5SDavid du Colombier } gx_photoex_device;
7683ff48bf5SDavid du Colombier 
7693ff48bf5SDavid du Colombier /*
7703ff48bf5SDavid du Colombier *	These can save some typing
7713ff48bf5SDavid du Colombier */
7723ff48bf5SDavid du Colombier 
7733ff48bf5SDavid du Colombier typedef	gx_device			DEV;
7743ff48bf5SDavid du Colombier typedef	gx_device_printer	PDEV;
7753ff48bf5SDavid du Colombier typedef	gx_photoex_device	EDEV;
7763ff48bf5SDavid du Colombier typedef	gx_color_index		CINX;
7773ff48bf5SDavid du Colombier typedef	gx_color_value		CVAL;
7783ff48bf5SDavid du Colombier typedef	gs_param_list		PLIST;
7793ff48bf5SDavid du Colombier typedef	gs_param_name		PNAME;
7803ff48bf5SDavid du Colombier 
7813ff48bf5SDavid du Colombier /*
7823ff48bf5SDavid du Colombier *	How many lines do we have to think ahead
7833ff48bf5SDavid du Colombier */
7843ff48bf5SDavid du Colombier 
7853ff48bf5SDavid du Colombier #define	MAX_MARK		((NOZZLES)*(HEAD_SPACING))
7863ff48bf5SDavid du Colombier 
7873ff48bf5SDavid du Colombier /*
7883ff48bf5SDavid du Colombier *	This structure stores a device scanline for one colour
7893ff48bf5SDavid du Colombier */
7903ff48bf5SDavid du Colombier 
7913ff48bf5SDavid du Colombier typedef	struct	{
7923ff48bf5SDavid du Colombier 
7933ff48bf5SDavid du Colombier 	int		first;					/* Index of the first useful byte	*/
7943ff48bf5SDavid du Colombier 	int		last;					/* Index of the last useful byte	*/
7953ff48bf5SDavid du Colombier 	byte	data[ MAX_BYTES ];		/* Actual raw data					*/
7963ff48bf5SDavid du Colombier 
7973ff48bf5SDavid du Colombier } RAWLINE;
7983ff48bf5SDavid du Colombier 
7993ff48bf5SDavid du Colombier /*
8003ff48bf5SDavid du Colombier *	These definitions are used by the microweave scheduler.
8013ff48bf5SDavid du Colombier *	These are the band height definitions. Do not fiddle with them,
8023ff48bf5SDavid du Colombier *	they are the largest number with which no lines are skipped
8033ff48bf5SDavid du Colombier *	and the unused nozzles in the head for each band is minimal.
8043ff48bf5SDavid du Colombier *	They, of course, depend on the number of nozzles in the head
8053ff48bf5SDavid du Colombier *	and their spacing, these numbers are for 32 and 8, respectively.
8063ff48bf5SDavid du Colombier */
8073ff48bf5SDavid du Colombier 
8083ff48bf5SDavid du Colombier #define	BAND_1440		13			/* Band height for 1440dpi, double scan	*/
8093ff48bf5SDavid du Colombier #define	BAND_720		31			/* Band height for 720dpi, single scan	*/
8103ff48bf5SDavid du Colombier #define	BAND_360		1			/* Band height for 360dpi, single scan	*/
8113ff48bf5SDavid du Colombier 
8123ff48bf5SDavid du Colombier #define	NOZZLE_1440		(NOZZLES)	/* Number of nozzles used for 1440dpi	*/
8133ff48bf5SDavid du Colombier #define	NOZZLE_720		(NOZZLES)	/* Number of nozzles used for 720dpi	*/
8143ff48bf5SDavid du Colombier #define	NOZZLE_360		1			/* Number of nozzles used for 360dpi	*/
8153ff48bf5SDavid du Colombier 
8163ff48bf5SDavid du Colombier /*
8173ff48bf5SDavid du Colombier *	This structure is used to generate the line scheduling data.
8183ff48bf5SDavid du Colombier *	Input/output refers to the scheduler I/F: input means data
8193ff48bf5SDavid du Colombier *	given to the scheduler, output is what it gives back. Unspecified
8203ff48bf5SDavid du Colombier *	data is scheduler private.
8213ff48bf5SDavid du Colombier */
8223ff48bf5SDavid du Colombier 
8233ff48bf5SDavid du Colombier typedef	struct {
8243ff48bf5SDavid du Colombier 
8253ff48bf5SDavid du Colombier 	int		last;					/* Input	Last line to print			*/
8263ff48bf5SDavid du Colombier 	int		resol;					/* Input	X Resolution				*/
8273ff48bf5SDavid du Colombier 	int		nozzle;					/* Output	Number of nozzles			*/
8283ff48bf5SDavid du Colombier 	int		down;					/* Output	Lines to move down			*/
8293ff48bf5SDavid du Colombier 	int		head[ NOZZLES ];		/* Output	Which lines to be sent		*/
8303ff48bf5SDavid du Colombier 	int		offset;					/* Output	Offset line by 1/1440"		*/
8313ff48bf5SDavid du Colombier 	int		top;					/* 			Head position now			*/
8323ff48bf5SDavid du Colombier 	int		markbeg;				/* 			First marked line			*/
8333ff48bf5SDavid du Colombier 	byte	mark[ MAX_MARK ];		/* 			Marks already printed lines	*/
8343ff48bf5SDavid du Colombier 
8353ff48bf5SDavid du Colombier } SCHEDUL;
8363ff48bf5SDavid du Colombier 
8373ff48bf5SDavid du Colombier /*
8383ff48bf5SDavid du Colombier *	These macros are used to access the printer device
8393ff48bf5SDavid du Colombier */
8403ff48bf5SDavid du Colombier 
8413ff48bf5SDavid du Colombier #define	SendByte( s, x )	fputc( (x), (s) )
8423ff48bf5SDavid du Colombier 
8433ff48bf5SDavid du Colombier #define	SendWord( s, x )	SendByte((s), (x) & 255); \
8443ff48bf5SDavid du Colombier 							SendByte((s), ((x) >> 8 ) & 255);
8453ff48bf5SDavid du Colombier 
8463ff48bf5SDavid du Colombier /*
8473ff48bf5SDavid du Colombier *	This structure stores all the data during rendering
8483ff48bf5SDavid du Colombier */
8493ff48bf5SDavid du Colombier 
8503ff48bf5SDavid du Colombier typedef	struct {
8513ff48bf5SDavid du Colombier 
8523ff48bf5SDavid du Colombier 	EDEV	*dev;					/* The actual device struct			*/
8533ff48bf5SDavid du Colombier 	FILE	*stream;				/* Output stream					*/
8543ff48bf5SDavid du Colombier 	int		yres;					/* Y resolution						*/
8553ff48bf5SDavid du Colombier 	int		xres;					/* X resolution						*/
8563ff48bf5SDavid du Colombier 	int		start;					/* Left margin in 1/1440 inches		*/
8573ff48bf5SDavid du Colombier 	int		width;					/* Input data width in pixels		*/
8583ff48bf5SDavid du Colombier 	int		lines;					/* Number of lines					*/
8593ff48bf5SDavid du Colombier 	int		mono;					/* Black only						*/
8603ff48bf5SDavid du Colombier 	byte	*dbuff;					/* Data buffer 						*/
8613ff48bf5SDavid du Colombier 	int		htone_thold;			/* Halftoner restart threshold		*/
8623ff48bf5SDavid du Colombier 	int		htone_last;				/* Last line halftoned				*/
8633ff48bf5SDavid du Colombier 	SCHEDUL	schedule;				/* Line scheduling info				*/
8643ff48bf5SDavid du Colombier 
8653ff48bf5SDavid du Colombier 	/* These are the error buffers for error diffusion. MAX_PIXELS*2
8663ff48bf5SDavid du Colombier 	   is needed for 1440 dpi printing. */
8673ff48bf5SDavid du Colombier 
8683ff48bf5SDavid du Colombier 	short	err[ MAX_ED_LINES ][ ICOLN ][ MAX_PIXELS*2 ];
8693ff48bf5SDavid du Colombier 
8703ff48bf5SDavid du Colombier 	/* Error buffer pointers. I love C :-) */
8713ff48bf5SDavid du Colombier 
8723ff48bf5SDavid du Colombier 	short	( *error[ MAX_ED_LINES ] )[ MAX_PIXELS*2 ];
8733ff48bf5SDavid du Colombier 
8743ff48bf5SDavid du Colombier 	/* This stores the halftoning result for a line,
8753ff48bf5SDavid du Colombier 	   not yet in device format. (It's CMYK 1 byte/pixel/colour) */
8763ff48bf5SDavid du Colombier 
8773ff48bf5SDavid du Colombier 	byte	res[ ICOLN ][ MAX_PIXELS*2 ];
8783ff48bf5SDavid du Colombier 
8793ff48bf5SDavid du Colombier 	/* This is the buffer for rendered lines, converted
8803ff48bf5SDavid du Colombier 	   to raw device data (not yet run-length encoded).
8813ff48bf5SDavid du Colombier 	   That is, it's 6 colours, 1 bit/pixel/colour.
8823ff48bf5SDavid du Colombier 	   The first index is the 1440 dpi X-weave phase. */
8833ff48bf5SDavid du Colombier 
8843ff48bf5SDavid du Colombier 	RAWLINE	raw[ 2 ][ DCOLN ][ MAX_MARK ];
8853ff48bf5SDavid du Colombier 
8863ff48bf5SDavid du Colombier 	/* This buffer stores a single line of one colour,
8873ff48bf5SDavid du Colombier 	   run-length encoded, ready to send to the printer */
8883ff48bf5SDavid du Colombier 
8893ff48bf5SDavid du Colombier 	byte	rle[ MAX_PIXELS * 2 ];
8903ff48bf5SDavid du Colombier 
8913ff48bf5SDavid du Colombier } RENDER;
8923ff48bf5SDavid du Colombier 
8933ff48bf5SDavid du Colombier /*
8943ff48bf5SDavid du Colombier *	This is the sctructure used by the actual halftoner algorithms
8953ff48bf5SDavid du Colombier */
8963ff48bf5SDavid du Colombier 
8973ff48bf5SDavid du Colombier typedef	struct	{
8983ff48bf5SDavid du Colombier 
8993ff48bf5SDavid du Colombier 	RENDER	*render;				/* Render info, if needed				*/
9003ff48bf5SDavid du Colombier 	byte	*data;					/* Input data							*/
9013ff48bf5SDavid du Colombier 	int 	step;					/* Steps on input data					*/
9023ff48bf5SDavid du Colombier 	byte	*res;					/* Result								*/
9033ff48bf5SDavid du Colombier 	byte	*block;					/* Blocking data						*/
9043ff48bf5SDavid du Colombier 	short	**err;					/* Pointers to error buffers			*/
9053ff48bf5SDavid du Colombier 	int		lim1; 					/* Halftoning lower limit				*/
9063ff48bf5SDavid du Colombier 	int		lim2; 					/* Halftoning upper limit				*/
9073ff48bf5SDavid du Colombier 	int		mval; 					/* Level represented by 'light' colour	*/
9083ff48bf5SDavid du Colombier 
9093ff48bf5SDavid du Colombier } HTONE;
9103ff48bf5SDavid du Colombier 
9113ff48bf5SDavid du Colombier /*
9123ff48bf5SDavid du Colombier *	Halftoner function table
9133ff48bf5SDavid du Colombier */
9143ff48bf5SDavid du Colombier 
9153ff48bf5SDavid du Colombier typedef	struct {
9163ff48bf5SDavid du Colombier 
9173ff48bf5SDavid du Colombier 	int		(*hthld)( RENDER *rend );
9183ff48bf5SDavid du Colombier 	void	(*hstrt)( RENDER *rend, int line );
9193ff48bf5SDavid du Colombier 	void	(*hteol)( RENDER *rend, int line );
9203ff48bf5SDavid du Colombier 	void	(*htone)( HTONE *htone, int line );
9213ff48bf5SDavid du Colombier 
9223ff48bf5SDavid du Colombier } HFUNCS;
9233ff48bf5SDavid du Colombier 
9243ff48bf5SDavid du Colombier /*
9253ff48bf5SDavid du Colombier *	Number of known halftoning methods
9263ff48bf5SDavid du Colombier */
9273ff48bf5SDavid du Colombier 
9283ff48bf5SDavid du Colombier #define	MAXHTONE		3
9293ff48bf5SDavid du Colombier 
9303ff48bf5SDavid du Colombier /*
9313ff48bf5SDavid du Colombier *	Dither matrix size
9323ff48bf5SDavid du Colombier */
9333ff48bf5SDavid du Colombier 
9343ff48bf5SDavid du Colombier #define	DMATRIX_X		16
9353ff48bf5SDavid du Colombier #define	DMATRIX_Y		16
9363ff48bf5SDavid du Colombier 
9373ff48bf5SDavid du Colombier /****************************************************************************/
9383ff48bf5SDavid du Colombier /*							Prototypes										*/
9393ff48bf5SDavid du Colombier /****************************************************************************/
9403ff48bf5SDavid du Colombier 
9413ff48bf5SDavid du Colombier private int		photoex_open( gx_device *pdev );
9423ff48bf5SDavid du Colombier private	int		photoex_print_page( PDEV *dev, FILE *prn_stream );
9433ff48bf5SDavid du Colombier private	CINX	photoex_map_rgb_color( DEV *dev, CVAL r, CVAL g, CVAL b );
9443ff48bf5SDavid du Colombier private int		photoex_map_color_rgb( DEV *dev, CINX index, CVAL prgb[3] );
9453ff48bf5SDavid du Colombier private	int		photoex_get_params( DEV *dev, PLIST *plist );
9463ff48bf5SDavid du Colombier private	int		photoex_put_params( DEV *dev, PLIST *plist );
9473ff48bf5SDavid du Colombier 
9483ff48bf5SDavid du Colombier private int 	PutInt( PLIST *plist, PNAME name, int *val,
9493ff48bf5SDavid du Colombier 						int minval, int maxval, int code );
9503ff48bf5SDavid du Colombier private	int		GetInt( PLIST *list, PNAME name, int *value, int code );
9513ff48bf5SDavid du Colombier 
9523ff48bf5SDavid du Colombier private	int		Cmy2A( int c, int m, int y );
9533ff48bf5SDavid du Colombier 
9543ff48bf5SDavid du Colombier private	void	SchedulerInit( SCHEDUL *p );
9553ff48bf5SDavid du Colombier private	int		ScheduleLines( SCHEDUL *p );
9563ff48bf5SDavid du Colombier private	void	ScheduleLeading( SCHEDUL *p );
9573ff48bf5SDavid du Colombier private	void	ScheduleMiddle( SCHEDUL *p );
9583ff48bf5SDavid du Colombier private	void	ScheduleTrailing( SCHEDUL *p );
9593ff48bf5SDavid du Colombier private	void	ScheduleBand( SCHEDUL *p, int mask );
9603ff48bf5SDavid du Colombier 
9613ff48bf5SDavid du Colombier private	void	RenderPage( RENDER *p );
9623ff48bf5SDavid du Colombier private	void	RenderLine( RENDER *p, int line );
9633ff48bf5SDavid du Colombier private	int		IsScanlineEmpty( RENDER *p, byte *line );
9643ff48bf5SDavid du Colombier 
9653ff48bf5SDavid du Colombier private	int		RleCompress( RAWLINE *raw, int min, int max, byte *rle_data );
9663ff48bf5SDavid du Colombier private	int		RleFlush( byte *first, byte *reps, byte *now, byte *out );
9673ff48bf5SDavid du Colombier 
9683ff48bf5SDavid du Colombier private	void	SendReset( FILE *stream );
9693ff48bf5SDavid du Colombier private	void	SendMargin( FILE *stream, int top, int bot );
9703ff48bf5SDavid du Colombier private	void	SendPaper( FILE *stream, int length );
9713ff48bf5SDavid du Colombier private	void	SendGmode( FILE *stream, int on );
9723ff48bf5SDavid du Colombier private void	SendUnit( FILE *stream, int res );
9733ff48bf5SDavid du Colombier private	void	SendUnidir( FILE *stream, int on );
9743ff48bf5SDavid du Colombier private	void	SendMicro( FILE *stream, int on );
9753ff48bf5SDavid du Colombier private void	SendInk( FILE *stream, int x );
9763ff48bf5SDavid du Colombier private	void	SendDown( FILE *stream, int x );
9773ff48bf5SDavid du Colombier private	void	SendRight( FILE *stream, int amount );
9783ff48bf5SDavid du Colombier private	void	SendColour( FILE *stream, int col );
9793ff48bf5SDavid du Colombier private void	SendData( FILE *stream, int hres, int vres, int noz, int col );
9803ff48bf5SDavid du Colombier private	void	SendString( FILE *stream, const char *s );
9813ff48bf5SDavid du Colombier 
9823ff48bf5SDavid du Colombier private	void	HalftonerStart( RENDER *render, int line );
9833ff48bf5SDavid du Colombier private	int		HalftoneThold( RENDER *render );
9843ff48bf5SDavid du Colombier private	void	HalftoneLine( RENDER *render, int line, byte *data );
9853ff48bf5SDavid du Colombier 
9863ff48bf5SDavid du Colombier private	int		BendorThold( RENDER *p );
9873ff48bf5SDavid du Colombier private	void	BendorStart( RENDER *p, int line );
9883ff48bf5SDavid du Colombier private	void	BendorEol( RENDER *p, int line );
9893ff48bf5SDavid du Colombier private	void	BendorLine( HTONE *htone, int y );
9903ff48bf5SDavid du Colombier 
9913ff48bf5SDavid du Colombier private	int		FloydSThold( RENDER *p );
9923ff48bf5SDavid du Colombier private	void	FloydSStart( RENDER *p, int line );
9933ff48bf5SDavid du Colombier private	void	FloydSEol( RENDER *p, int line );
9943ff48bf5SDavid du Colombier private	void	FloydSLine( HTONE *htone, int y );
9953ff48bf5SDavid du Colombier 
9963ff48bf5SDavid du Colombier private	int		DitherThold( RENDER *p );
9973ff48bf5SDavid du Colombier private	void	DitherStart( RENDER *p, int line );
9983ff48bf5SDavid du Colombier private	void	DitherEol( RENDER *p, int line );
9993ff48bf5SDavid du Colombier private	void	DitherLine( HTONE *htone, int y );
10003ff48bf5SDavid du Colombier 
10013ff48bf5SDavid du Colombier /****************************************************************************/
10023ff48bf5SDavid du Colombier /*							Static data										*/
10033ff48bf5SDavid du Colombier /****************************************************************************/
10043ff48bf5SDavid du Colombier 
10053ff48bf5SDavid du Colombier /*
10063ff48bf5SDavid du Colombier *	Halftoner function table
10073ff48bf5SDavid du Colombier */
10083ff48bf5SDavid du Colombier 
10093ff48bf5SDavid du Colombier private	const HFUNCS	htable[ MAXHTONE ] = {
10103ff48bf5SDavid du Colombier 
10113ff48bf5SDavid du Colombier 	{ FloydSThold, FloydSStart, FloydSEol, FloydSLine },
10123ff48bf5SDavid du Colombier 	{ DitherThold, DitherStart, DitherEol, DitherLine },
10133ff48bf5SDavid du Colombier 	{ BendorThold, BendorStart, BendorEol, BendorLine }
10143ff48bf5SDavid du Colombier };
10153ff48bf5SDavid du Colombier 
10163ff48bf5SDavid du Colombier /*
10173ff48bf5SDavid du Colombier *	Define the printer procedures.
10183ff48bf5SDavid du Colombier *	The definition is based on GS macros, the only real stuff that we
10193ff48bf5SDavid du Colombier *	define here are the photoex_ functions.
10203ff48bf5SDavid du Colombier */
10213ff48bf5SDavid du Colombier 
10223ff48bf5SDavid du Colombier private	gx_device_procs photoex_device_procs = prn_color_params_procs(
10233ff48bf5SDavid du Colombier 
10243ff48bf5SDavid du Colombier 	photoex_open,					/* Opens the device						*/
10253ff48bf5SDavid du Colombier 	gdev_prn_output_page,
10263ff48bf5SDavid du Colombier 	gdev_prn_close,
10273ff48bf5SDavid du Colombier 	photoex_map_rgb_color,			/* Maps an RGB pixel to device colour	*/
10283ff48bf5SDavid du Colombier 	photoex_map_color_rgb,			/* Maps device colour back to RGB		*/
10293ff48bf5SDavid du Colombier 	photoex_get_params,				/* Gets device parameters				*/
10303ff48bf5SDavid du Colombier 	photoex_put_params				/* Puts device parameters				*/
10313ff48bf5SDavid du Colombier );
10323ff48bf5SDavid du Colombier 
10333ff48bf5SDavid du Colombier /*
10343ff48bf5SDavid du Colombier *	Device descriptor structure - this is what GhostScript looks
10353ff48bf5SDavid du Colombier *	for and uses to identify our device.
10363ff48bf5SDavid du Colombier *	Do not make it private (or static) !
10373ff48bf5SDavid du Colombier */
10383ff48bf5SDavid du Colombier 
10393ff48bf5SDavid du Colombier gx_photoex_device far_data gs_photoex_device = {
10403ff48bf5SDavid du Colombier 
10413ff48bf5SDavid du Colombier 	/* This is a macro that fills GS specific fields in the struct */
10423ff48bf5SDavid du Colombier 
10433ff48bf5SDavid du Colombier 	prn_device_body(
10443ff48bf5SDavid du Colombier 
10453ff48bf5SDavid du Colombier 		gx_photoex_device,			/* Device struct type					*/
10463ff48bf5SDavid du Colombier 		photoex_device_procs, 		/* Procedure table						*/
10473ff48bf5SDavid du Colombier 		"photoex",					/* Name of the device					*/
10483ff48bf5SDavid du Colombier 		DEFAULT_WIDTH_10THS,		/* Default width						*/
10493ff48bf5SDavid du Colombier 		DEFAULT_HEIGHT_10THS,		/* Default height						*/
10503ff48bf5SDavid du Colombier 		X_DPI, 						/* Vertical resolution					*/
10513ff48bf5SDavid du Colombier 		Y_DPI,						/* Horizontal resolution				*/
10523ff48bf5SDavid du Colombier 		MARGIN_L, 					/* Left margin							*/
10533ff48bf5SDavid du Colombier 		MARGIN_B, 					/* Bottom margin						*/
10543ff48bf5SDavid du Colombier 		MARGIN_R,					/* Right margin							*/
10553ff48bf5SDavid du Colombier 		MARGIN_T, 					/* Top margin							*/
10563ff48bf5SDavid du Colombier 		ICOLN,						/* Number of colours (4:CMYK)			*/
10573ff48bf5SDavid du Colombier 		32,							/* Bit per pixel for the device(!)		*/
10583ff48bf5SDavid du Colombier 		255,						/* Max. gray level						*/
10593ff48bf5SDavid du Colombier 		255, 						/* Max. colour level					*/
10603ff48bf5SDavid du Colombier 		256,						/* Number of gray gradations			*/
10613ff48bf5SDavid du Colombier 		256,						/* Number of colour gradations			*/
10623ff48bf5SDavid du Colombier 		photoex_print_page			/* Print page procedure					*/
10633ff48bf5SDavid du Colombier 	),
10643ff48bf5SDavid du Colombier 
10653ff48bf5SDavid du Colombier 	/* Here come our extensions */
10663ff48bf5SDavid du Colombier 
10673ff48bf5SDavid du Colombier 	0,								/* Shingling off, not implemented		*/
10683ff48bf5SDavid du Colombier 	0,								/* Depletion off, not implemented		*/
10693ff48bf5SDavid du Colombier 	0,								/* Dither type: FS ED					*/
10703ff48bf5SDavid du Colombier 	0,								/* No splash correction					*/
10713ff48bf5SDavid du Colombier 	0,								/* No leakage							*/
10723ff48bf5SDavid du Colombier 	0,								/* Not monochrome						*/
10733ff48bf5SDavid du Colombier 	1,								/* Colour inhibition on black			*/
10743ff48bf5SDavid du Colombier 	127,							/* Mid level cyan						*/
10753ff48bf5SDavid du Colombier 	127,							/* Mid level magenta					*/
10763ff48bf5SDavid du Colombier 	0								/* Automatic dot size setting			*/
10773ff48bf5SDavid du Colombier };
10783ff48bf5SDavid du Colombier 
10793ff48bf5SDavid du Colombier /*
10803ff48bf5SDavid du Colombier *	This table contains the line scheduling table for the first
10813ff48bf5SDavid du Colombier *	few runs if we are in 720 dpi mode.
10823ff48bf5SDavid du Colombier */
10833ff48bf5SDavid du Colombier 
10843ff48bf5SDavid du Colombier private	const int	start_720[ HEAD_SPACING ][ NOZZLES ] = {
10853ff48bf5SDavid du Colombier 
10863ff48bf5SDavid du Colombier 	{	  0,	  8,	 16,	 24,	 32,	 40,	 48,	 56,
10873ff48bf5SDavid du Colombier 		 64,	 72,	 80,	 88,	 96,	104,	112,	120,
10883ff48bf5SDavid du Colombier 		128,	136,	144,	152,	160,	168,	176,	184,
10893ff48bf5SDavid du Colombier 		192,	200,	208,	216,	224,	232,	240,	248 },
10903ff48bf5SDavid du Colombier 
10913ff48bf5SDavid du Colombier 	{	  1,	  9,	 17,	 25,	 33,	 41,	 49,	 57,
10923ff48bf5SDavid du Colombier 		 65,	 73,	 81,	 89,	 97,	105,	113,	121,
10933ff48bf5SDavid du Colombier 		129,	137,	145,	153,	161,	169,	177,	185,
10943ff48bf5SDavid du Colombier 		193,	201,	209,	 -1,	 -1,	 -1,	 -1,	 -1 },
10953ff48bf5SDavid du Colombier 
10963ff48bf5SDavid du Colombier 	{	  2,	 10,	 18,	 26,	 34,	 42,	 50,	 58,
10973ff48bf5SDavid du Colombier 		 66,	 74,	 82,	 90,	 98,	106,	114,	122,
10983ff48bf5SDavid du Colombier 		130,	138,	146,	154,	162,	170,	178,	 -1,
10993ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11003ff48bf5SDavid du Colombier 
11013ff48bf5SDavid du Colombier 	{	  3,	 11,	 19,	 27,	 35,	 43,	 51,	 59,
11023ff48bf5SDavid du Colombier 		 67,	 75,	 83,	 91,	 99,	107,	115,	123,
11033ff48bf5SDavid du Colombier 		131,	139,	147,	 -1,	 -1,	 -1,	 -1,	 -1,
11043ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11053ff48bf5SDavid du Colombier 
11063ff48bf5SDavid du Colombier 	{	  4,	 12,	 20,	 28,	 36,	 44,	 52,	 60,
11073ff48bf5SDavid du Colombier 		 68,	 76,	 84,	 92,	100,	108,	116,	 -1,
11083ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11093ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11103ff48bf5SDavid du Colombier 
11113ff48bf5SDavid du Colombier 	{	  5,	 13,	 21,	 29,	 37,	 45,	 53,	 61,
11123ff48bf5SDavid du Colombier 		 69,	 77,	 85,	 -1,	 -1,	 -1,	 -1,	 -1,
11133ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11143ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11153ff48bf5SDavid du Colombier 
11163ff48bf5SDavid du Colombier 	{	  6,	 14,	 22,	 30,	 38,	 46,	 54,	 -1,
11173ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11183ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11193ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11203ff48bf5SDavid du Colombier 
11213ff48bf5SDavid du Colombier 	{	  7,	 15,	 23,	 -1,	 -1,	 -1,	 -1,	 -1,
11223ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11233ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11243ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 }
11253ff48bf5SDavid du Colombier };
11263ff48bf5SDavid du Colombier 
11273ff48bf5SDavid du Colombier 
11283ff48bf5SDavid du Colombier /*
11293ff48bf5SDavid du Colombier *	This table contains the scheduling table for the first
11303ff48bf5SDavid du Colombier *	few lines if we are in 1440 dpi mode
11313ff48bf5SDavid du Colombier */
11323ff48bf5SDavid du Colombier 
11333ff48bf5SDavid du Colombier private	const int	start_1440[ 2 ][ HEAD_SPACING ][ NOZZLES ] = {
11343ff48bf5SDavid du Colombier   {
11353ff48bf5SDavid du Colombier 	{	  0,	  8,	 16,	 24,	 32,	 40,	 48,	 56,
11363ff48bf5SDavid du Colombier 		 64,	 72,	 80,	 88,	 96,	104,	112,	120,
11373ff48bf5SDavid du Colombier 		128,	136,	144,	152,	160,	168,	176,	184,
11383ff48bf5SDavid du Colombier 		192,	200,	208,	216,	224,	232,	240,	248 },
11393ff48bf5SDavid du Colombier 
11403ff48bf5SDavid du Colombier 	{	  1,	  9,	 17,	 25,	 33,	 41,	 49,	 57,
11413ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11423ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11433ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11443ff48bf5SDavid du Colombier 
11453ff48bf5SDavid du Colombier 	{	  2,	 10,	 18,	 -1,	 -1,	 -1,	 -1,	 -1,
11463ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11473ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11483ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11493ff48bf5SDavid du Colombier 
11503ff48bf5SDavid du Colombier 	{	  3,	 11,	 19,	 27,	 35,	 43,	 51,	 59,
11513ff48bf5SDavid du Colombier 		 67,	 75,	 83,	 -1,	 -1,	 -1,	 -1,	 -1,
11523ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11533ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11543ff48bf5SDavid du Colombier 
11553ff48bf5SDavid du Colombier 	{	  4,	 12,	 20,	 28,	 36,	 44,	 -1,	 -1,
11563ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11573ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11583ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11593ff48bf5SDavid du Colombier 
11603ff48bf5SDavid du Colombier 	{	  5,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11613ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11623ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11633ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11643ff48bf5SDavid du Colombier 
11653ff48bf5SDavid du Colombier 	{	  6,	 14,	 22,	 30,	 38,	 46,	 54,	 62,
11663ff48bf5SDavid du Colombier 		 70,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11673ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11683ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11693ff48bf5SDavid du Colombier 
11703ff48bf5SDavid du Colombier 	{	  7,	 15,	 23,	 31,	 -1,	 -1,	 -1,	 -1,
11713ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11723ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11733ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11743ff48bf5SDavid du Colombier 
11753ff48bf5SDavid du Colombier   },
11763ff48bf5SDavid du Colombier   {
11773ff48bf5SDavid du Colombier 	{	  0,	  8,	 16,	 24,	 32,	 40,	 48,	 56,
11783ff48bf5SDavid du Colombier 		 64,	 72,	 80,	 88,	 96,	 -1,	 -1,	 -1,
11793ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11803ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11813ff48bf5SDavid du Colombier 
11823ff48bf5SDavid du Colombier 	{	  1,	  9,	 17,	 25,	 33,	 41,	 49,	 57,
11833ff48bf5SDavid du Colombier 		 65,	 73,	 81,	 89,	 97,	105,	113,	121,
11843ff48bf5SDavid du Colombier 		129,	137,	145,	153,	161,	 -1,	 -1,	 -1,
11853ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11863ff48bf5SDavid du Colombier 
11873ff48bf5SDavid du Colombier 	{	  2,	 10,	 18,	 26,	 34,	 42,	 50,	 58,
11883ff48bf5SDavid du Colombier 		 66,	 74,	 82,	 90,	 98,	106,	114,	122,
11893ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
11903ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11913ff48bf5SDavid du Colombier 
11923ff48bf5SDavid du Colombier 	{	  3,	 11,	 19,	 27,	 35,	 43,	 51,	 59,
11933ff48bf5SDavid du Colombier 		 67,	 75,	 83,	 91,	 99,	107,	115,	123,
11943ff48bf5SDavid du Colombier 		131,	139,	147,	155,	163,	171,	179,	187,
11953ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
11963ff48bf5SDavid du Colombier 
11973ff48bf5SDavid du Colombier 	{	  4,	 12,	 20,	 28,	 36,	 44,	 52,	 60,
11983ff48bf5SDavid du Colombier 		 68,	 76,	 84,	 92,	100,	108,	116,	124,
11993ff48bf5SDavid du Colombier 		132,	140,	148,	 -1,	 -1,	 -1,	 -1,	 -1,
12003ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
12013ff48bf5SDavid du Colombier 
12023ff48bf5SDavid du Colombier 	{	  5,	 13,	 21,	 29,	 37,	 45,	 53,	 61,
12033ff48bf5SDavid du Colombier 		 69,	 77,	 85,	 93,	101,	109,	 -1,	 -1,
12043ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
12053ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
12063ff48bf5SDavid du Colombier 
12073ff48bf5SDavid du Colombier 	{	  6,	 14,	 22,	 30,	 38,	 46,	 54,	 62,
12083ff48bf5SDavid du Colombier 		 70,	 78,	 86,	 94,	102,	110,	118,	126,
12093ff48bf5SDavid du Colombier 		134,	142,	150,	158,	166,	174,	 -1,	 -1,
12103ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
12113ff48bf5SDavid du Colombier 
12123ff48bf5SDavid du Colombier 	{	  7,	 15,	 23,	 31,	 39,	 47,	 55,	 63,
12133ff48bf5SDavid du Colombier 		 71,	 79,	 87,	 95,	103,	111,	119,	127,
12143ff48bf5SDavid du Colombier 		135,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,
12153ff48bf5SDavid du Colombier 		 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1,	 -1 },
12163ff48bf5SDavid du Colombier 
12173ff48bf5SDavid du Colombier   }
12183ff48bf5SDavid du Colombier };
12193ff48bf5SDavid du Colombier 
12203ff48bf5SDavid du Colombier /*
12213ff48bf5SDavid du Colombier *	This is the dither matrix we use for ordered dither
12223ff48bf5SDavid du Colombier *	It is a shameless copy of Ghostscript's own ...
12233ff48bf5SDavid du Colombier */
12243ff48bf5SDavid du Colombier 
12253ff48bf5SDavid du Colombier private	byte	dmatrix[ DMATRIX_Y ][ DMATRIX_X ] = {
12263ff48bf5SDavid du Colombier 	{
12273ff48bf5SDavid du Colombier 		0x0e, 0x8e, 0x2e, 0xae, 0x06, 0x86, 0x26, 0xa6,
12283ff48bf5SDavid du Colombier 		0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4
12293ff48bf5SDavid du Colombier 	},
12303ff48bf5SDavid du Colombier 	{
12313ff48bf5SDavid du Colombier 		0xce, 0x4e, 0xee, 0x6e, 0xc6, 0x46, 0xe6, 0x66,
12323ff48bf5SDavid du Colombier 		0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64
12333ff48bf5SDavid du Colombier 	},
12343ff48bf5SDavid du Colombier 	{
12353ff48bf5SDavid du Colombier 		0x3e, 0xbe, 0x1e, 0x9e, 0x36, 0xb6, 0x16, 0x96,
12363ff48bf5SDavid du Colombier 		0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94
12373ff48bf5SDavid du Colombier 	},
12383ff48bf5SDavid du Colombier 	{
12393ff48bf5SDavid du Colombier 		0xfe, 0x7e, 0xde, 0x5e, 0xf6, 0x76, 0xd6, 0x56,
12403ff48bf5SDavid du Colombier 		0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54
12413ff48bf5SDavid du Colombier 	},
12423ff48bf5SDavid du Colombier 	{
12433ff48bf5SDavid du Colombier 		0x01, 0x81, 0x21, 0xa1, 0x09, 0x89, 0x29, 0xa9,
12443ff48bf5SDavid du Colombier 		0x03, 0x83, 0x23, 0xa3, 0x0b, 0x8b, 0x2b, 0xab
12453ff48bf5SDavid du Colombier 	},
12463ff48bf5SDavid du Colombier 	{
12473ff48bf5SDavid du Colombier 		0xc1, 0x41, 0xe1, 0x61, 0xc9, 0x49, 0xe9, 0x69,
12483ff48bf5SDavid du Colombier 		0xc3, 0x43, 0xe3, 0x63, 0xcb, 0x4b, 0xeb, 0x6b
12493ff48bf5SDavid du Colombier 	},
12503ff48bf5SDavid du Colombier 	{
12513ff48bf5SDavid du Colombier 		0x31, 0xb1, 0x11, 0x91, 0x39, 0xb9, 0x19, 0x99,
12523ff48bf5SDavid du Colombier 		0x33, 0xb3, 0x13, 0x93, 0x3b, 0xbb, 0x1b, 0x9b
12533ff48bf5SDavid du Colombier 	},
12543ff48bf5SDavid du Colombier 	{
12553ff48bf5SDavid du Colombier 		0xf1, 0x71, 0xd1, 0x51, 0xf9, 0x79, 0xd9, 0x59,
12563ff48bf5SDavid du Colombier 		0xf3, 0x73, 0xd3, 0x53, 0xfb, 0x7b, 0xdb, 0x5b
12573ff48bf5SDavid du Colombier 	},
12583ff48bf5SDavid du Colombier 	{
12593ff48bf5SDavid du Colombier 		0x0d, 0x8d, 0x2d, 0xad, 0x05, 0x85, 0x25, 0xa5,
12603ff48bf5SDavid du Colombier 		0x0f, 0x8f, 0x2f, 0xaf, 0x07, 0x87, 0x27, 0xa7
12613ff48bf5SDavid du Colombier 	},
12623ff48bf5SDavid du Colombier 	{
12633ff48bf5SDavid du Colombier 		0xcd, 0x4d, 0xed, 0x6d, 0xc5, 0x45, 0xe5, 0x65,
12643ff48bf5SDavid du Colombier 		0xcf, 0x4f, 0xef, 0x6f, 0xc7, 0x47, 0xe7, 0x67
12653ff48bf5SDavid du Colombier 	},
12663ff48bf5SDavid du Colombier 	{
12673ff48bf5SDavid du Colombier 		0x3d, 0xbd, 0x1d, 0x9d, 0x35, 0xb5, 0x15, 0x95,
12683ff48bf5SDavid du Colombier 		0x3f, 0xbf, 0x1f, 0x9f, 0x37, 0xb7, 0x17, 0x97
12693ff48bf5SDavid du Colombier 	},
12703ff48bf5SDavid du Colombier 	{
12713ff48bf5SDavid du Colombier 		0xfd, 0x7d, 0xdd, 0x5d, 0xf5, 0x75, 0xd5, 0x55,
12723ff48bf5SDavid du Colombier 		0xff, 0x7f, 0xdf, 0x5f, 0xf7, 0x77, 0xd7, 0x57
12733ff48bf5SDavid du Colombier 	},
12743ff48bf5SDavid du Colombier 	{
12753ff48bf5SDavid du Colombier 		0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa,
12763ff48bf5SDavid du Colombier 		0x01, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8
12773ff48bf5SDavid du Colombier 	},
12783ff48bf5SDavid du Colombier 	{
12793ff48bf5SDavid du Colombier 		0xc2, 0x42, 0xe2, 0x62, 0xca, 0x4a, 0xea, 0x6a,
12803ff48bf5SDavid du Colombier 		0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68
12813ff48bf5SDavid du Colombier 	},
12823ff48bf5SDavid du Colombier 	{
12833ff48bf5SDavid du Colombier 		0x32, 0xb2, 0x12, 0x92, 0x3a, 0xba, 0x1a, 0x9a,
12843ff48bf5SDavid du Colombier 		0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98
12853ff48bf5SDavid du Colombier 	},
12863ff48bf5SDavid du Colombier 	{
12873ff48bf5SDavid du Colombier 		0xf2, 0x72, 0xd2, 0x52, 0xfa, 0x7a, 0xda, 0x5a,
12883ff48bf5SDavid du Colombier 		0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58
12893ff48bf5SDavid du Colombier 	}
12903ff48bf5SDavid du Colombier };
12913ff48bf5SDavid du Colombier 
12923ff48bf5SDavid du Colombier /*
12933ff48bf5SDavid du Colombier *	This is the (minimalistic) colour compensation table
12943ff48bf5SDavid du Colombier */
12953ff48bf5SDavid du Colombier 
12963ff48bf5SDavid du Colombier static	CCOMP	ctable[] = {
12973ff48bf5SDavid du Colombier 
1298*593dc095SDavid du Colombier 	{ -255, -255,   0,   0, 255 },		/* same as green */
1299*593dc095SDavid du Colombier 	{  102,    0, 255,   0,   0 },		/* cyan */
1300*593dc095SDavid du Colombier 	{  255,  255, 255, 255,   0 },		/* blue */
1301*593dc095SDavid du Colombier 	{  560,  512,   0, 255,   0 },		/* magenta */
1302*593dc095SDavid du Colombier 	{  765,  765,   0, 255, 255 },		/* red */
1303*593dc095SDavid du Colombier 	{ 1045, 1020,   0,   0, 255 },		/* yellow */
1304*593dc095SDavid du Colombier 	{ 1275, 1275, 255,   0, 255 },		/* green */
1305*593dc095SDavid du Colombier 	{ 1632, 1530, 255,   0,   0 }		/* same as cyan */
13063ff48bf5SDavid du Colombier };
13073ff48bf5SDavid du Colombier 
13083ff48bf5SDavid du Colombier /*
13093ff48bf5SDavid du Colombier *	This is the ink transfer function.
13103ff48bf5SDavid du Colombier *	We use only one for all inks, this may be wrong.
13113ff48bf5SDavid du Colombier */
13123ff48bf5SDavid du Colombier 
13133ff48bf5SDavid du Colombier static const unsigned char	xtrans[ 256 ] = {
13143ff48bf5SDavid du Colombier 
13153ff48bf5SDavid du Colombier 	  0,   0,   0,   0,   0,   0,   0,   0,
13163ff48bf5SDavid du Colombier 	  0,   0,   0,   0,   0,   0,   0,   0,
13173ff48bf5SDavid du Colombier 	  0,   0,   0,   0,   0,   0,   0,   0,
13183ff48bf5SDavid du Colombier 	  0,   0,   0,   0,   0,   0,   0,   0,
13193ff48bf5SDavid du Colombier 	  0,   0,   0,   0,   1,   1,   1,   1,
13203ff48bf5SDavid du Colombier 	  1,   1,   1,   1,   1,   1,   1,   1,
13213ff48bf5SDavid du Colombier 	  1,   1,   1,   1,   2,   2,   2,   2,
13223ff48bf5SDavid du Colombier 	  2,   2,   2,   2,   2,   2,   3,   3,
13233ff48bf5SDavid du Colombier 	  3,   3,   3,   3,   3,   4,   4,   4,
13243ff48bf5SDavid du Colombier 	  4,   4,   4,   5,   5,   5,   5,   5,
13253ff48bf5SDavid du Colombier 	  6,   6,   6,   6,   6,   7,   7,   7,
13263ff48bf5SDavid du Colombier 	  7,   8,   8,   8,   8,   9,   9,   9,
13273ff48bf5SDavid du Colombier 	 10,  10,  10,  11,  11,  11,  12,  12,
13283ff48bf5SDavid du Colombier 	 12,  13,  13,  13,  14,  14,  14,  15,
13293ff48bf5SDavid du Colombier 	 15,  16,  16,  17,  17,  17,  18,  18,
13303ff48bf5SDavid du Colombier 	 19,  19,  20,  20,  21,  21,  22,  22,
13313ff48bf5SDavid du Colombier 	 23,  23,  24,  24,  25,  26,  26,  27,
13323ff48bf5SDavid du Colombier 	 27,  28,  29,  29,  30,  30,  31,  32,
13333ff48bf5SDavid du Colombier 	 32,  33,  34,  34,  35,  36,  37,  37,
13343ff48bf5SDavid du Colombier 	 38,  39,  40,  40,  41,  42,  43,  44,
13353ff48bf5SDavid du Colombier 	 44,  45,  46,  47,  48,  49,  50,  51,
13363ff48bf5SDavid du Colombier 	 51,  52,  53,  54,  55,  56,  57,  58,
13373ff48bf5SDavid du Colombier 	 59,  60,  61,  62,  63,  64,  65,  67,
13383ff48bf5SDavid du Colombier 	 68,  69,  70,  71,  72,  73,  74,  76,
13393ff48bf5SDavid du Colombier 	 77,  78,  79,  80,  82,  83,  84,  86,
13403ff48bf5SDavid du Colombier 	 87,  88,  89,  91,  92,  94,  95,  96,
13413ff48bf5SDavid du Colombier 	 98,  99, 101, 102, 103, 105, 106, 108,
13423ff48bf5SDavid du Colombier 	109, 111, 112, 114, 116, 117, 119, 120,
13433ff48bf5SDavid du Colombier 	122, 124, 125, 127, 129, 130, 132, 134,
13443ff48bf5SDavid du Colombier 	136, 137, 139, 141, 143, 145, 146, 148,
13453ff48bf5SDavid du Colombier 	150, 152, 154, 156, 158, 160, 162, 164,
13463ff48bf5SDavid du Colombier 	166, 168, 170, 172, 174, 176, 178, 180
13473ff48bf5SDavid du Colombier };
13483ff48bf5SDavid du Colombier 
13493ff48bf5SDavid du Colombier /****************************************************************************/
13503ff48bf5SDavid du Colombier /*							Device opening									*/
13513ff48bf5SDavid du Colombier /****************************************************************************/
13523ff48bf5SDavid du Colombier 
photoex_open(DEV * pdev)13533ff48bf5SDavid du Colombier private int		photoex_open( DEV *pdev )
13543ff48bf5SDavid du Colombier {
13553ff48bf5SDavid du Colombier double	height;
13563ff48bf5SDavid du Colombier double	width;
13573ff48bf5SDavid du Colombier float	margins[ 4 ];						/* L, B, R, T					*/
13583ff48bf5SDavid du Colombier 
13593ff48bf5SDavid du Colombier 	height = pdev->height / pdev->y_pixels_per_inch;
13603ff48bf5SDavid du Colombier 	width  = pdev->width  / pdev->x_pixels_per_inch;
13613ff48bf5SDavid du Colombier 
13623ff48bf5SDavid du Colombier 	margins[ 0 ] = 0.12;
13633ff48bf5SDavid du Colombier 	margins[ 1 ] = 0.5;
13643ff48bf5SDavid du Colombier 	margins[ 2 ] = 0.12;
13653ff48bf5SDavid du Colombier 	margins[ 3 ] = ( width > 11.46+0.12 ) ? width - (11.46+0.12) : 0.12;
13663ff48bf5SDavid du Colombier 
13673ff48bf5SDavid du Colombier 	gx_device_set_margins( pdev, margins, true );
13683ff48bf5SDavid du Colombier 	return( gdev_prn_open( pdev ) );
13693ff48bf5SDavid du Colombier }
13703ff48bf5SDavid du Colombier 
13713ff48bf5SDavid du Colombier /****************************************************************************/
13723ff48bf5SDavid du Colombier /*							Colour procedures								*/
13733ff48bf5SDavid du Colombier /****************************************************************************/
13743ff48bf5SDavid du Colombier 
13753ff48bf5SDavid du Colombier /*
13763ff48bf5SDavid du Colombier *	Map an RGB colour to device colour.
13773ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13783ff48bf5SDavid du Colombier *
13793ff48bf5SDavid du Colombier *	Since we present ourselves to Ghostscript as if we were a
13803ff48bf5SDavid du Colombier *	full colour resolution RGB device, we calculate the CMYK
13813ff48bf5SDavid du Colombier *	values and pack them into the result. This depends on
13823ff48bf5SDavid du Colombier *	color_index being at least 32 bit !!!
13833ff48bf5SDavid du Colombier */
13843ff48bf5SDavid du Colombier 
photoex_map_rgb_color(DEV * dev,CVAL r,CVAL g,CVAL b)13853ff48bf5SDavid du Colombier private	CINX	photoex_map_rgb_color( DEV *dev, CVAL r, CVAL g, CVAL b )
13863ff48bf5SDavid du Colombier {
13873ff48bf5SDavid du Colombier int		c, y, m, k;
13883ff48bf5SDavid du Colombier int		a, s, f;
13893ff48bf5SDavid du Colombier EDEV	*edev;
13903ff48bf5SDavid du Colombier int		i;
13913ff48bf5SDavid du Colombier 
13923ff48bf5SDavid du Colombier 	edev = (EDEV *) dev;
13933ff48bf5SDavid du Colombier 
13943ff48bf5SDavid du Colombier 	/* White and black are treated on their own */
13953ff48bf5SDavid du Colombier 
13963ff48bf5SDavid du Colombier 	if ( ( r & g & b ) == ( 1 << gx_color_value_bits ) - 1 ) {
13973ff48bf5SDavid du Colombier 
13983ff48bf5SDavid du Colombier 		/* White */
13993ff48bf5SDavid du Colombier 
14003ff48bf5SDavid du Colombier 		return( BUILD_CMYK( 0, 0, 0, 0 ) );
14013ff48bf5SDavid du Colombier 	}
14023ff48bf5SDavid du Colombier 
14033ff48bf5SDavid du Colombier 	if ( ( r | g | b ) == 0 ) {
14043ff48bf5SDavid du Colombier 
14053ff48bf5SDavid du Colombier 		/* Black */
14063ff48bf5SDavid du Colombier 
14073ff48bf5SDavid du Colombier 		return( BUILD_CMYK( 0, 0, 0, xtrans[ 0xff ] ) );
14083ff48bf5SDavid du Colombier 	}
14093ff48bf5SDavid du Colombier 
14103ff48bf5SDavid du Colombier 	/* Map RGB to 8 bit/colour CMY */
14113ff48bf5SDavid du Colombier 
14123ff48bf5SDavid du Colombier 	c = 255 - ( r >> ( gx_color_value_bits - 8 ) );
14133ff48bf5SDavid du Colombier 	m = 255 - ( g >> ( gx_color_value_bits - 8 ) );
14143ff48bf5SDavid du Colombier 	y = 255 - ( b >> ( gx_color_value_bits - 8 ) );
14153ff48bf5SDavid du Colombier 
14163ff48bf5SDavid du Colombier 	k = xtrans[ min( c, min( m, y ) ) ] * 0.8; /* FIXME:empirical constant */
14173ff48bf5SDavid du Colombier 	c -= k;
14183ff48bf5SDavid du Colombier 	m -= k;
14193ff48bf5SDavid du Colombier 	y -= k;
14203ff48bf5SDavid du Colombier 
14213ff48bf5SDavid du Colombier 	s = max ( c, max( y, m ) );
14223ff48bf5SDavid du Colombier 
14233ff48bf5SDavid du Colombier 	/* Map the colour to an angle and find the relevant table range */
14243ff48bf5SDavid du Colombier 
14253ff48bf5SDavid du Colombier 	a = Cmy2A( c, m, y );
14263ff48bf5SDavid du Colombier 	for ( i = 1 ; a > ctable[ i ].ra ; i++ );
14273ff48bf5SDavid du Colombier 
14283ff48bf5SDavid du Colombier 	/* Now map c, m, y. */
14293ff48bf5SDavid du Colombier 
14303ff48bf5SDavid du Colombier 	f = ((a - ctable[ i-1 ].ra) << 16 ) / (ctable[ i ].ra - ctable[ i-1 ].ra);
14313ff48bf5SDavid du Colombier 	c = (( ctable[i-1].c << 16 ) + ( ctable[i].c - ctable[i-1].c ) * f ) >> 16;
14323ff48bf5SDavid du Colombier 	m = (( ctable[i-1].m << 16 ) + ( ctable[i].m - ctable[i-1].m ) * f ) >> 16;
14333ff48bf5SDavid du Colombier 	y = (( ctable[i-1].y << 16 ) + ( ctable[i].y - ctable[i-1].y ) * f ) >> 16;
14343ff48bf5SDavid du Colombier 
14353ff48bf5SDavid du Colombier 	s = xtrans[ s ];
14363ff48bf5SDavid du Colombier 	c = ( c * s ) >> 8;
14373ff48bf5SDavid du Colombier 	m = ( m * s ) >> 8;
14383ff48bf5SDavid du Colombier 	y = ( y * s ) >> 8;
14393ff48bf5SDavid du Colombier 
14403ff48bf5SDavid du Colombier 	return( BUILD_CMYK( c, m, y, k ) );
14413ff48bf5SDavid du Colombier }
14423ff48bf5SDavid du Colombier 
14433ff48bf5SDavid du Colombier /*
14443ff48bf5SDavid du Colombier *	Map a device colour value back to RGB.
14453ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14463ff48bf5SDavid du Colombier *
14473ff48bf5SDavid du Colombier *	CAVEAT:
14483ff48bf5SDavid du Colombier *	This mapping is *not* the inverse of the RGB->CMYK.
14493ff48bf5SDavid du Colombier *	It does not do any ink transfer compensation, colour compensation etc.
14503ff48bf5SDavid du Colombier */
14513ff48bf5SDavid du Colombier 
photoex_map_color_rgb(DEV * dev,CINX index,CVAL prgb[3])14523ff48bf5SDavid du Colombier private int		photoex_map_color_rgb( DEV *dev, CINX index, CVAL prgb[3] )
14533ff48bf5SDavid du Colombier {
14543ff48bf5SDavid du Colombier uint	c, m, y, k;
14553ff48bf5SDavid du Colombier CVAL	r, g, b;
14563ff48bf5SDavid du Colombier 
14573ff48bf5SDavid du Colombier 	/* Let's separate the colours */
14583ff48bf5SDavid du Colombier 
14593ff48bf5SDavid du Colombier 	DECOMPOSE_CMYK( index, c, m, y, k );
14603ff48bf5SDavid du Colombier 
14613ff48bf5SDavid du Colombier 	k = index & 255;
14623ff48bf5SDavid du Colombier 	y = ( index >> 8 ) & 255;
14633ff48bf5SDavid du Colombier 	m = ( index >> 16 ) & 255;
14643ff48bf5SDavid du Colombier 	c = ( index >> 24 ) & 255;
14653ff48bf5SDavid du Colombier 
14663ff48bf5SDavid du Colombier 	/* Depending on whether we use Adobe or Ghostscript mapping,
14673ff48bf5SDavid du Colombier 	   calculate the colours */
14683ff48bf5SDavid du Colombier 
14693ff48bf5SDavid du Colombier 	if ( MAP_RGB_ADOBE ) {
14703ff48bf5SDavid du Colombier 
14713ff48bf5SDavid du Colombier 		r = gx_max_color_value * ( 1.0 - min( 1.0, (c / 255.0 + k / 255.0) ) );
14723ff48bf5SDavid du Colombier 		g = gx_max_color_value * ( 1.0 - min( 1.0, (m / 255.0 + k / 255.0) ) );
14733ff48bf5SDavid du Colombier 		b = gx_max_color_value * ( 1.0 - min( 1.0, (y / 255.0 + k / 255.0) ) );
14743ff48bf5SDavid du Colombier 	}
14753ff48bf5SDavid du Colombier 	else {
14763ff48bf5SDavid du Colombier 
14773ff48bf5SDavid du Colombier 		r = gx_max_color_value * ( 1.0 - c / 255.0 ) * ( 1.0 - k / 255.0);
14783ff48bf5SDavid du Colombier 		g = gx_max_color_value * ( 1.0 - m / 255.0 ) * ( 1.0 - k / 255.0);
14793ff48bf5SDavid du Colombier 		b = gx_max_color_value * ( 1.0 - y / 255.0 ) * ( 1.0 - k / 255.0);
14803ff48bf5SDavid du Colombier 	}
14813ff48bf5SDavid du Colombier 
14823ff48bf5SDavid du Colombier 	prgb[ 0 ] = r;
14833ff48bf5SDavid du Colombier 	prgb[ 1 ] = g;
14843ff48bf5SDavid du Colombier 	prgb[ 2 ] = b;
14853ff48bf5SDavid du Colombier 
14863ff48bf5SDavid du Colombier 	return( 0 );
14873ff48bf5SDavid du Colombier }
14883ff48bf5SDavid du Colombier 
14893ff48bf5SDavid du Colombier /*
14903ff48bf5SDavid du Colombier *	This function maps a (c,m,y) triplet into an angle.
14913ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14923ff48bf5SDavid du Colombier *
14933ff48bf5SDavid du Colombier *	Angle:    0 cyan	C=255 M=  0 Y=  0
14943ff48bf5SDavid du Colombier *			255 blue    C=255 M=255 Y=  0
14953ff48bf5SDavid du Colombier *			510 magenta	C=  0 M=255 Y=  0
14963ff48bf5SDavid du Colombier *			765 red     C=  0 M=255 Y=255
14973ff48bf5SDavid du Colombier *		   1020 yellow	C=  0 M=  0 Y=255
14983ff48bf5SDavid du Colombier *		   1275 green   C=255 M=  0 Y=255
14993ff48bf5SDavid du Colombier *		   1530 cyan
15003ff48bf5SDavid du Colombier */
15013ff48bf5SDavid du Colombier 
Cmy2A(int c,int m,int y)15023ff48bf5SDavid du Colombier private	int		Cmy2A( int c, int m, int y )
15033ff48bf5SDavid du Colombier {
15043ff48bf5SDavid du Colombier int		black;
15053ff48bf5SDavid du Colombier int		maxim;
15063ff48bf5SDavid du Colombier int		a;
15073ff48bf5SDavid du Colombier 
15083ff48bf5SDavid du Colombier 	/* Calculate the black level */
15093ff48bf5SDavid du Colombier 
15103ff48bf5SDavid du Colombier 	black = min( c, min( m, y ) );
15113ff48bf5SDavid du Colombier 
15123ff48bf5SDavid du Colombier 	/* Remove the black from the colours themselves */
15133ff48bf5SDavid du Colombier 
15143ff48bf5SDavid du Colombier 	c -= black;
15153ff48bf5SDavid du Colombier 	m -= black;
15163ff48bf5SDavid du Colombier 	y -= black;
15173ff48bf5SDavid du Colombier 
15183ff48bf5SDavid du Colombier 	/* If all 3 remaining colours are 0, then it is a gray: special case */
15193ff48bf5SDavid du Colombier 
15203ff48bf5SDavid du Colombier 	if ( ! c && ! m && ! y ) return( 0 );
15213ff48bf5SDavid du Colombier 
15223ff48bf5SDavid du Colombier 	/* Normalise the colours. At least one at most two of them is 0
15233ff48bf5SDavid du Colombier 	   and at least one at most two of them is 255 */
15243ff48bf5SDavid du Colombier 
15253ff48bf5SDavid du Colombier 	maxim = max( c, max( m, y ) );
15263ff48bf5SDavid du Colombier 
15273ff48bf5SDavid du Colombier 	c = ( 255 * c ) / maxim;
15283ff48bf5SDavid du Colombier 	m = ( 255 * m ) / maxim;
15293ff48bf5SDavid du Colombier 	y = ( 255 * y ) / maxim;
15303ff48bf5SDavid du Colombier 
15313ff48bf5SDavid du Colombier 	if ( c == 255 ) {
15323ff48bf5SDavid du Colombier 
15333ff48bf5SDavid du Colombier 		if ( ! y )
15343ff48bf5SDavid du Colombier 
15353ff48bf5SDavid du Colombier 			a = m;					/* cyan - blue */
15363ff48bf5SDavid du Colombier 		else
15373ff48bf5SDavid du Colombier 			a = 1530 - y;			/* green - cyan */
15383ff48bf5SDavid du Colombier 	}
15393ff48bf5SDavid du Colombier 	else if ( m == 255 ) {
15403ff48bf5SDavid du Colombier 
15413ff48bf5SDavid du Colombier 		if ( ! c )
15423ff48bf5SDavid du Colombier 
15433ff48bf5SDavid du Colombier 			a = 510 + y;			/* magenta - red */
15443ff48bf5SDavid du Colombier 		else
15453ff48bf5SDavid du Colombier 			a = 510 - c;			/* blue - magenta */
15463ff48bf5SDavid du Colombier 	}
15473ff48bf5SDavid du Colombier 	else {
15483ff48bf5SDavid du Colombier 
15493ff48bf5SDavid du Colombier 		if ( ! m )
15503ff48bf5SDavid du Colombier 
15513ff48bf5SDavid du Colombier 			a = 1020 + c;			/* yellow - green */
15523ff48bf5SDavid du Colombier 		else
15533ff48bf5SDavid du Colombier 			a = 1020 - m;			/* red - yellow */
15543ff48bf5SDavid du Colombier 	}
15553ff48bf5SDavid du Colombier 
15563ff48bf5SDavid du Colombier 	return( a );
15573ff48bf5SDavid du Colombier }
15583ff48bf5SDavid du Colombier 
15593ff48bf5SDavid du Colombier /****************************************************************************/
15603ff48bf5SDavid du Colombier /*						Device parameter handling							*/
15613ff48bf5SDavid du Colombier /****************************************************************************/
15623ff48bf5SDavid du Colombier 
15633ff48bf5SDavid du Colombier /*
15643ff48bf5SDavid du Colombier *	Tell Ghostscript all about our extra device parameters
15653ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15663ff48bf5SDavid du Colombier */
15673ff48bf5SDavid du Colombier 
photoex_get_params(DEV * device,PLIST * plist)15683ff48bf5SDavid du Colombier private	int		photoex_get_params( DEV *device, PLIST *plist )
15693ff48bf5SDavid du Colombier {
15703ff48bf5SDavid du Colombier int		code;
15713ff48bf5SDavid du Colombier EDEV	*dev;
15723ff48bf5SDavid du Colombier 
15733ff48bf5SDavid du Colombier 	dev  = (EDEV *) device;
15743ff48bf5SDavid du Colombier 
15753ff48bf5SDavid du Colombier 	code = gdev_prn_get_params( device, plist );
15763ff48bf5SDavid du Colombier 
15773ff48bf5SDavid du Colombier 	code = GetInt( plist, "Depletion",	&dev->depletion, code );
15783ff48bf5SDavid du Colombier 	code = GetInt( plist, "Shingling",	&dev->shingling, code );
15793ff48bf5SDavid du Colombier 	code = GetInt( plist, "Render",  	&dev->halftoner, code );
15803ff48bf5SDavid du Colombier 	code = GetInt( plist, "Splash",		&dev->splash,    code );
15813ff48bf5SDavid du Colombier 	code = GetInt( plist, "Leakage",	&dev->leakage,   code );
15823ff48bf5SDavid du Colombier 	code = GetInt( plist, "Binhibit",	&dev->pureblack, code );
15833ff48bf5SDavid du Colombier 	code = GetInt( plist, "DotSize",	&dev->dotsize,	 code );
15843ff48bf5SDavid du Colombier 	return( code );
15853ff48bf5SDavid du Colombier }
15863ff48bf5SDavid du Colombier 
15873ff48bf5SDavid du Colombier /*
15883ff48bf5SDavid du Colombier *	Get all extra device-dependent parameters
15893ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15903ff48bf5SDavid du Colombier */
15913ff48bf5SDavid du Colombier 
photoex_put_params(DEV * device,PLIST * plist)15923ff48bf5SDavid du Colombier private	int		photoex_put_params( DEV *device, PLIST *plist )
15933ff48bf5SDavid du Colombier {
15943ff48bf5SDavid du Colombier int		code;
15953ff48bf5SDavid du Colombier EDEV	*dev;
15963ff48bf5SDavid du Colombier 
15973ff48bf5SDavid du Colombier 	dev  = (EDEV *) device;
15983ff48bf5SDavid du Colombier 	code = 0;
15993ff48bf5SDavid du Colombier 
16003ff48bf5SDavid du Colombier 	code = PutInt( plist, "Depletion",	&dev->depletion, 0,		    2, code );
16013ff48bf5SDavid du Colombier 	code = PutInt( plist, "Shingling",	&dev->shingling, 0, 	    2, code );
16023ff48bf5SDavid du Colombier 	code = PutInt( plist, "Render",		&dev->halftoner, 0,MAXHTONE-1, code );
16033ff48bf5SDavid du Colombier 	code = PutInt( plist, "Splash",		&dev->splash,    0,		   50, code );
16043ff48bf5SDavid du Colombier 	code = PutInt( plist, "Leakage",	&dev->leakage,   0,		   25, code );
16053ff48bf5SDavid du Colombier 	code = PutInt( plist, "Binhibit",	&dev->pureblack, 0,		    1, code );
16063ff48bf5SDavid du Colombier 	code = PutInt( plist, "DotSize",	&dev->dotsize,   0,		    4, code );
16073ff48bf5SDavid du Colombier 
16083ff48bf5SDavid du Colombier 	if ( code < 0 )
16093ff48bf5SDavid du Colombier 
16103ff48bf5SDavid du Colombier 		return( code );
16113ff48bf5SDavid du Colombier 	else
16123ff48bf5SDavid du Colombier 		return( gdev_prn_put_params( device, plist ) );
16133ff48bf5SDavid du Colombier }
16143ff48bf5SDavid du Colombier 
16153ff48bf5SDavid du Colombier /*
16163ff48bf5SDavid du Colombier *	Reads a named integer from Ghostscript
16173ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16183ff48bf5SDavid du Colombier */
16193ff48bf5SDavid du Colombier 
PutInt(PLIST * plist,PNAME name,int * val,int minval,int maxval,int code)16203ff48bf5SDavid du Colombier private int 	PutInt( PLIST *plist, PNAME name, int *val,
16213ff48bf5SDavid du Colombier 						int minval, int maxval, int code )
16223ff48bf5SDavid du Colombier {
16233ff48bf5SDavid du Colombier int		new;
16243ff48bf5SDavid du Colombier 
16253ff48bf5SDavid du Colombier 	/* If code is already an error, we return it and do nothing. */
16263ff48bf5SDavid du Colombier 
16273ff48bf5SDavid du Colombier 	if ( code ) return( code );
16283ff48bf5SDavid du Colombier 
16293ff48bf5SDavid du Colombier 	/* Otherwise we try to read the value */
16303ff48bf5SDavid du Colombier 
16313ff48bf5SDavid du Colombier 	new = *val;
16323ff48bf5SDavid du Colombier 
16333ff48bf5SDavid du Colombier 	switch ( code = param_read_int( plist, name, &new ) ) {
16343ff48bf5SDavid du Colombier 
16353ff48bf5SDavid du Colombier 		case 1:						/* No such parameter defined, it's OK	*/
16363ff48bf5SDavid du Colombier 
16373ff48bf5SDavid du Colombier 			code = 0;
16383ff48bf5SDavid du Colombier 			break;
16393ff48bf5SDavid du Colombier 
16403ff48bf5SDavid du Colombier 		case 0:						/* We have received a value, rangecheck	*/
16413ff48bf5SDavid du Colombier 
16423ff48bf5SDavid du Colombier 			if ( minval > new || new > maxval )
16433ff48bf5SDavid du Colombier 
16443ff48bf5SDavid du Colombier 				param_signal_error( plist, name, gs_error_rangecheck );
16453ff48bf5SDavid du Colombier 			else
16463ff48bf5SDavid du Colombier 				*val = new;
16473ff48bf5SDavid du Colombier 
16483ff48bf5SDavid du Colombier 			break;
16493ff48bf5SDavid du Colombier 
16503ff48bf5SDavid du Colombier 		default:					/* Error								*/
16513ff48bf5SDavid du Colombier 			break;
16523ff48bf5SDavid du Colombier 	}
16533ff48bf5SDavid du Colombier 
16543ff48bf5SDavid du Colombier 	return( code );
16553ff48bf5SDavid du Colombier }
16563ff48bf5SDavid du Colombier 
16573ff48bf5SDavid du Colombier /*
16583ff48bf5SDavid du Colombier *	Writes a named integer to Ghostscript
16593ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16603ff48bf5SDavid du Colombier */
16613ff48bf5SDavid du Colombier 
GetInt(PLIST * list,PNAME name,int * value,int code)16623ff48bf5SDavid du Colombier private	int		GetInt( PLIST *list, PNAME name, int *value, int code )
16633ff48bf5SDavid du Colombier {
16643ff48bf5SDavid du Colombier 	if ( code < 0 ) return( code );
16653ff48bf5SDavid du Colombier 	return( param_write_int( list, name, value ) );
16663ff48bf5SDavid du Colombier }
16673ff48bf5SDavid du Colombier 
16683ff48bf5SDavid du Colombier /****************************************************************************/
16693ff48bf5SDavid du Colombier /*							Page rendering									*/
16703ff48bf5SDavid du Colombier /****************************************************************************/
16713ff48bf5SDavid du Colombier 
16723ff48bf5SDavid du Colombier /*
16733ff48bf5SDavid du Colombier *	This is the function that Ghostscript calls to render a page
16743ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16753ff48bf5SDavid du Colombier */
16763ff48bf5SDavid du Colombier 
photoex_print_page(PDEV * device,FILE * stream)16773ff48bf5SDavid du Colombier private	int		photoex_print_page( PDEV *device, FILE *stream )
16783ff48bf5SDavid du Colombier {
16793ff48bf5SDavid du Colombier int			pixels;						/* Length of the line 				*/
16803ff48bf5SDavid du Colombier int			x;							/* Work vars						*/
16813ff48bf5SDavid du Colombier EDEV		*dev;						/* Our device						*/
16823ff48bf5SDavid du Colombier RENDER		*render;					/* Rendering info					*/
16833ff48bf5SDavid du Colombier 
16843ff48bf5SDavid du Colombier int			xres, yres;
16853ff48bf5SDavid du Colombier int			start, width;
16863ff48bf5SDavid du Colombier int			unit;
16873ff48bf5SDavid du Colombier double		psize;
16883ff48bf5SDavid du Colombier 
16893ff48bf5SDavid du Colombier 	dev = (EDEV *) device;
16903ff48bf5SDavid du Colombier 
16913ff48bf5SDavid du Colombier 	/* Check if the resolution is one of the supported ones */
16923ff48bf5SDavid du Colombier 
16933ff48bf5SDavid du Colombier 	yres = (int) dev->y_pixels_per_inch;
16943ff48bf5SDavid du Colombier 	xres = (int) dev->x_pixels_per_inch;
16953ff48bf5SDavid du Colombier 
16963ff48bf5SDavid du Colombier 	if ( ! ( ( xres ==  360 && yres == 360 ) ||
16973ff48bf5SDavid du Colombier 			 ( xres ==  720 && yres == 720 ) ||
16983ff48bf5SDavid du Colombier 			 ( xres == 1440 && yres == 720 ) ) )
16993ff48bf5SDavid du Colombier 
17003ff48bf5SDavid du Colombier 		return( gs_error_rangecheck );
17013ff48bf5SDavid du Colombier 
17023ff48bf5SDavid du Colombier 	pixels = gdev_prn_raster( device ) / sizeof( long );
17033ff48bf5SDavid du Colombier 	psize  = device->height / device->y_pixels_per_inch;
17043ff48bf5SDavid du Colombier 
17053ff48bf5SDavid du Colombier 	/* Check if the requested width is within device limits.
17063ff48bf5SDavid du Colombier 	   The calculations are in 1440 dpi units. */
17073ff48bf5SDavid du Colombier 
17083ff48bf5SDavid du Colombier 	start = 1440.0 * dev_l_margin( device );
17093ff48bf5SDavid du Colombier 
17103ff48bf5SDavid du Colombier 	x = xres == 360 ? 4 : xres == 720 ? 2 : 1;
17113ff48bf5SDavid du Colombier 
17123ff48bf5SDavid du Colombier 	if ( start + x * pixels > 2 * MAX_PIXELS ) {
17133ff48bf5SDavid du Colombier 
17143ff48bf5SDavid du Colombier 		/* We're over the limit, clip width to the required level */
17153ff48bf5SDavid du Colombier 
17163ff48bf5SDavid du Colombier 		width = ( 2 * MAX_PIXELS - start ) / x;
17173ff48bf5SDavid du Colombier 
17183ff48bf5SDavid du Colombier 		/* It is rather inprobable that someone would set up a
17193ff48bf5SDavid du Colombier 		   left margin wider than the printer, still ... */
17203ff48bf5SDavid du Colombier 
17213ff48bf5SDavid du Colombier 		if ( width <= 0 ) return( gs_error_rangecheck );
17223ff48bf5SDavid du Colombier 	}
17233ff48bf5SDavid du Colombier 	else {
17243ff48bf5SDavid du Colombier 
17253ff48bf5SDavid du Colombier 		/* We accept the width as it is */
17263ff48bf5SDavid du Colombier 
17273ff48bf5SDavid du Colombier 		width = pixels;
17283ff48bf5SDavid du Colombier 	}
17293ff48bf5SDavid du Colombier 
17303ff48bf5SDavid du Colombier 	/* Now try to get the memory we need. It's actually quite a lot,
17313ff48bf5SDavid du Colombier 	   since we have to cache 256 processed lines at 6kbyte each plus
17323ff48bf5SDavid du Colombier 	   we need error buffers and stuff. All in all, we'll request
17333ff48bf5SDavid du Colombier 	   about 1.5 ~ 2M. */
17343ff48bf5SDavid du Colombier 
1735*593dc095SDavid du Colombier 	if ( ! ( render = (RENDER *) gs_malloc( dev->memory, 1, sizeof( RENDER ), "PhotoEX" )))
17363ff48bf5SDavid du Colombier 
17373ff48bf5SDavid du Colombier 		return_error( gs_error_VMerror );
17383ff48bf5SDavid du Colombier 
1739*593dc095SDavid du Colombier 	if ( ! ( render->dbuff = (byte *) gs_malloc( dev->memory, pixels, sizeof( long ),
17403ff48bf5SDavid du Colombier 			"PhotoEX" ) ) ) {
17413ff48bf5SDavid du Colombier 
1742*593dc095SDavid du Colombier 		gs_free( dev->memory, render, 1, sizeof( RENDER ), "PhotoEX" );
17433ff48bf5SDavid du Colombier 		return_error( gs_error_VMerror );
17443ff48bf5SDavid du Colombier 	}
17453ff48bf5SDavid du Colombier 
17463ff48bf5SDavid du Colombier 	/* We've done every possible check and preparation, now
17473ff48bf5SDavid du Colombier 	   do the work. Fill the rest of the structure so we can pass
17483ff48bf5SDavid du Colombier 	   it to the actual render routine. */
17493ff48bf5SDavid du Colombier 
17503ff48bf5SDavid du Colombier 	render->dev		= dev;
17513ff48bf5SDavid du Colombier 	render->yres	= yres;
17523ff48bf5SDavid du Colombier 	render->xres	= xres;
17533ff48bf5SDavid du Colombier 	render->width	= width;
17543ff48bf5SDavid du Colombier 	render->lines	= dev->height;
17553ff48bf5SDavid du Colombier 	render->stream	= stream;
17563ff48bf5SDavid du Colombier 	render->mono	= dev->mono;
17573ff48bf5SDavid du Colombier 
17583ff48bf5SDavid du Colombier  	/* Initialise the printer */
17593ff48bf5SDavid du Colombier 
17603ff48bf5SDavid du Colombier 	SendReset( stream );
17613ff48bf5SDavid du Colombier 	SendReset( stream );
17623ff48bf5SDavid du Colombier 	SendGmode( stream, 1 );
17633ff48bf5SDavid du Colombier 
17643ff48bf5SDavid du Colombier 	/* Set up units */
17653ff48bf5SDavid du Colombier 
17663ff48bf5SDavid du Colombier 	unit = ( yres == 360 ) ? 360 : 720;
17673ff48bf5SDavid du Colombier 	SendUnit( stream, RESCODE( unit ) );
17683ff48bf5SDavid du Colombier 
17693ff48bf5SDavid du Colombier 	/* Set up papersize and margins */
17703ff48bf5SDavid du Colombier 
17713ff48bf5SDavid du Colombier 	SendPaper( stream, device->height / device->y_pixels_per_inch * unit );
17723ff48bf5SDavid du Colombier 	SendMargin( stream, ( psize - dev_b_margin( device ) ) * unit,
17733ff48bf5SDavid du Colombier 					    dev_t_margin( device ) * unit );
17743ff48bf5SDavid du Colombier 
17753ff48bf5SDavid du Colombier 	/* Dot size as per user setting */
17763ff48bf5SDavid du Colombier 
17773ff48bf5SDavid du Colombier 	if ( dev->dotsize )
17783ff48bf5SDavid du Colombier 
17793ff48bf5SDavid du Colombier 		SendInk( stream, dev->dotsize );
17803ff48bf5SDavid du Colombier 	else
17813ff48bf5SDavid du Colombier 		SendInk( stream, yres == 360 ? 3 : ( xres == 720 ? 2 : 1 ) );
17823ff48bf5SDavid du Colombier 
17833ff48bf5SDavid du Colombier 	/* Microveawe is off, unidirectional printing on */
17843ff48bf5SDavid du Colombier 
17853ff48bf5SDavid du Colombier 	SendMicro( stream, 0 );
17863ff48bf5SDavid du Colombier 	SendUnidir( stream, 1 );
17873ff48bf5SDavid du Colombier 
17883ff48bf5SDavid du Colombier 	/* Render the page and send image data to printer */
17893ff48bf5SDavid du Colombier 
17903ff48bf5SDavid du Colombier 	RenderPage( render );
17913ff48bf5SDavid du Colombier 
17923ff48bf5SDavid du Colombier 	/* Eject the paper, reset printer */
17933ff48bf5SDavid du Colombier 
17943ff48bf5SDavid du Colombier 	SendByte( stream, FF );
17953ff48bf5SDavid du Colombier 	SendReset( stream );
17963ff48bf5SDavid du Colombier 
17973ff48bf5SDavid du Colombier 	/* Release the memory and return */
17983ff48bf5SDavid du Colombier 
1799*593dc095SDavid du Colombier 	gs_free( dev->memory, render->dbuff, pixels, sizeof( long ), "PhotoEX" );
1800*593dc095SDavid du Colombier 	gs_free( dev->memory, render, 1, sizeof( RENDER ), "PhotoEX" );
18013ff48bf5SDavid du Colombier 	return( 0 );
18023ff48bf5SDavid du Colombier }
18033ff48bf5SDavid du Colombier 
18043ff48bf5SDavid du Colombier /*
18053ff48bf5SDavid du Colombier *	Renders a page
18063ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~
18073ff48bf5SDavid du Colombier */
18083ff48bf5SDavid du Colombier 
RenderPage(RENDER * p)18093ff48bf5SDavid du Colombier private	void	RenderPage( RENDER *p )
18103ff48bf5SDavid du Colombier {
18113ff48bf5SDavid du Colombier int		last_done;					/* The last line rendered				*/
18123ff48bf5SDavid du Colombier int		last_need;					/* The largest line number we need		*/
18133ff48bf5SDavid du Colombier int		move_down;					/* Amount of delayed head positioning	*/
18143ff48bf5SDavid du Colombier int		last_band;					/* Indicates the last band				*/
18153ff48bf5SDavid du Colombier int		min, max;					/* Min/max active bytes in a raw line	*/
18163ff48bf5SDavid du Colombier int		phase;						/* 1440dpi X weave offset				*/
18173ff48bf5SDavid du Colombier int		i, j, l, col;
18183ff48bf5SDavid du Colombier 
18193ff48bf5SDavid du Colombier 	p->htone_thold = HalftoneThold( p );
18203ff48bf5SDavid du Colombier 	p->htone_last  = -1 - p->htone_thold;
18213ff48bf5SDavid du Colombier 
18223ff48bf5SDavid du Colombier 	p->schedule.top   = -1;
18233ff48bf5SDavid du Colombier 	p->schedule.resol = p->xres;
18243ff48bf5SDavid du Colombier 	p->schedule.last  = p->lines;
18253ff48bf5SDavid du Colombier 
18263ff48bf5SDavid du Colombier 	last_done = -1;
18273ff48bf5SDavid du Colombier 	move_down = 0;
18283ff48bf5SDavid du Colombier 
18293ff48bf5SDavid du Colombier 	do {
18303ff48bf5SDavid du Colombier 
18313ff48bf5SDavid du Colombier 		/* Schedule the next batch of lines */
18323ff48bf5SDavid du Colombier 
18333ff48bf5SDavid du Colombier 		last_band = ScheduleLines( &p->schedule );
18343ff48bf5SDavid du Colombier 
18353ff48bf5SDavid du Colombier 		/* Find the largest line number we have to process and
18363ff48bf5SDavid du Colombier 		   halftone all lines which have not yet been done */
18373ff48bf5SDavid du Colombier 
18383ff48bf5SDavid du Colombier 		last_need = last_done;
18393ff48bf5SDavid du Colombier 		for ( i = NOZZLES-1 ; i >= 0 && p->schedule.head[ i ] == -1 ; i-- );
18403ff48bf5SDavid du Colombier 		if ( i >= 0 ) last_need = p->schedule.head[ i ];
18413ff48bf5SDavid du Colombier 		while ( last_need > last_done ) RenderLine( p, ++last_done );
18423ff48bf5SDavid du Colombier 
18433ff48bf5SDavid du Colombier 		/* Now loop through the colours and build the data stream */
18443ff48bf5SDavid du Colombier 
18453ff48bf5SDavid du Colombier 		phase = p->schedule.offset;
18463ff48bf5SDavid du Colombier 
18473ff48bf5SDavid du Colombier 		for ( col = 0 ; col < DCOLN ; col++ ) {
18483ff48bf5SDavid du Colombier 
18493ff48bf5SDavid du Colombier 			/* First see if we have to send any data at all */
18503ff48bf5SDavid du Colombier 
18513ff48bf5SDavid du Colombier 			min = MAX_BYTES;
18523ff48bf5SDavid du Colombier 			max = 0;
18533ff48bf5SDavid du Colombier 
18543ff48bf5SDavid du Colombier 			for ( i = 0 ; i < NOZZLES && i < p->schedule.nozzle ; i++ ) {
18553ff48bf5SDavid du Colombier 
18563ff48bf5SDavid du Colombier 				if ( ( j = p->schedule.head[ i ] ) != -1 ) {
18573ff48bf5SDavid du Colombier 
18583ff48bf5SDavid du Colombier 					j %= MAX_MARK;
18593ff48bf5SDavid du Colombier 
18603ff48bf5SDavid du Colombier 					if ( p->raw[ phase ][ col ][ j ].first < min )
18613ff48bf5SDavid du Colombier 
18623ff48bf5SDavid du Colombier 						min = p->raw[ phase ][ col ][ j ].first;
18633ff48bf5SDavid du Colombier 
18643ff48bf5SDavid du Colombier 					if ( p->raw[ phase ][ col ][ j ].last > max )
18653ff48bf5SDavid du Colombier 
18663ff48bf5SDavid du Colombier 						max = p->raw[ phase ][ col ][ j ].last;
18673ff48bf5SDavid du Colombier 				}
18683ff48bf5SDavid du Colombier 			}
18693ff48bf5SDavid du Colombier 
18703ff48bf5SDavid du Colombier 			if ( min <= max ) {
18713ff48bf5SDavid du Colombier 
18723ff48bf5SDavid du Colombier 				max++;
18733ff48bf5SDavid du Colombier 
18743ff48bf5SDavid du Colombier 				/* We have to send data to the printer. If we have
18753ff48bf5SDavid du Colombier 				   to position the head, do so now */
18763ff48bf5SDavid du Colombier 
18773ff48bf5SDavid du Colombier 				if ( move_down ) {
18783ff48bf5SDavid du Colombier 
18793ff48bf5SDavid du Colombier 					SendDown( p->stream, move_down );
18803ff48bf5SDavid du Colombier 					move_down = 0;
18813ff48bf5SDavid du Colombier 				}
18823ff48bf5SDavid du Colombier 
18833ff48bf5SDavid du Colombier 				/* Set the desired colour */
18843ff48bf5SDavid du Colombier 
18853ff48bf5SDavid du Colombier 				SendColour( p->stream, col );
18863ff48bf5SDavid du Colombier 
18873ff48bf5SDavid du Colombier 				/* Move the head to the desired position */
18883ff48bf5SDavid du Colombier 
18893ff48bf5SDavid du Colombier 				if ( p->xres == 360 )
18903ff48bf5SDavid du Colombier 
18913ff48bf5SDavid du Colombier 					SendRight( p->stream, 4 * 8 * min );
18923ff48bf5SDavid du Colombier 
18933ff48bf5SDavid du Colombier 				else if ( p->xres == 720 )
18943ff48bf5SDavid du Colombier 
18953ff48bf5SDavid du Colombier 					SendRight( p->stream, 2 * 8 * min );
18963ff48bf5SDavid du Colombier 				else
18973ff48bf5SDavid du Colombier 					SendRight( p->stream, 8 * min + phase );
18983ff48bf5SDavid du Colombier 
18993ff48bf5SDavid du Colombier 				/* Send the data */
19003ff48bf5SDavid du Colombier 
19013ff48bf5SDavid du Colombier 				SendData( p->stream, p->xres, p->yres, p->schedule.nozzle,
19023ff48bf5SDavid du Colombier 						  ( max-min ) * 8 );
19033ff48bf5SDavid du Colombier 
19043ff48bf5SDavid du Colombier 				for ( i = 0 ; i < p->schedule.nozzle ; i++ ) {
19053ff48bf5SDavid du Colombier 
19063ff48bf5SDavid du Colombier 					if ( ( j = p->schedule.head[ i ] ) == -1 ||
19073ff48bf5SDavid du Colombier 						 ( p->raw[ phase ][ col ][ j % MAX_MARK ].last <
19083ff48bf5SDavid du Colombier 						   p->raw[ phase ][ col ][ j % MAX_MARK ].first ) ) {
19093ff48bf5SDavid du Colombier 
19103ff48bf5SDavid du Colombier 						l = RleCompress( NULL, min, max, p->rle );
19113ff48bf5SDavid du Colombier 					}
19123ff48bf5SDavid du Colombier 					else {
19133ff48bf5SDavid du Colombier 
19143ff48bf5SDavid du Colombier 						l = RleCompress( p->raw[ phase ][ col ] + j % MAX_MARK,
19153ff48bf5SDavid du Colombier 									   min, max, p->rle );
19163ff48bf5SDavid du Colombier 					}
19173ff48bf5SDavid du Colombier 
19183ff48bf5SDavid du Colombier 					fwrite( p->rle, l, 1, p->stream );
19193ff48bf5SDavid du Colombier 				}
19203ff48bf5SDavid du Colombier 
19213ff48bf5SDavid du Colombier 				SendByte( p->stream, CR );
19223ff48bf5SDavid du Colombier 			}
19233ff48bf5SDavid du Colombier 		}
19243ff48bf5SDavid du Colombier 
19253ff48bf5SDavid du Colombier 		/* Note the amount the head should go down before it prints the
19263ff48bf5SDavid du Colombier 		   next band */
19273ff48bf5SDavid du Colombier 
19283ff48bf5SDavid du Colombier 		move_down += p->schedule.down;
19293ff48bf5SDavid du Colombier 
19303ff48bf5SDavid du Colombier 	} while	( ! last_band );
19313ff48bf5SDavid du Colombier }
19323ff48bf5SDavid du Colombier 
19333ff48bf5SDavid du Colombier /*
19343ff48bf5SDavid du Colombier *	Render the the next scanline
19353ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19363ff48bf5SDavid du Colombier *
19373ff48bf5SDavid du Colombier *	If it finds a continuous sequence of empty lines, it renders
19383ff48bf5SDavid du Colombier *	the first htone_thold number of them then stops calling the
19393ff48bf5SDavid du Colombier *	actual rendering function (which is computationally expensive).
19403ff48bf5SDavid du Colombier *	When it sees a nonempty line again, it restarts the renderer.
19413ff48bf5SDavid du Colombier */
19423ff48bf5SDavid du Colombier 
RenderLine(RENDER * p,int line)19433ff48bf5SDavid du Colombier private	void	RenderLine( RENDER *p, int line )
19443ff48bf5SDavid du Colombier {
19453ff48bf5SDavid du Colombier byte	*data;
19463ff48bf5SDavid du Colombier int		i;
19473ff48bf5SDavid du Colombier 
19483ff48bf5SDavid du Colombier 	/* Get the line from Ghostscript and see if its empty */
19493ff48bf5SDavid du Colombier 
19503ff48bf5SDavid du Colombier 	gdev_prn_get_bits( (PDEV *) p->dev, line, p->dbuff, &data );
19513ff48bf5SDavid du Colombier 
19523ff48bf5SDavid du Colombier 	if ( IsScanlineEmpty( p, data ) ) {
19533ff48bf5SDavid du Colombier 
19543ff48bf5SDavid du Colombier 		if ( line - p->htone_last > p->htone_thold ) {
19553ff48bf5SDavid du Colombier 
19563ff48bf5SDavid du Colombier 			/* The line is empty and is farer from the last nonempty
19573ff48bf5SDavid du Colombier 			   line than the threshold, no need to render it. */
19583ff48bf5SDavid du Colombier 
19593ff48bf5SDavid du Colombier 			for ( i = 0 ; i < DCOLN ; i++ ) {
19603ff48bf5SDavid du Colombier 
19613ff48bf5SDavid du Colombier 				p->raw[ 0 ][ i ][ line % MAX_MARK ].first = MAX_BYTES;
19623ff48bf5SDavid du Colombier 				p->raw[ 0 ][ i ][ line % MAX_MARK ].last  = 0;
19633ff48bf5SDavid du Colombier 				p->raw[ 1 ][ i ][ line % MAX_MARK ].first = MAX_BYTES;
19643ff48bf5SDavid du Colombier 				p->raw[ 1 ][ i ][ line % MAX_MARK ].last  = 0;
19653ff48bf5SDavid du Colombier 
19663ff48bf5SDavid du Colombier 			}
19673ff48bf5SDavid du Colombier 		}
19683ff48bf5SDavid du Colombier 		else {
19693ff48bf5SDavid du Colombier 
19703ff48bf5SDavid du Colombier 			/* The line is empty but it is within the threshold, so we
19713ff48bf5SDavid du Colombier 			   have to render it. We do not move the index, though */
19723ff48bf5SDavid du Colombier 
19733ff48bf5SDavid du Colombier 			HalftoneLine( p, line, data );
19743ff48bf5SDavid du Colombier 		}
19753ff48bf5SDavid du Colombier 	}
19763ff48bf5SDavid du Colombier 	else {
19773ff48bf5SDavid du Colombier 
19783ff48bf5SDavid du Colombier 		/* This line is not empty */
19793ff48bf5SDavid du Colombier 
19803ff48bf5SDavid du Colombier 		if ( line - p->htone_last >= p->htone_thold ) {
19813ff48bf5SDavid du Colombier 
19823ff48bf5SDavid du Colombier 			/* Previous lines were empty and we have already stopped
19833ff48bf5SDavid du Colombier 			   rendering them. We have to restart the renderer */
19843ff48bf5SDavid du Colombier 
19853ff48bf5SDavid du Colombier 			HalftonerStart( p, line );
19863ff48bf5SDavid du Colombier 		}
19873ff48bf5SDavid du Colombier 
19883ff48bf5SDavid du Colombier 		/* Render the line and move the last active index to this line */
19893ff48bf5SDavid du Colombier 
19903ff48bf5SDavid du Colombier 		HalftoneLine( p, line, data );
19913ff48bf5SDavid du Colombier 		p->htone_last = line;
19923ff48bf5SDavid du Colombier 	}
19933ff48bf5SDavid du Colombier }
19943ff48bf5SDavid du Colombier 
19953ff48bf5SDavid du Colombier /*
19963ff48bf5SDavid du Colombier *	This function tests if a scanline is empty
19973ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19983ff48bf5SDavid du Colombier */
19993ff48bf5SDavid du Colombier 
IsScanlineEmpty(RENDER * r,byte * line)20003ff48bf5SDavid du Colombier private	int		IsScanlineEmpty( RENDER *r, byte *line )
20013ff48bf5SDavid du Colombier {
20023ff48bf5SDavid du Colombier int		i;
20033ff48bf5SDavid du Colombier long	*p;
20043ff48bf5SDavid du Colombier 
20053ff48bf5SDavid du Colombier 	p = (long *) line;
20063ff48bf5SDavid du Colombier 
20073ff48bf5SDavid du Colombier 	for ( i = 0 ; i < r->width ; i++ ) {
20083ff48bf5SDavid du Colombier 
20093ff48bf5SDavid du Colombier 		if ( *p++ ) return( FALSE );
20103ff48bf5SDavid du Colombier 	}
20113ff48bf5SDavid du Colombier 
20123ff48bf5SDavid du Colombier 	return( TRUE );
20133ff48bf5SDavid du Colombier }
20143ff48bf5SDavid du Colombier 
20153ff48bf5SDavid du Colombier /****************************************************************************/
20163ff48bf5SDavid du Colombier /*						Microweaved line scheduling							*/
20173ff48bf5SDavid du Colombier /****************************************************************************/
20183ff48bf5SDavid du Colombier 
20193ff48bf5SDavid du Colombier /*
20203ff48bf5SDavid du Colombier *	Schedule head data for the next band
20213ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20223ff48bf5SDavid du Colombier *
20233ff48bf5SDavid du Colombier *	This function fills the SCHEDUL structure with information
20243ff48bf5SDavid du Colombier *	about what to print. The head field will contain the line numbers
20253ff48bf5SDavid du Colombier *	which are assigned to the nozzles in the head. -1 means that
20263ff48bf5SDavid du Colombier *	no active data is assigned to the nozzle in this band.
20273ff48bf5SDavid du Colombier *	The offset field is only used for horizontal microweaving, if it
20283ff48bf5SDavid du Colombier *	is set then the line should be offseted by 1/1440".
20293ff48bf5SDavid du Colombier *	The down field contains the number of units which the head should
20303ff48bf5SDavid du Colombier *	move down when printing of the band is finished. Other fields are
20313ff48bf5SDavid du Colombier *	mainly for the routine's internal use. At the first call, however,
20323ff48bf5SDavid du Colombier *	the top field should be set to -1, the resol field should be set
20333ff48bf5SDavid du Colombier *	to 360, 720 or 1440 and the last field should contain the number
20343ff48bf5SDavid du Colombier *	of lines to print (that is, last + 1 :-).
20353ff48bf5SDavid du Colombier *
20363ff48bf5SDavid du Colombier *	The routine returns a flag indicating if this was the last print
20373ff48bf5SDavid du Colombier *	for the page.
20383ff48bf5SDavid du Colombier */
20393ff48bf5SDavid du Colombier 
ScheduleLines(SCHEDUL * p)20403ff48bf5SDavid du Colombier private	int	ScheduleLines( SCHEDUL *p )
20413ff48bf5SDavid du Colombier {
20423ff48bf5SDavid du Colombier int		i;
20433ff48bf5SDavid du Colombier 
20443ff48bf5SDavid du Colombier 	if ( p->top == -1 ) {
20453ff48bf5SDavid du Colombier 
20463ff48bf5SDavid du Colombier 		/* First call, init everything, then fall through to the rest */
20473ff48bf5SDavid du Colombier 
20483ff48bf5SDavid du Colombier 		SchedulerInit( p );
20493ff48bf5SDavid du Colombier 	}
20503ff48bf5SDavid du Colombier 
20513ff48bf5SDavid du Colombier 	/* If nozzle is one, just schedule the next line and that's it.
20523ff48bf5SDavid du Colombier 	   You can use this feature for hardware microweave at 720 dpi,
20533ff48bf5SDavid du Colombier 	   the driver uses it for 360 dpi. */
20543ff48bf5SDavid du Colombier 
20553ff48bf5SDavid du Colombier 	if ( p->nozzle == 1 ) {
20563ff48bf5SDavid du Colombier 
20573ff48bf5SDavid du Colombier 		p->head[ 0 ] = p->top;
20583ff48bf5SDavid du Colombier 		p->down = 1;
20593ff48bf5SDavid du Colombier 		p->top++;
20603ff48bf5SDavid du Colombier 		return( p->top == p->last );
20613ff48bf5SDavid du Colombier 	}
20623ff48bf5SDavid du Colombier 
20633ff48bf5SDavid du Colombier 	/* Release all expired entries in the mark array */
20643ff48bf5SDavid du Colombier 
20653ff48bf5SDavid du Colombier 	for ( i = p->markbeg ; i < p->top ; i++ ) p->mark[ i % MAX_MARK ] = 0;
20663ff48bf5SDavid du Colombier 	p->markbeg = p->top;
20673ff48bf5SDavid du Colombier 
20683ff48bf5SDavid du Colombier 	/* If top is less than the the head spacing, then create the image
20693ff48bf5SDavid du Colombier 	   by single steps. This will cause banding on the very top, but
20703ff48bf5SDavid du Colombier 	   there's nothing we can do about it. We're still better than
20713ff48bf5SDavid du Colombier 	   Epson's driver which simply ignores the first few lines,
20723ff48bf5SDavid du Colombier 	   it does not even try to schedule them ... */
20733ff48bf5SDavid du Colombier 
20743ff48bf5SDavid du Colombier 	if ( p->top < HEAD_SPACING ) {
20753ff48bf5SDavid du Colombier 
20763ff48bf5SDavid du Colombier 		ScheduleLeading( p );
20773ff48bf5SDavid du Colombier 		return( FALSE );
20783ff48bf5SDavid du Colombier 	}
20793ff48bf5SDavid du Colombier 
20803ff48bf5SDavid du Colombier 	/* See if we are almost at the end. If yes, we will advance line by
20813ff48bf5SDavid du Colombier 	   line. */
20823ff48bf5SDavid du Colombier 
20833ff48bf5SDavid du Colombier 	if ( p->top + p->resol + (NOZZLES) * HEAD_SPACING > p->last ) {
20843ff48bf5SDavid du Colombier 
20853ff48bf5SDavid du Colombier  		ScheduleTrailing( p );
20863ff48bf5SDavid du Colombier 
20873ff48bf5SDavid du Colombier 		if ( p->down )
20883ff48bf5SDavid du Colombier 
20893ff48bf5SDavid du Colombier 			return( p->top + (NOZZLES-1) * HEAD_SPACING >= p->last );
20903ff48bf5SDavid du Colombier 		else
20913ff48bf5SDavid du Colombier 			return( FALSE );
20923ff48bf5SDavid du Colombier 	}
20933ff48bf5SDavid du Colombier 
20943ff48bf5SDavid du Colombier 	/* Otherwise we're in the middle of the page, just do the
20953ff48bf5SDavid du Colombier 	   simple banding and selecting as many lines as we can. */
20963ff48bf5SDavid du Colombier 
20973ff48bf5SDavid du Colombier 	ScheduleMiddle( p );
20983ff48bf5SDavid du Colombier 	return( FALSE );
20993ff48bf5SDavid du Colombier }
21003ff48bf5SDavid du Colombier 
21013ff48bf5SDavid du Colombier /*
21023ff48bf5SDavid du Colombier *	Initialise the scheduler
21033ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~
21043ff48bf5SDavid du Colombier */
21053ff48bf5SDavid du Colombier 
SchedulerInit(SCHEDUL * p)21063ff48bf5SDavid du Colombier private	void	SchedulerInit( SCHEDUL *p )
21073ff48bf5SDavid du Colombier {
21083ff48bf5SDavid du Colombier int		i;
21093ff48bf5SDavid du Colombier 
21103ff48bf5SDavid du Colombier 	p->top = 0;
21113ff48bf5SDavid du Colombier 
21123ff48bf5SDavid du Colombier 	switch ( p->resol ) {
21133ff48bf5SDavid du Colombier 
21143ff48bf5SDavid du Colombier 		case 360:
21153ff48bf5SDavid du Colombier 			p->offset = 0;
21163ff48bf5SDavid du Colombier 			p->resol  = BAND_360;
21173ff48bf5SDavid du Colombier 			p->nozzle = NOZZLE_360;
21183ff48bf5SDavid du Colombier 			break;
21193ff48bf5SDavid du Colombier 
21203ff48bf5SDavid du Colombier 		case 720:
21213ff48bf5SDavid du Colombier 			p->offset = 0;
21223ff48bf5SDavid du Colombier 			p->resol  = BAND_720;
21233ff48bf5SDavid du Colombier 			p->nozzle = NOZZLE_720;
21243ff48bf5SDavid du Colombier 			break;
21253ff48bf5SDavid du Colombier 
21263ff48bf5SDavid du Colombier 		case 1440:
21273ff48bf5SDavid du Colombier 			p->offset = 1;			/* Need to be set for the algorithm! */
21283ff48bf5SDavid du Colombier 			p->resol  = BAND_1440;
21293ff48bf5SDavid du Colombier 			p->nozzle = NOZZLE_1440;
21303ff48bf5SDavid du Colombier 			break;
21313ff48bf5SDavid du Colombier 	}
21323ff48bf5SDavid du Colombier 
21333ff48bf5SDavid du Colombier 	for ( i = 0 ; i < NOZZLES  ; i++ ) p->head[ i ] = -1;
21343ff48bf5SDavid du Colombier 	for ( i = 0 ; i < MAX_MARK ; i++ ) p->mark[ i ] = 0;
21353ff48bf5SDavid du Colombier 	p->markbeg = 0;
21363ff48bf5SDavid du Colombier }
21373ff48bf5SDavid du Colombier 
21383ff48bf5SDavid du Colombier /*
21393ff48bf5SDavid du Colombier *	Scheduling the first BAND lines for the image
21403ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21413ff48bf5SDavid du Colombier */
21423ff48bf5SDavid du Colombier 
ScheduleLeading(SCHEDUL * p)21433ff48bf5SDavid du Colombier private	void	ScheduleLeading( SCHEDUL *p )
21443ff48bf5SDavid du Colombier {
21453ff48bf5SDavid du Colombier int		i;
21463ff48bf5SDavid du Colombier 
21473ff48bf5SDavid du Colombier 	if ( p->resol == BAND_720 ) {
21483ff48bf5SDavid du Colombier 
21493ff48bf5SDavid du Colombier 		/* Copy the line scheduling data to the struct */
21503ff48bf5SDavid du Colombier 
21513ff48bf5SDavid du Colombier 		memcpy( p->head, start_720[ p->top ], sizeof( int ) * NOZZLES );
21523ff48bf5SDavid du Colombier 
21533ff48bf5SDavid du Colombier 		/* Mark all lines to be set */
21543ff48bf5SDavid du Colombier 
21553ff48bf5SDavid du Colombier 		for ( i = 0 ; i < NOZZLES ; i++ )
21563ff48bf5SDavid du Colombier 
21573ff48bf5SDavid du Colombier 			if ( p->head[ i ] != -1 )
21583ff48bf5SDavid du Colombier 
21593ff48bf5SDavid du Colombier 				p->mark[ p->head[ i ] % MAX_MARK ] = 1;
21603ff48bf5SDavid du Colombier 
21613ff48bf5SDavid du Colombier 		/* We move down by one line except at the end */
21623ff48bf5SDavid du Colombier 
21633ff48bf5SDavid du Colombier 		if ( p->top == HEAD_SPACING - 1 ) {
21643ff48bf5SDavid du Colombier 
21653ff48bf5SDavid du Colombier 			p->down = BAND_720 - p->top;
21663ff48bf5SDavid du Colombier 			p->top  = BAND_720;
21673ff48bf5SDavid du Colombier 		}
21683ff48bf5SDavid du Colombier 		else {
21693ff48bf5SDavid du Colombier 
21703ff48bf5SDavid du Colombier 			p->down = 1;
21713ff48bf5SDavid du Colombier 			p->top++;
21723ff48bf5SDavid du Colombier 		}
21733ff48bf5SDavid du Colombier 	}
21743ff48bf5SDavid du Colombier 	else {
21753ff48bf5SDavid du Colombier 
21763ff48bf5SDavid du Colombier 		/* 1440 dpi version, two passes needed for each scanline */
21773ff48bf5SDavid du Colombier 
21783ff48bf5SDavid du Colombier 		if ( p->offset ) {
21793ff48bf5SDavid du Colombier 
21803ff48bf5SDavid du Colombier 			/* Copy the non-offseted scheduling data to the struct */
21813ff48bf5SDavid du Colombier 
21823ff48bf5SDavid du Colombier 			memcpy( p->head, start_1440[0][p->top], sizeof( int ) * NOZZLES );
21833ff48bf5SDavid du Colombier 
21843ff48bf5SDavid du Colombier 			/* Mark all lines to be set */
21853ff48bf5SDavid du Colombier 
21863ff48bf5SDavid du Colombier 			for ( i = 0 ; i < NOZZLES ; i++ )
21873ff48bf5SDavid du Colombier 
21883ff48bf5SDavid du Colombier 				if ( p->head[ i ] != -1 )
21893ff48bf5SDavid du Colombier 
21903ff48bf5SDavid du Colombier 					p->mark[ p->head[ i ] % MAX_MARK ] = 1;
21913ff48bf5SDavid du Colombier 
21923ff48bf5SDavid du Colombier 			/* This is the non-offseted line, do not move ! */
21933ff48bf5SDavid du Colombier 
21943ff48bf5SDavid du Colombier 			p->offset = 0;
21953ff48bf5SDavid du Colombier 			p->down = 0;
21963ff48bf5SDavid du Colombier 		}
21973ff48bf5SDavid du Colombier 		else {
21983ff48bf5SDavid du Colombier 
21993ff48bf5SDavid du Colombier 			/* Copy the non-offseted schduling data to the struct */
22003ff48bf5SDavid du Colombier 
22013ff48bf5SDavid du Colombier 			memcpy( p->head, start_1440[1][p->top], sizeof( int ) * NOZZLES );
22023ff48bf5SDavid du Colombier 
22033ff48bf5SDavid du Colombier 			/* Mark all lines to be set */
22043ff48bf5SDavid du Colombier 
22053ff48bf5SDavid du Colombier 			for ( i = 0 ; i < NOZZLES ; i++ )
22063ff48bf5SDavid du Colombier 
22073ff48bf5SDavid du Colombier 				if ( p->head[ i ] != -1 )
22083ff48bf5SDavid du Colombier 
22093ff48bf5SDavid du Colombier 					p->mark[ p->head[ i ] % MAX_MARK ] |= 2;
22103ff48bf5SDavid du Colombier 
22113ff48bf5SDavid du Colombier 			/* We move down by one line except at the end and set offset */
22123ff48bf5SDavid du Colombier 
22133ff48bf5SDavid du Colombier 			if ( p->top == HEAD_SPACING - 1 ) {
22143ff48bf5SDavid du Colombier 
22153ff48bf5SDavid du Colombier 				p->down = BAND_1440 - p->top;
22163ff48bf5SDavid du Colombier 				p->top  = BAND_1440;
22173ff48bf5SDavid du Colombier 			}
22183ff48bf5SDavid du Colombier 			else {
22193ff48bf5SDavid du Colombier 
22203ff48bf5SDavid du Colombier 				p->down = 1;
22213ff48bf5SDavid du Colombier 				p->top++;
22223ff48bf5SDavid du Colombier 			}
22233ff48bf5SDavid du Colombier 
22243ff48bf5SDavid du Colombier 			p->offset = 1;
22253ff48bf5SDavid du Colombier 		}
22263ff48bf5SDavid du Colombier 	}
22273ff48bf5SDavid du Colombier }
22283ff48bf5SDavid du Colombier 
22293ff48bf5SDavid du Colombier /*
22303ff48bf5SDavid du Colombier *	Scheduling the bulk of the image
22313ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22323ff48bf5SDavid du Colombier */
22333ff48bf5SDavid du Colombier 
ScheduleMiddle(SCHEDUL * p)22343ff48bf5SDavid du Colombier private	void	ScheduleMiddle( SCHEDUL *p )
22353ff48bf5SDavid du Colombier {
22363ff48bf5SDavid du Colombier int		ph0, ph1;
22373ff48bf5SDavid du Colombier int		line, mask;
22383ff48bf5SDavid du Colombier int		i;
22393ff48bf5SDavid du Colombier 
22403ff48bf5SDavid du Colombier 	if ( p->resol == BAND_720 ) {
22413ff48bf5SDavid du Colombier 
22423ff48bf5SDavid du Colombier 		/* 720 DPI printing. See which lines should we print and
22433ff48bf5SDavid du Colombier 		   fill the head array accordingly, then move down a band. */
22443ff48bf5SDavid du Colombier 
22453ff48bf5SDavid du Colombier 		ScheduleBand( p, 1 );
22463ff48bf5SDavid du Colombier 		p->down = BAND_720;
22473ff48bf5SDavid du Colombier 		p->top += BAND_720;
22483ff48bf5SDavid du Colombier 	}
22493ff48bf5SDavid du Colombier 	else {
22503ff48bf5SDavid du Colombier 
22513ff48bf5SDavid du Colombier 		/* 1440 dpi printing. This is a bit more complex than the
22523ff48bf5SDavid du Colombier 		   720 dpi one. First, see how many lines in each phase
22533ff48bf5SDavid du Colombier 		   has already been printed. */
22543ff48bf5SDavid du Colombier 
22553ff48bf5SDavid du Colombier 		ph0 = ph1 = 0;
22563ff48bf5SDavid du Colombier 
22573ff48bf5SDavid du Colombier 		for ( line = p->top, i=0 ; i < NOZZLES ; i++, line += HEAD_SPACING ) {
22583ff48bf5SDavid du Colombier 
22593ff48bf5SDavid du Colombier 			line = p->top + i * HEAD_SPACING;
22603ff48bf5SDavid du Colombier 			ph0 += p->mark[ line % MAX_MARK ] & 1;
22613ff48bf5SDavid du Colombier 			ph1 += p->mark[ line % MAX_MARK ] & 2;
22623ff48bf5SDavid du Colombier 		}
22633ff48bf5SDavid du Colombier 
22643ff48bf5SDavid du Colombier 		ph1 >>= 1;
22653ff48bf5SDavid du Colombier 
22663ff48bf5SDavid du Colombier 		/* Choose the phase which has less lines in it. */
22673ff48bf5SDavid du Colombier 
22683ff48bf5SDavid du Colombier 		if ( ph0 <= ph1 ) {
22693ff48bf5SDavid du Colombier 
22703ff48bf5SDavid du Colombier 			p->offset = 0;
22713ff48bf5SDavid du Colombier 			mask = 1;
22723ff48bf5SDavid du Colombier 		}
22733ff48bf5SDavid du Colombier 		else {
22743ff48bf5SDavid du Colombier 
22753ff48bf5SDavid du Colombier 			p->offset = 1;
22763ff48bf5SDavid du Colombier 			mask = 2;
22773ff48bf5SDavid du Colombier 		}
22783ff48bf5SDavid du Colombier 
22793ff48bf5SDavid du Colombier 		/* Fill the line array and mark the phase.
22803ff48bf5SDavid du Colombier 		   We should check here if moving down the head will leave
22813ff48bf5SDavid du Colombier 		   any line empty, but we do not because we *know* that it
22823ff48bf5SDavid du Colombier 		   won't - the BAND_1440 is selected by finding a value
22833ff48bf5SDavid du Colombier 		   which guarantees that it will cover every line. */
22843ff48bf5SDavid du Colombier 
22853ff48bf5SDavid du Colombier 		ScheduleBand( p, mask );
22863ff48bf5SDavid du Colombier 		p->down = BAND_1440;
22873ff48bf5SDavid du Colombier 		p->top += BAND_1440;
22883ff48bf5SDavid du Colombier 	}
22893ff48bf5SDavid du Colombier }
22903ff48bf5SDavid du Colombier 
22913ff48bf5SDavid du Colombier /*
22923ff48bf5SDavid du Colombier *	Scheduling the last lines of the image
22933ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22943ff48bf5SDavid du Colombier */
22953ff48bf5SDavid du Colombier 
ScheduleTrailing(SCHEDUL * p)22963ff48bf5SDavid du Colombier private	void	ScheduleTrailing( SCHEDUL *p )
22973ff48bf5SDavid du Colombier {
22983ff48bf5SDavid du Colombier int		mask;
22993ff48bf5SDavid du Colombier 
23003ff48bf5SDavid du Colombier 	if ( p->down > 1 ) {
23013ff48bf5SDavid du Colombier 
23023ff48bf5SDavid du Colombier 		/* This is the first time we came here. */
23033ff48bf5SDavid du Colombier 
23043ff48bf5SDavid du Colombier 		p->offset = 1;
23053ff48bf5SDavid du Colombier 	}
23063ff48bf5SDavid du Colombier 
23073ff48bf5SDavid du Colombier 	if ( p->resol == BAND_720 ) {
23083ff48bf5SDavid du Colombier 
23093ff48bf5SDavid du Colombier 		p->offset = 0;
23103ff48bf5SDavid du Colombier 		p->down   = 1;
23113ff48bf5SDavid du Colombier 		mask	  = 1;
23123ff48bf5SDavid du Colombier 	}
23133ff48bf5SDavid du Colombier 	else {
23143ff48bf5SDavid du Colombier 
23153ff48bf5SDavid du Colombier 		if ( p->offset ) {
23163ff48bf5SDavid du Colombier 
23173ff48bf5SDavid du Colombier 			p->offset = 0;
23183ff48bf5SDavid du Colombier 			p->down	  = 0;
23193ff48bf5SDavid du Colombier 			mask	  = 1;
23203ff48bf5SDavid du Colombier 		}
23213ff48bf5SDavid du Colombier 		else {
23223ff48bf5SDavid du Colombier 
23233ff48bf5SDavid du Colombier 			p->offset = 1;
23243ff48bf5SDavid du Colombier 			p->down	  = 1;
23253ff48bf5SDavid du Colombier 			mask	  = 2;
23263ff48bf5SDavid du Colombier 		}
23273ff48bf5SDavid du Colombier 	}
23283ff48bf5SDavid du Colombier 
23293ff48bf5SDavid du Colombier 	ScheduleBand( p, mask );
23303ff48bf5SDavid du Colombier 	p->top += p->down;
23313ff48bf5SDavid du Colombier }
23323ff48bf5SDavid du Colombier 
23333ff48bf5SDavid du Colombier /*
23343ff48bf5SDavid du Colombier *	Select lines from a given set
23353ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23363ff48bf5SDavid du Colombier */
23373ff48bf5SDavid du Colombier 
ScheduleBand(SCHEDUL * p,int mask)23383ff48bf5SDavid du Colombier private	void	ScheduleBand( SCHEDUL *p, int mask )
23393ff48bf5SDavid du Colombier {
23403ff48bf5SDavid du Colombier int		i;
23413ff48bf5SDavid du Colombier int		line;
23423ff48bf5SDavid du Colombier 
23433ff48bf5SDavid du Colombier 	for ( line = p->top, i = 0 ; i < NOZZLES ; i++, line += HEAD_SPACING ) {
23443ff48bf5SDavid du Colombier 
23453ff48bf5SDavid du Colombier 
23463ff48bf5SDavid du Colombier 		if ( p->mark[ line % MAX_MARK ] & mask ) {
23473ff48bf5SDavid du Colombier 
23483ff48bf5SDavid du Colombier 			p->head[ i ] = -1;
23493ff48bf5SDavid du Colombier 		}
23503ff48bf5SDavid du Colombier 		else {
23513ff48bf5SDavid du Colombier 
23523ff48bf5SDavid du Colombier 			p->head[ i ] = line;
23533ff48bf5SDavid du Colombier 			p->mark[ line % MAX_MARK ] |= mask;
23543ff48bf5SDavid du Colombier 		}
23553ff48bf5SDavid du Colombier 	}
23563ff48bf5SDavid du Colombier }
23573ff48bf5SDavid du Colombier 
23583ff48bf5SDavid du Colombier /****************************************************************************/
23593ff48bf5SDavid du Colombier /*						Formatting printer data								*/
23603ff48bf5SDavid du Colombier /****************************************************************************/
23613ff48bf5SDavid du Colombier 
23623ff48bf5SDavid du Colombier /*
23633ff48bf5SDavid du Colombier *	Packs a line to raw device format
23643ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23653ff48bf5SDavid du Colombier *
23663ff48bf5SDavid du Colombier *	Reads pixnum pixels and if the pixel is lev_on, then sets the
23673ff48bf5SDavid du Colombier *	appropriate bit in the resulting datastream. The length of the
23683ff48bf5SDavid du Colombier *	result is pixnum/8 (rounded up).
23693ff48bf5SDavid du Colombier */
23703ff48bf5SDavid du Colombier 
PackLine(byte * input,int pixnum,int lev_on,int step,RAWLINE * line)23713ff48bf5SDavid du Colombier private	void	PackLine( byte *input, int pixnum, int lev_on, int step,
23723ff48bf5SDavid du Colombier 						  RAWLINE *line )
23733ff48bf5SDavid du Colombier {
23743ff48bf5SDavid du Colombier byte	bits;
23753ff48bf5SDavid du Colombier char	*result;
23763ff48bf5SDavid du Colombier int		i, j, k;
23773ff48bf5SDavid du Colombier 
23783ff48bf5SDavid du Colombier 	result = line->data;
23793ff48bf5SDavid du Colombier 	line->first = MAX_PIXELS;
23803ff48bf5SDavid du Colombier 	line->last  = 0;
23813ff48bf5SDavid du Colombier 
23823ff48bf5SDavid du Colombier 	for ( j = 0x80, bits = k = i = 0 ; i < pixnum ; i += step, input += step ){
23833ff48bf5SDavid du Colombier 
23843ff48bf5SDavid du Colombier 		if ( *input == lev_on ) bits |= j;
23853ff48bf5SDavid du Colombier 
23863ff48bf5SDavid du Colombier 		if ( ! ( j >>= 1 ) ) {
23873ff48bf5SDavid du Colombier 
23883ff48bf5SDavid du Colombier 			if ( bits ) {
23893ff48bf5SDavid du Colombier 
23903ff48bf5SDavid du Colombier 				if ( line->first > k ) line->first = k;
23913ff48bf5SDavid du Colombier 				if ( line->last  < k ) line->last  = k;
23923ff48bf5SDavid du Colombier 			}
23933ff48bf5SDavid du Colombier 
23943ff48bf5SDavid du Colombier 			*result++ = bits;
23953ff48bf5SDavid du Colombier 			j		  = 0x80;
23963ff48bf5SDavid du Colombier 			bits	  = 0;
23973ff48bf5SDavid du Colombier 			k++;
23983ff48bf5SDavid du Colombier 		}
23993ff48bf5SDavid du Colombier 	}
24003ff48bf5SDavid du Colombier 
24013ff48bf5SDavid du Colombier 	if ( j != 0x80 ) {
24023ff48bf5SDavid du Colombier 
24033ff48bf5SDavid du Colombier 		*result = bits;
24043ff48bf5SDavid du Colombier 
24053ff48bf5SDavid du Colombier 		if ( bits ) {
24063ff48bf5SDavid du Colombier 
24073ff48bf5SDavid du Colombier 			if ( line->first > k ) line->first = k;
24083ff48bf5SDavid du Colombier 			if ( line->last  < k ) line->last  = k;
24093ff48bf5SDavid du Colombier 		}
24103ff48bf5SDavid du Colombier 	}
24113ff48bf5SDavid du Colombier }
24123ff48bf5SDavid du Colombier 
24133ff48bf5SDavid du Colombier /*
24143ff48bf5SDavid du Colombier *	Compresses (run-length encodes) a line
24153ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24163ff48bf5SDavid du Colombier *
24173ff48bf5SDavid du Colombier *	Returns the length of the RLE data.
24183ff48bf5SDavid du Colombier */
24193ff48bf5SDavid du Colombier 
RleCompress(RAWLINE * raw,int min,int max,byte * rle_data)24203ff48bf5SDavid du Colombier private	int		RleCompress( RAWLINE *raw, int min, int max, byte *rle_data )
24213ff48bf5SDavid du Colombier {
24223ff48bf5SDavid du Colombier int		i, n;
24233ff48bf5SDavid du Colombier byte	pbyte;
24243ff48bf5SDavid du Colombier byte	*start, *rstrt;
24253ff48bf5SDavid du Colombier int		length;
24263ff48bf5SDavid du Colombier byte	*input;
24273ff48bf5SDavid du Colombier int 	len;
24283ff48bf5SDavid du Colombier 
24293ff48bf5SDavid du Colombier 	if ( ! raw ) {
24303ff48bf5SDavid du Colombier 
24313ff48bf5SDavid du Colombier 		/* This is an empty line */
24323ff48bf5SDavid du Colombier 
24333ff48bf5SDavid du Colombier 		for ( n = 0, i = max - min ; i >= 129 ; i -= 129 ) {
24343ff48bf5SDavid du Colombier 
24353ff48bf5SDavid du Colombier 			*rle_data++ = 128;
24363ff48bf5SDavid du Colombier 			*rle_data++ = 0;
24373ff48bf5SDavid du Colombier 			n += 2;
24383ff48bf5SDavid du Colombier 		}
24393ff48bf5SDavid du Colombier 
24403ff48bf5SDavid du Colombier 		if ( i >= 2 ) {
24413ff48bf5SDavid du Colombier 
24423ff48bf5SDavid du Colombier 			*rle_data++ = 257 - i;
24433ff48bf5SDavid du Colombier 			*rle_data++ = 0;
24443ff48bf5SDavid du Colombier 			n += 2;
24453ff48bf5SDavid du Colombier 		}
24463ff48bf5SDavid du Colombier 		else if ( i ) {
24473ff48bf5SDavid du Colombier 
24483ff48bf5SDavid du Colombier 			*rle_data++ = 0;
24493ff48bf5SDavid du Colombier 			*rle_data++ = 0;
24503ff48bf5SDavid du Colombier 			n+= 2;
24513ff48bf5SDavid du Colombier 		}
24523ff48bf5SDavid du Colombier 
24533ff48bf5SDavid du Colombier 		return( n );
24543ff48bf5SDavid du Colombier 	}
24553ff48bf5SDavid du Colombier 
24563ff48bf5SDavid du Colombier 	/* There's data, set up encoding parameters */
24573ff48bf5SDavid du Colombier 
24583ff48bf5SDavid du Colombier 	input = raw->data + min;
24593ff48bf5SDavid du Colombier 	len   = max - min;
24603ff48bf5SDavid du Colombier 
24613ff48bf5SDavid du Colombier 	/* Create a run-length encoded version. We do it even if no pixel
24623ff48bf5SDavid du Colombier 	   was set because it may be that this line is just part of a
24633ff48bf5SDavid du Colombier 	   multi-line band. */
24643ff48bf5SDavid du Colombier 
24653ff48bf5SDavid du Colombier 	length = 0;
24663ff48bf5SDavid du Colombier 	start  = input;
24673ff48bf5SDavid du Colombier 	rstrt  = NULL;
24683ff48bf5SDavid du Colombier 	pbyte  = *input++;
24693ff48bf5SDavid du Colombier 
24703ff48bf5SDavid du Colombier 	for ( i = 1 ; i < len ; i++, input++ ) {
24713ff48bf5SDavid du Colombier 
24723ff48bf5SDavid du Colombier 		if ( *input == pbyte ) {
24733ff48bf5SDavid du Colombier 
24743ff48bf5SDavid du Colombier 			/* This byte is identical to the previous one(s). */
24753ff48bf5SDavid du Colombier 
24763ff48bf5SDavid du Colombier 			if ( ! rstrt ) {
24773ff48bf5SDavid du Colombier 
24783ff48bf5SDavid du Colombier 				/* This is the start of a new repeating sequence */
24793ff48bf5SDavid du Colombier 
24803ff48bf5SDavid du Colombier 				rstrt = input - 1;
24813ff48bf5SDavid du Colombier 			}
24823ff48bf5SDavid du Colombier 		}
24833ff48bf5SDavid du Colombier 		else {
24843ff48bf5SDavid du Colombier 
24853ff48bf5SDavid du Colombier 			/* Different byte than the previous one(s) */
24863ff48bf5SDavid du Colombier 
24873ff48bf5SDavid du Colombier 			if ( rstrt ) {
24883ff48bf5SDavid du Colombier 
24893ff48bf5SDavid du Colombier 				/* There was a repetitive sequence. */
24903ff48bf5SDavid du Colombier 
24913ff48bf5SDavid du Colombier 				if ( rstrt - input < 4 ) {
24923ff48bf5SDavid du Colombier 
24933ff48bf5SDavid du Colombier 					/* For less than four bytes it isn't worth
24943ff48bf5SDavid du Colombier 					   to do RLE, we discard them */
24953ff48bf5SDavid du Colombier 
24963ff48bf5SDavid du Colombier 					rstrt = NULL;
24973ff48bf5SDavid du Colombier 				}
24983ff48bf5SDavid du Colombier 				else {
24993ff48bf5SDavid du Colombier 
25003ff48bf5SDavid du Colombier 					/* We must flush */
25013ff48bf5SDavid du Colombier 
25023ff48bf5SDavid du Colombier 					n = RleFlush( start, rstrt, input, rle_data );
25033ff48bf5SDavid du Colombier 					rle_data  += n;
25043ff48bf5SDavid du Colombier 					length += n;
25053ff48bf5SDavid du Colombier 
25063ff48bf5SDavid du Colombier 					/* Initialise again */
25073ff48bf5SDavid du Colombier 
25083ff48bf5SDavid du Colombier 					start = rle_data;
25093ff48bf5SDavid du Colombier 					rstrt = NULL;
25103ff48bf5SDavid du Colombier 				}
25113ff48bf5SDavid du Colombier 			}
25123ff48bf5SDavid du Colombier 
25133ff48bf5SDavid du Colombier 			pbyte = *rle_data;
25143ff48bf5SDavid du Colombier 		}
25153ff48bf5SDavid du Colombier 	}
25163ff48bf5SDavid du Colombier 
25173ff48bf5SDavid du Colombier 	/* We flush whatever is left over */
25183ff48bf5SDavid du Colombier 
25193ff48bf5SDavid du Colombier 	length += RleFlush( start, rstrt, input, rle_data );
25203ff48bf5SDavid du Colombier 
25213ff48bf5SDavid du Colombier 	return( length );
25223ff48bf5SDavid du Colombier }
25233ff48bf5SDavid du Colombier 
25243ff48bf5SDavid du Colombier /*
25253ff48bf5SDavid du Colombier *	This function flushes the RLE encoding buffer
25263ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25273ff48bf5SDavid du Colombier *
25283ff48bf5SDavid du Colombier *	Assumes that it gets a nonrepetitive pattern followed by a repetitive
25293ff48bf5SDavid du Colombier *	one. 'first' points to the start of the non-repetitive part.
25303ff48bf5SDavid du Colombier *	'reps' points to the first byte in the repetitive sequence or it
25313ff48bf5SDavid du Colombier *	may be NULL, if there were no repetitve bytes. 'now' points to
25323ff48bf5SDavid du Colombier *	one after the last byte in the sequence.
25333ff48bf5SDavid du Colombier *	It puts the result into 'out' and returns the number of bytes
25343ff48bf5SDavid du Colombier *	written out.
25353ff48bf5SDavid du Colombier *
25363ff48bf5SDavid du Colombier *	There is one possible performance penalty in using this method:
25373ff48bf5SDavid du Colombier *	If the repetitive sequence is n*128+1 byte long, then the last
25383ff48bf5SDavid du Colombier *	byte will be written out as single byte. If the following sequence
25393ff48bf5SDavid du Colombier *	has a nonrepetitive start, this byte could be combined into that
25403ff48bf5SDavid du Colombier *	but it isn't. This can cause some penalty, however, we will live
25413ff48bf5SDavid du Colombier *	with that for now.
25423ff48bf5SDavid du Colombier */
25433ff48bf5SDavid du Colombier 
RleFlush(byte * first,byte * reps,byte * now,byte * out)25443ff48bf5SDavid du Colombier private	int		RleFlush( byte *first, byte *reps, byte *now, byte *out )
25453ff48bf5SDavid du Colombier {
25463ff48bf5SDavid du Colombier int		count;
25473ff48bf5SDavid du Colombier int		l;
25483ff48bf5SDavid du Colombier 
25493ff48bf5SDavid du Colombier 	if ( ! first ) return( 0 );
25503ff48bf5SDavid du Colombier 
25513ff48bf5SDavid du Colombier 	if ( ! reps ) reps = now;
25523ff48bf5SDavid du Colombier 
25533ff48bf5SDavid du Colombier 	count = 0;
25543ff48bf5SDavid du Colombier 
25553ff48bf5SDavid du Colombier 	/* Write the nonrepetitve pattern first */
25563ff48bf5SDavid du Colombier 
25573ff48bf5SDavid du Colombier 	while ( ( l = reps - first ) ) {
25583ff48bf5SDavid du Colombier 
25593ff48bf5SDavid du Colombier 		if ( l > 128 ) {
25603ff48bf5SDavid du Colombier 
25613ff48bf5SDavid du Colombier 			/* More than 128 consecutive bytes, write out a 128 byte chunk */
25623ff48bf5SDavid du Colombier 
25633ff48bf5SDavid du Colombier 			*out++ = 127;
25643ff48bf5SDavid du Colombier 			memcpy( out, first, 128 );
25653ff48bf5SDavid du Colombier 			out   += 128;
25663ff48bf5SDavid du Colombier 			first += 128;
25673ff48bf5SDavid du Colombier 			count += 129;
25683ff48bf5SDavid du Colombier 		}
25693ff48bf5SDavid du Colombier 		else {
25703ff48bf5SDavid du Colombier 
25713ff48bf5SDavid du Colombier 			/* There are not more than 128 bytes, write them into a
25723ff48bf5SDavid du Colombier 			   single chunk */
25733ff48bf5SDavid du Colombier 
25743ff48bf5SDavid du Colombier 			*out++ = l - 1;
25753ff48bf5SDavid du Colombier 			memcpy( out, first, l );
25763ff48bf5SDavid du Colombier 			count += l + 1;
25773ff48bf5SDavid du Colombier 			first += l;
25783ff48bf5SDavid du Colombier 			out   += l;
25793ff48bf5SDavid du Colombier 		}
25803ff48bf5SDavid du Colombier 	}
25813ff48bf5SDavid du Colombier 
25823ff48bf5SDavid du Colombier 	/* Now write the repeated pattern */
25833ff48bf5SDavid du Colombier 
25843ff48bf5SDavid du Colombier 	while ( ( l = now - reps ) ) {
25853ff48bf5SDavid du Colombier 
25863ff48bf5SDavid du Colombier 		if ( l > 128 ) {
25873ff48bf5SDavid du Colombier 
25883ff48bf5SDavid du Colombier 			/* More than 128 bytes are identical, write out a
25893ff48bf5SDavid du Colombier 			   129 byte chunk */
25903ff48bf5SDavid du Colombier 
25913ff48bf5SDavid du Colombier 			*out++ = 128;
25923ff48bf5SDavid du Colombier 			*out++ = *reps;
25933ff48bf5SDavid du Colombier 			count += 2;
25943ff48bf5SDavid du Colombier 			reps  += 129;
25953ff48bf5SDavid du Colombier 		}
25963ff48bf5SDavid du Colombier 		else {
25973ff48bf5SDavid du Colombier 
25983ff48bf5SDavid du Colombier 			if ( l == 1 ) {
25993ff48bf5SDavid du Colombier 
26003ff48bf5SDavid du Colombier 				/* There is only one byte left, write it out as a
26013ff48bf5SDavid du Colombier 				   nonrepetitive chunk */
26023ff48bf5SDavid du Colombier 
26033ff48bf5SDavid du Colombier 				*out++ = 0;
26043ff48bf5SDavid du Colombier 				*out++ = *reps;
26053ff48bf5SDavid du Colombier 				count += 2;
26063ff48bf5SDavid du Colombier 				reps++;
26073ff48bf5SDavid du Colombier 			}
26083ff48bf5SDavid du Colombier 			else {
26093ff48bf5SDavid du Colombier 
26103ff48bf5SDavid du Colombier 				/* What remains is at least 2 bytes but not larger than what
26113ff48bf5SDavid du Colombier 				   can be written in a single chunk */
26123ff48bf5SDavid du Colombier 
26133ff48bf5SDavid du Colombier 				*out++ = 257 - l;
26143ff48bf5SDavid du Colombier 				*out++ = *reps;
26153ff48bf5SDavid du Colombier 				count += 2;
26163ff48bf5SDavid du Colombier 				reps   = now;
26173ff48bf5SDavid du Colombier 			}
26183ff48bf5SDavid du Colombier 		}
26193ff48bf5SDavid du Colombier 	}
26203ff48bf5SDavid du Colombier 
26213ff48bf5SDavid du Colombier 	return( count );
26223ff48bf5SDavid du Colombier }
26233ff48bf5SDavid du Colombier 
26243ff48bf5SDavid du Colombier /****************************************************************************/
26253ff48bf5SDavid du Colombier /*		Low level procedures to send various commands to the printer		*/
26263ff48bf5SDavid du Colombier /****************************************************************************/
26273ff48bf5SDavid du Colombier 
SendReset(FILE * stream)26283ff48bf5SDavid du Colombier private	void	SendReset( FILE *stream )
26293ff48bf5SDavid du Colombier {
26303ff48bf5SDavid du Colombier 	SendString( stream, ESC "@" );
26313ff48bf5SDavid du Colombier }
26323ff48bf5SDavid du Colombier 
SendMargin(FILE * stream,int top,int bot)26333ff48bf5SDavid du Colombier private	void	SendMargin( FILE *stream, int top, int bot )
26343ff48bf5SDavid du Colombier {
26353ff48bf5SDavid du Colombier 	SendString( stream, ESC "(c" );
26363ff48bf5SDavid du Colombier 	SendWord( stream, 4 );
26373ff48bf5SDavid du Colombier 	SendWord( stream, bot );
26383ff48bf5SDavid du Colombier 	SendWord( stream, top );
26393ff48bf5SDavid du Colombier }
26403ff48bf5SDavid du Colombier 
SendPaper(FILE * stream,int length)26413ff48bf5SDavid du Colombier private	void	SendPaper( FILE *stream, int length )
26423ff48bf5SDavid du Colombier {
26433ff48bf5SDavid du Colombier 	SendString( stream, ESC "(C" );
26443ff48bf5SDavid du Colombier 	SendWord( stream, 2 );
26453ff48bf5SDavid du Colombier 	SendWord( stream, length );
26463ff48bf5SDavid du Colombier }
26473ff48bf5SDavid du Colombier 
SendGmode(FILE * stream,int on)26483ff48bf5SDavid du Colombier private	void	SendGmode( FILE *stream, int on )
26493ff48bf5SDavid du Colombier {
26503ff48bf5SDavid du Colombier 	SendString( stream, ESC "(G" );
26513ff48bf5SDavid du Colombier 	SendWord( stream, 1 );
26523ff48bf5SDavid du Colombier 	SendByte( stream, on );
26533ff48bf5SDavid du Colombier }
26543ff48bf5SDavid du Colombier 
SendUnit(FILE * stream,int res)26553ff48bf5SDavid du Colombier private void	SendUnit( FILE *stream, int res )
26563ff48bf5SDavid du Colombier {
26573ff48bf5SDavid du Colombier 	SendString( stream, ESC "(U" );
26583ff48bf5SDavid du Colombier 	SendWord( stream, 1 );
26593ff48bf5SDavid du Colombier 	SendByte( stream, res );
26603ff48bf5SDavid du Colombier }
26613ff48bf5SDavid du Colombier 
SendUnidir(FILE * stream,int on)26623ff48bf5SDavid du Colombier private	void	SendUnidir( FILE *stream, int on )
26633ff48bf5SDavid du Colombier {
26643ff48bf5SDavid du Colombier 	SendString( stream, ESC "U" );
26653ff48bf5SDavid du Colombier 	SendByte( stream, on );
26663ff48bf5SDavid du Colombier }
26673ff48bf5SDavid du Colombier 
SendMicro(FILE * stream,int on)26683ff48bf5SDavid du Colombier private	void	SendMicro( FILE *stream, int on )
26693ff48bf5SDavid du Colombier {
26703ff48bf5SDavid du Colombier 	SendString( stream, ESC "(i" );
26713ff48bf5SDavid du Colombier 	SendWord( stream, 1 );
26723ff48bf5SDavid du Colombier 	SendByte( stream, on );
26733ff48bf5SDavid du Colombier }
26743ff48bf5SDavid du Colombier 
SendInk(FILE * stream,int x)26753ff48bf5SDavid du Colombier private void	SendInk( FILE *stream, int x )
26763ff48bf5SDavid du Colombier {
26773ff48bf5SDavid du Colombier 	SendString( stream, ESC "(e" );
26783ff48bf5SDavid du Colombier 	SendWord( stream, 2 );
26793ff48bf5SDavid du Colombier 	SendByte( stream, 0 );
26803ff48bf5SDavid du Colombier 	SendByte( stream, x );
26813ff48bf5SDavid du Colombier }
26823ff48bf5SDavid du Colombier 
SendDown(FILE * stream,int x)26833ff48bf5SDavid du Colombier private	void	SendDown( FILE *stream, int x )
26843ff48bf5SDavid du Colombier {
26853ff48bf5SDavid du Colombier 	SendString( stream, ESC "(v" );
26863ff48bf5SDavid du Colombier 	SendWord( stream, 2 );
26873ff48bf5SDavid du Colombier 	SendWord( stream, x );
26883ff48bf5SDavid du Colombier }
26893ff48bf5SDavid du Colombier 
SendRight(FILE * stream,int amount)26903ff48bf5SDavid du Colombier private	void	SendRight( FILE *stream, int amount )
26913ff48bf5SDavid du Colombier {
26923ff48bf5SDavid du Colombier 	SendString( stream, ESC "(\\" );
26933ff48bf5SDavid du Colombier 	SendWord( stream, 4 );
26943ff48bf5SDavid du Colombier 	SendWord( stream, 1440 );
26953ff48bf5SDavid du Colombier 	SendWord( stream, amount );
26963ff48bf5SDavid du Colombier }
26973ff48bf5SDavid du Colombier 
SendColour(FILE * stream,int col)26983ff48bf5SDavid du Colombier private	void	SendColour( FILE *stream, int col )
26993ff48bf5SDavid du Colombier {
27003ff48bf5SDavid du Colombier static	int	ccode[] = { 0x000, 0x200, 0x100, 0x400, 0x201, 0x101 };
27013ff48bf5SDavid du Colombier 
27023ff48bf5SDavid du Colombier 	SendString( stream, ESC "(r" );
27033ff48bf5SDavid du Colombier 	SendWord( stream, 2 );
27043ff48bf5SDavid du Colombier 	SendWord( stream, ccode[ col ] );
27053ff48bf5SDavid du Colombier }
27063ff48bf5SDavid du Colombier 
SendData(FILE * stream,int hres,int vres,int noz,int col)27073ff48bf5SDavid du Colombier private void	SendData( FILE *stream, int hres, int vres, int noz, int col )
27083ff48bf5SDavid du Colombier {
27093ff48bf5SDavid du Colombier 	SendString( stream, ESC "." );
27103ff48bf5SDavid du Colombier 	SendByte( stream, 1 );				/* Run-length encoded data */
27113ff48bf5SDavid du Colombier 
27123ff48bf5SDavid du Colombier 	/* If we use 1 nozzle, then vertical resolution is what it is.
27133ff48bf5SDavid du Colombier 	   Otherwise it must be set to 90 dpi */
27143ff48bf5SDavid du Colombier 
27153ff48bf5SDavid du Colombier 	if ( noz == 1 )
27163ff48bf5SDavid du Colombier 
27173ff48bf5SDavid du Colombier 		SendByte( stream, RESCODE( vres ) );
27183ff48bf5SDavid du Colombier 	else
27193ff48bf5SDavid du Colombier 		SendByte( stream, RESCODE( 90 ) );
27203ff48bf5SDavid du Colombier 
27213ff48bf5SDavid du Colombier 	/* The horizontal resolution is max. 720 dpi */
27223ff48bf5SDavid du Colombier 
27233ff48bf5SDavid du Colombier 	if ( hres > 720 )
27243ff48bf5SDavid du Colombier 
27253ff48bf5SDavid du Colombier 		SendByte( stream, RESCODE( 720 ) );
27263ff48bf5SDavid du Colombier 	else
27273ff48bf5SDavid du Colombier 		SendByte( stream, RESCODE( hres ) );
27283ff48bf5SDavid du Colombier 
27293ff48bf5SDavid du Colombier 	SendByte( stream, noz );
27303ff48bf5SDavid du Colombier 	SendWord( stream, col );
27313ff48bf5SDavid du Colombier }
27323ff48bf5SDavid du Colombier 
SendString(FILE * stream,const char * s)27333ff48bf5SDavid du Colombier private	void	SendString( FILE *stream, const char *s )
27343ff48bf5SDavid du Colombier {
27353ff48bf5SDavid du Colombier 	while ( *s ) SendByte( stream, *s++ );
27363ff48bf5SDavid du Colombier }
27373ff48bf5SDavid du Colombier 
27383ff48bf5SDavid du Colombier /****************************************************************************/
27393ff48bf5SDavid du Colombier /*					Halftoning wrapper functions							*/
27403ff48bf5SDavid du Colombier /****************************************************************************/
27413ff48bf5SDavid du Colombier 
27423ff48bf5SDavid du Colombier /*
27433ff48bf5SDavid du Colombier *	Calls the start function of the choosen halftoner
27443ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27453ff48bf5SDavid du Colombier */
27463ff48bf5SDavid du Colombier 
HalftonerStart(RENDER * render,int line)27473ff48bf5SDavid du Colombier private	void	HalftonerStart( RENDER *render, int line )
27483ff48bf5SDavid du Colombier {
27493ff48bf5SDavid du Colombier 	(*(htable[ render->dev->halftoner ].hstrt))( render, line );
27503ff48bf5SDavid du Colombier }
27513ff48bf5SDavid du Colombier 
27523ff48bf5SDavid du Colombier /*
27533ff48bf5SDavid du Colombier *	Returns the restart threshold for the given halftoner
27543ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27553ff48bf5SDavid du Colombier */
27563ff48bf5SDavid du Colombier 
HalftoneThold(RENDER * render)27573ff48bf5SDavid du Colombier private	int		HalftoneThold( RENDER *render )
27583ff48bf5SDavid du Colombier {
27593ff48bf5SDavid du Colombier 	return( (*(htable[ render->dev->halftoner ].hthld))( render ) );
27603ff48bf5SDavid du Colombier }
27613ff48bf5SDavid du Colombier 
27623ff48bf5SDavid du Colombier /*
27633ff48bf5SDavid du Colombier *	This function renders a line
27643ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27653ff48bf5SDavid du Colombier *
27663ff48bf5SDavid du Colombier *	This function has one fundamental assumption: halftoning of separate
27673ff48bf5SDavid du Colombier *	colours is independent of each other.
27683ff48bf5SDavid du Colombier *
27693ff48bf5SDavid du Colombier *	It calls the mono halftoner with the K, C, M, Y components.
27703ff48bf5SDavid du Colombier */
27713ff48bf5SDavid du Colombier 
HalftoneLine(RENDER * render,int line,byte * data)27723ff48bf5SDavid du Colombier private	void	HalftoneLine( RENDER *render, int line, byte *data )
27733ff48bf5SDavid du Colombier {
27743ff48bf5SDavid du Colombier void		(*htone)( HTONE *, int );
27753ff48bf5SDavid du Colombier EDEV		*dev;
27763ff48bf5SDavid du Colombier int			offs;
27773ff48bf5SDavid du Colombier HTONE		hdata;
27783ff48bf5SDavid du Colombier short		*errs[ MAX_ED_LINES ];
27793ff48bf5SDavid du Colombier int			i;
27803ff48bf5SDavid du Colombier 
27813ff48bf5SDavid du Colombier 	/* Get the rendering function */
27823ff48bf5SDavid du Colombier 
27833ff48bf5SDavid du Colombier 	dev   = render->dev;
27843ff48bf5SDavid du Colombier 	htone = htable[ render->dev->halftoner ].htone;
27853ff48bf5SDavid du Colombier 	offs  = render->mono ? 0 : OFFS_K;
27863ff48bf5SDavid du Colombier 
27873ff48bf5SDavid du Colombier 	if ( dev->mono ) {
27883ff48bf5SDavid du Colombier 
27893ff48bf5SDavid du Colombier 		/* Monochrome, do only the black */
27903ff48bf5SDavid du Colombier 
27913ff48bf5SDavid du Colombier 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
27923ff48bf5SDavid du Colombier 
27933ff48bf5SDavid du Colombier 			errs[ i ] = render->error[ i ][ OFFS_K ];
27943ff48bf5SDavid du Colombier 
27953ff48bf5SDavid du Colombier 		hdata.render = render;
27963ff48bf5SDavid du Colombier 		hdata.data   = data + OFFS_K;
27973ff48bf5SDavid du Colombier 		hdata.step	 = sizeof( byte );
27983ff48bf5SDavid du Colombier 		hdata.res	 = render->res[ OFFS_K ];
27993ff48bf5SDavid du Colombier 		hdata.block  = NULL;
28003ff48bf5SDavid du Colombier 		hdata.err	 = errs;
28013ff48bf5SDavid du Colombier 		hdata.mval	 = 255;
28023ff48bf5SDavid du Colombier 
28033ff48bf5SDavid du Colombier 		(*htone)( &hdata, line );
28043ff48bf5SDavid du Colombier 	}
28053ff48bf5SDavid du Colombier 	else {
28063ff48bf5SDavid du Colombier 
28073ff48bf5SDavid du Colombier 		/* Colour. D black first */
28083ff48bf5SDavid du Colombier 
28093ff48bf5SDavid du Colombier 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
28103ff48bf5SDavid du Colombier 
28113ff48bf5SDavid du Colombier 			errs[ i ] = render->error[ i ][ OFFS_K ];
28123ff48bf5SDavid du Colombier 
28133ff48bf5SDavid du Colombier 		hdata.render = render;
28143ff48bf5SDavid du Colombier 		hdata.step	 = sizeof( long );
28153ff48bf5SDavid du Colombier 		hdata.data   = data + OFFS_K;
28163ff48bf5SDavid du Colombier 		hdata.res	 = render->res[ OFFS_K ];
28173ff48bf5SDavid du Colombier 		hdata.block  = NULL;
28183ff48bf5SDavid du Colombier 		hdata.err	 = errs;
28193ff48bf5SDavid du Colombier 		hdata.mval	 = 255;
28203ff48bf5SDavid du Colombier 
28213ff48bf5SDavid du Colombier 		(*htone)( &hdata, line );
28223ff48bf5SDavid du Colombier 
28233ff48bf5SDavid du Colombier 		/* Yellow has no intermediate ink. The already done black
28243ff48bf5SDavid du Colombier 		   may inhibit it. */
28253ff48bf5SDavid du Colombier 
28263ff48bf5SDavid du Colombier 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
28273ff48bf5SDavid du Colombier 
28283ff48bf5SDavid du Colombier 			errs[ i ] = render->error[ i ][ OFFS_Y ];
28293ff48bf5SDavid du Colombier 
28303ff48bf5SDavid du Colombier 		hdata.render = render;
28313ff48bf5SDavid du Colombier 		hdata.step	 = sizeof( long );
28323ff48bf5SDavid du Colombier 		hdata.data   = data + OFFS_Y;
28333ff48bf5SDavid du Colombier 		hdata.res	 = render->res[ OFFS_Y ];
28343ff48bf5SDavid du Colombier 		hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
28353ff48bf5SDavid du Colombier 		hdata.err	 = errs;
28363ff48bf5SDavid du Colombier 		hdata.mval	 = 255;
28373ff48bf5SDavid du Colombier 
28383ff48bf5SDavid du Colombier 		(*htone)( &hdata, line );
28393ff48bf5SDavid du Colombier 
28403ff48bf5SDavid du Colombier 		/* Cyan and magenta has intermediate colour ink, black may inhibit */
28413ff48bf5SDavid du Colombier 
28423ff48bf5SDavid du Colombier 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
28433ff48bf5SDavid du Colombier 
28443ff48bf5SDavid du Colombier 			errs[ i ] = render->error[ i ][ OFFS_C ];
28453ff48bf5SDavid du Colombier 
28463ff48bf5SDavid du Colombier 		hdata.data   = data + OFFS_C;
28473ff48bf5SDavid du Colombier 		hdata.res	 = render->res[ OFFS_C ];
28483ff48bf5SDavid du Colombier 		hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
28493ff48bf5SDavid du Colombier 		hdata.mval	 = dev->midcyan;
28503ff48bf5SDavid du Colombier 
28513ff48bf5SDavid du Colombier 		(*htone)( &hdata, line );
28523ff48bf5SDavid du Colombier 
28533ff48bf5SDavid du Colombier 		for ( i = 0 ; i < MAX_ED_LINES ; i++ )
28543ff48bf5SDavid du Colombier 
28553ff48bf5SDavid du Colombier 			errs[ i ] = render->error[ i ][ OFFS_M ];
28563ff48bf5SDavid du Colombier 
28573ff48bf5SDavid du Colombier 		hdata.data   = data + OFFS_M;
28583ff48bf5SDavid du Colombier 		hdata.res	 = render->res[ OFFS_M ];
28593ff48bf5SDavid du Colombier 		hdata.block  = dev->pureblack ? render->res[ OFFS_K ] : NULL;
28603ff48bf5SDavid du Colombier 		hdata.mval	 = dev->midmagenta;
28613ff48bf5SDavid du Colombier 
28623ff48bf5SDavid du Colombier 		(*htone)( &hdata, line );
28633ff48bf5SDavid du Colombier 	}
28643ff48bf5SDavid du Colombier 
28653ff48bf5SDavid du Colombier 	/* Here we have create the raw device format scanlines */
28663ff48bf5SDavid du Colombier 
28673ff48bf5SDavid du Colombier 	if ( dev->mono ) {
28683ff48bf5SDavid du Colombier 
28693ff48bf5SDavid du Colombier 		if ( render->xres == 1440 ) {
28703ff48bf5SDavid du Colombier 
28713ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_K ], render->width, 255, 2,
28723ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
28733ff48bf5SDavid du Colombier 
28743ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_K ]+1, render->width-1, 255, 2,
28753ff48bf5SDavid du Colombier 					  render->raw[ 1 ][ DEV_BLACK ]+ line % MAX_MARK );
28763ff48bf5SDavid du Colombier 		}
28773ff48bf5SDavid du Colombier 		else {
28783ff48bf5SDavid du Colombier 
28793ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_K ], render->width, 255, 1,
28803ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
28813ff48bf5SDavid du Colombier 		}
28823ff48bf5SDavid du Colombier 	}
28833ff48bf5SDavid du Colombier 	else {
28843ff48bf5SDavid du Colombier 
28853ff48bf5SDavid du Colombier 		if ( render->xres == 1440 ) {
28863ff48bf5SDavid du Colombier 
28873ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_K ], render->width, 255, 2,
28883ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
28893ff48bf5SDavid du Colombier 
28903ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_K ]+1, render->width-1, 255, 2,
28913ff48bf5SDavid du Colombier 					  render->raw[ 1 ][ DEV_BLACK ]+ line % MAX_MARK );
28923ff48bf5SDavid du Colombier 
28933ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_C ], render->width, 255, 2,
28943ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_CYAN ]+ line % MAX_MARK );
28953ff48bf5SDavid du Colombier 
28963ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_C ]+1, render->width-1, 255, 2,
28973ff48bf5SDavid du Colombier 					  render->raw[ 1 ][ DEV_CYAN ]+ line % MAX_MARK );
28983ff48bf5SDavid du Colombier 
28993ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_M ], render->width, 255, 2,
29003ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_MAGENTA ]+ line % MAX_MARK);
29013ff48bf5SDavid du Colombier 
29023ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_M ]+1, render->width-1, 255, 2,
29033ff48bf5SDavid du Colombier 					  render->raw[ 1 ][ DEV_MAGENTA ]+ line % MAX_MARK);
29043ff48bf5SDavid du Colombier 
29053ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_Y ], render->width, 255, 2,
29063ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_YELLOW ]+ line % MAX_MARK );
29073ff48bf5SDavid du Colombier 
29083ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_Y ]+1, render->width-1, 255, 2,
29093ff48bf5SDavid du Colombier 					  render->raw[ 1 ][ DEV_YELLOW ]+ line % MAX_MARK );
29103ff48bf5SDavid du Colombier 
29113ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_C ], render->width, dev->midcyan,
29123ff48bf5SDavid du Colombier 					  2, render->raw[ 0 ][ DEV_LCYAN ]+ line % MAX_MARK );
29133ff48bf5SDavid du Colombier 
29143ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_C ]+1, render->width-1, dev->midcyan,
29153ff48bf5SDavid du Colombier 					  2, render->raw[ 1 ][ DEV_LCYAN ]+ line % MAX_MARK );
29163ff48bf5SDavid du Colombier 
29173ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_M ], render->width, dev->midmagenta,
29183ff48bf5SDavid du Colombier 					  2, render->raw[0][ DEV_LMAGENTA ]+ line % MAX_MARK );
29193ff48bf5SDavid du Colombier 
29203ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_M ]+1, render->width-1,dev->midmagenta,
29213ff48bf5SDavid du Colombier 					  2, render->raw[1][ DEV_LMAGENTA ]+ line % MAX_MARK );
29223ff48bf5SDavid du Colombier 		}
29233ff48bf5SDavid du Colombier 		else {
29243ff48bf5SDavid du Colombier 
29253ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_K ], render->width, 255, 1,
29263ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_BLACK ]+ line % MAX_MARK );
29273ff48bf5SDavid du Colombier 
29283ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_C ], render->width, 255, 1,
29293ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_CYAN ]+ line % MAX_MARK );
29303ff48bf5SDavid du Colombier 
29313ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_M ], render->width, 255, 1,
29323ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_MAGENTA ]+ line % MAX_MARK);
29333ff48bf5SDavid du Colombier 
29343ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_Y ], render->width, 255, 1,
29353ff48bf5SDavid du Colombier 					  render->raw[ 0 ][ DEV_YELLOW ]+ line % MAX_MARK );
29363ff48bf5SDavid du Colombier 
29373ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_C ], render->width, dev->midcyan,
29383ff48bf5SDavid du Colombier 					  1, render->raw[ 0 ][ DEV_LCYAN ]+ line % MAX_MARK );
29393ff48bf5SDavid du Colombier 
29403ff48bf5SDavid du Colombier 			PackLine( render->res[ OFFS_M ], render->width, dev->midmagenta,
29413ff48bf5SDavid du Colombier 					  1, render->raw[0][ DEV_LMAGENTA ]+ line % MAX_MARK );
29423ff48bf5SDavid du Colombier 		}
29433ff48bf5SDavid du Colombier 	}
29443ff48bf5SDavid du Colombier 
29453ff48bf5SDavid du Colombier 	/* Call the halftoner specific end-of-line function */
29463ff48bf5SDavid du Colombier 
29473ff48bf5SDavid du Colombier 	(*htable[ render->dev->halftoner ].hteol)( render, line );
29483ff48bf5SDavid du Colombier }
29493ff48bf5SDavid du Colombier 
29503ff48bf5SDavid du Colombier /****************************************************************************/
29513ff48bf5SDavid du Colombier /*					Floyd - Steinberg error diffusion						*/
29523ff48bf5SDavid du Colombier /****************************************************************************/
29533ff48bf5SDavid du Colombier 
29543ff48bf5SDavid du Colombier /*
29553ff48bf5SDavid du Colombier *	This function returns the empty range threshold
29563ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29573ff48bf5SDavid du Colombier */
29583ff48bf5SDavid du Colombier 
FloydSThold(RENDER * p)29593ff48bf5SDavid du Colombier private	int		FloydSThold( RENDER *p )
29603ff48bf5SDavid du Colombier {
29613ff48bf5SDavid du Colombier 	return( 5 );
29623ff48bf5SDavid du Colombier }
29633ff48bf5SDavid du Colombier 
29643ff48bf5SDavid du Colombier /*
29653ff48bf5SDavid du Colombier *	This function initialises the halftoner
29663ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29673ff48bf5SDavid du Colombier */
29683ff48bf5SDavid du Colombier 
FloydSStart(RENDER * p,int line)29693ff48bf5SDavid du Colombier private	void	FloydSStart( RENDER *p, int line )
29703ff48bf5SDavid du Colombier {
29713ff48bf5SDavid du Colombier 	memset( p->err, 0, ICOLN * MAX_PIXELS*2 );
29723ff48bf5SDavid du Colombier 	p->error[ 0 ] = p->err[ 0 ];
29733ff48bf5SDavid du Colombier }
29743ff48bf5SDavid du Colombier 
29753ff48bf5SDavid du Colombier /*
29763ff48bf5SDavid du Colombier *	This function does the end-of-line processing
29773ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29783ff48bf5SDavid du Colombier */
29793ff48bf5SDavid du Colombier 
FloydSEol(RENDER * p,int line)29803ff48bf5SDavid du Colombier private	void	FloydSEol( RENDER *p, int line )
29813ff48bf5SDavid du Colombier {
29823ff48bf5SDavid du Colombier 	/* Since we use single error buffering, nothing to do */
29833ff48bf5SDavid du Colombier }
29843ff48bf5SDavid du Colombier 
29853ff48bf5SDavid du Colombier /*
29863ff48bf5SDavid du Colombier *	This is the classical Floyd-Steinberg error diffusion.
29873ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29883ff48bf5SDavid du Colombier *
29893ff48bf5SDavid du Colombier *	The matrix is the following:
29903ff48bf5SDavid du Colombier *
29913ff48bf5SDavid du Colombier *          *    7/16	r
29923ff48bf5SDavid du Colombier *   3/16  5/16  1/16
29933ff48bf5SDavid du Colombier *
29943ff48bf5SDavid du Colombier *	r is the residual (0, in theory).
29953ff48bf5SDavid du Colombier *	Absolutely nothing fancy is done here.
29963ff48bf5SDavid du Colombier *
29973ff48bf5SDavid du Colombier */
29983ff48bf5SDavid du Colombier 
FloydSLine(HTONE * htone,int y)29993ff48bf5SDavid du Colombier private	void   FloydSLine( HTONE *htone, int y )
30003ff48bf5SDavid du Colombier {
30013ff48bf5SDavid du Colombier int		x;							/* Counts the pixels					*/
30023ff48bf5SDavid du Colombier int		pixel;						/* Current pixel value					*/
30033ff48bf5SDavid du Colombier int		pixerr;						/* Error value							*/
30043ff48bf5SDavid du Colombier int		length;						/* Number of pixels to process			*/
30053ff48bf5SDavid du Colombier byte	*res;						/* Result								*/
30063ff48bf5SDavid du Colombier byte	*data;						/* Input data							*/
30073ff48bf5SDavid du Colombier byte	*block;						/* Block pixel							*/
30083ff48bf5SDavid du Colombier int		lim1, lim2;					/* Limits								*/
30093ff48bf5SDavid du Colombier short	e0, e1;						/* Propagating errors in current line	*/
30103ff48bf5SDavid du Colombier short	*l0;						/* Error buffer pointer					*/
30113ff48bf5SDavid du Colombier 
30123ff48bf5SDavid du Colombier 	length  = htone->render->width;
30133ff48bf5SDavid du Colombier 
30143ff48bf5SDavid du Colombier 	res		= htone->res;
30153ff48bf5SDavid du Colombier 	data	= htone->data;
30163ff48bf5SDavid du Colombier 	block	= htone->block;
30173ff48bf5SDavid du Colombier 
30183ff48bf5SDavid du Colombier 	lim1	= htone->mval / 2;
30193ff48bf5SDavid du Colombier 	lim2	= ( htone->mval + 256 ) / 2;
30203ff48bf5SDavid du Colombier 
30213ff48bf5SDavid du Colombier 	l0		= htone->err[ 0 ];
30223ff48bf5SDavid du Colombier 
30233ff48bf5SDavid du Colombier 	e0		= l0[ 1 ];
30243ff48bf5SDavid du Colombier 	e1		= l0[ 2 ];
30253ff48bf5SDavid du Colombier 
30263ff48bf5SDavid du Colombier 	l0[ 1 ] = 0;
30273ff48bf5SDavid du Colombier 	l0[ 2 ] = 0;
30283ff48bf5SDavid du Colombier 
30293ff48bf5SDavid du Colombier 	for ( x = 0 ; x < length ; x++ ) {
30303ff48bf5SDavid du Colombier 
30313ff48bf5SDavid du Colombier 		/* First, clear the res byte. It is needed for the black */
30323ff48bf5SDavid du Colombier 
30333ff48bf5SDavid du Colombier 		*res = 0;
30343ff48bf5SDavid du Colombier 
30353ff48bf5SDavid du Colombier 		/* Add the actual error to the pixel, normalise, init, whatever. */
30363ff48bf5SDavid du Colombier 
30373ff48bf5SDavid du Colombier 		pixel = ( ( *data << 4 ) + e0 );
30383ff48bf5SDavid du Colombier 		e0 = e1;
30393ff48bf5SDavid du Colombier 		e1 = l0[ 3 ] + ( pixel & 15 );			/* This is the residual */
30403ff48bf5SDavid du Colombier 
30413ff48bf5SDavid du Colombier 		l0[ 3 ] = 0;
30423ff48bf5SDavid du Colombier 		pixel >>= 4;
30433ff48bf5SDavid du Colombier 
30443ff48bf5SDavid du Colombier 		if ( ( block && *block ) || ( pixel < lim1 ) )
30453ff48bf5SDavid du Colombier 
30463ff48bf5SDavid du Colombier 			*res = 0;
30473ff48bf5SDavid du Colombier 
30483ff48bf5SDavid du Colombier 		else if ( pixel >= lim2 )
30493ff48bf5SDavid du Colombier 
30503ff48bf5SDavid du Colombier 			*res = 255;
30513ff48bf5SDavid du Colombier 		else
30523ff48bf5SDavid du Colombier 			*res = htone->mval;
30533ff48bf5SDavid du Colombier 
30543ff48bf5SDavid du Colombier 		/* Calculate the err */
30553ff48bf5SDavid du Colombier 
30563ff48bf5SDavid du Colombier 		pixerr = pixel - *res;
30573ff48bf5SDavid du Colombier 
30583ff48bf5SDavid du Colombier 		/* Diffuse the err */
30593ff48bf5SDavid du Colombier 
30603ff48bf5SDavid du Colombier 		e0		+= ( pixerr << 3 ) - pixerr;	/* 7/16		*/
30613ff48bf5SDavid du Colombier 		l0[ 0 ] += ( pixerr << 2 ) - pixerr;	/* 3/16		*/
30623ff48bf5SDavid du Colombier 		l0[ 1 ] += ( pixerr << 2 ) + pixerr;	/* 5/16		*/
30633ff48bf5SDavid du Colombier 		l0[ 2 ] += pixerr;						/* 1/16		*/
30643ff48bf5SDavid du Colombier 
30653ff48bf5SDavid du Colombier 		/* We have done everything, move the pointers */
30663ff48bf5SDavid du Colombier 
30673ff48bf5SDavid du Colombier 		res++;
30683ff48bf5SDavid du Colombier 		if ( block ) block++;
30693ff48bf5SDavid du Colombier 		data += htone->step;
30703ff48bf5SDavid du Colombier 		l0++;
30713ff48bf5SDavid du Colombier 	}
30723ff48bf5SDavid du Colombier }
30733ff48bf5SDavid du Colombier 
30743ff48bf5SDavid du Colombier /****************************************************************************/
30753ff48bf5SDavid du Colombier /*							Ordered dither									*/
30763ff48bf5SDavid du Colombier /****************************************************************************/
30773ff48bf5SDavid du Colombier 
30783ff48bf5SDavid du Colombier /*
30793ff48bf5SDavid du Colombier *	This function returns the empty range threshold
30803ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30813ff48bf5SDavid du Colombier */
30823ff48bf5SDavid du Colombier 
DitherThold(RENDER * p)30833ff48bf5SDavid du Colombier private	int		DitherThold( RENDER *p )
30843ff48bf5SDavid du Colombier {
30853ff48bf5SDavid du Colombier 	return( 0 );
30863ff48bf5SDavid du Colombier }
30873ff48bf5SDavid du Colombier 
30883ff48bf5SDavid du Colombier /*
30893ff48bf5SDavid du Colombier *	This function initialises the halftoner
30903ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30913ff48bf5SDavid du Colombier */
30923ff48bf5SDavid du Colombier 
DitherStart(RENDER * p,int line)30933ff48bf5SDavid du Colombier private	void	DitherStart( RENDER *p, int line )
30943ff48bf5SDavid du Colombier {
30953ff48bf5SDavid du Colombier 	/* Nothing to initialise */
30963ff48bf5SDavid du Colombier }
30973ff48bf5SDavid du Colombier 
30983ff48bf5SDavid du Colombier /*
30993ff48bf5SDavid du Colombier *	This function does the end-of-line processing
31003ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31013ff48bf5SDavid du Colombier */
31023ff48bf5SDavid du Colombier 
DitherEol(RENDER * p,int line)31033ff48bf5SDavid du Colombier private	void	DitherEol( RENDER *p, int line )
31043ff48bf5SDavid du Colombier {
31053ff48bf5SDavid du Colombier 	/* Nothing to do - dithering has no memory */
31063ff48bf5SDavid du Colombier }
31073ff48bf5SDavid du Colombier 
31083ff48bf5SDavid du Colombier /*
31093ff48bf5SDavid du Colombier *	Clustered dither of a particular colour of a line
31103ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31113ff48bf5SDavid du Colombier */
31123ff48bf5SDavid du Colombier 
DitherLine(HTONE * htone,int y)31133ff48bf5SDavid du Colombier private	void   DitherLine( HTONE *htone, int y )
31143ff48bf5SDavid du Colombier {
31153ff48bf5SDavid du Colombier int		x;							/* Counts the pixels					*/
31163ff48bf5SDavid du Colombier int		pixel;						/* Current pixel value					*/
31173ff48bf5SDavid du Colombier int		length;						/* Number of pixels to process			*/
31183ff48bf5SDavid du Colombier byte	*res;						/* Result								*/
31193ff48bf5SDavid du Colombier byte	*data;						/* Input data							*/
31203ff48bf5SDavid du Colombier byte	*block;						/* Block pixel							*/
31213ff48bf5SDavid du Colombier byte	*matrix;					/* Dither matrix's current line			*/
31223ff48bf5SDavid du Colombier int		mx;							/* Matrix index							*/
31233ff48bf5SDavid du Colombier int		lval, hval;					/* Halftoned high/low values			*/
31243ff48bf5SDavid du Colombier 
31253ff48bf5SDavid du Colombier 	length  = htone->render->width;
31263ff48bf5SDavid du Colombier 
31273ff48bf5SDavid du Colombier 	res		= htone->res;
31283ff48bf5SDavid du Colombier 	data	= htone->data;
31293ff48bf5SDavid du Colombier 	block	= htone->block;
31303ff48bf5SDavid du Colombier 
31313ff48bf5SDavid du Colombier 	matrix	= dmatrix[ y % DMATRIX_Y ];
31323ff48bf5SDavid du Colombier 
31333ff48bf5SDavid du Colombier 	for ( mx = x = 0 ; x < length ; x++ ) {
31343ff48bf5SDavid du Colombier 
31353ff48bf5SDavid du Colombier 		/* First, clear the res byte. It is needed for the black */
31363ff48bf5SDavid du Colombier 
31373ff48bf5SDavid du Colombier 		*res = 0;
31383ff48bf5SDavid du Colombier 
31393ff48bf5SDavid du Colombier 		/* Next, see if the pixel is above the mval */
31403ff48bf5SDavid du Colombier 
31413ff48bf5SDavid du Colombier 		if ( ( pixel = *data ) > htone->mval ) {
31423ff48bf5SDavid du Colombier 
31433ff48bf5SDavid du Colombier 			lval = htone->mval;
31443ff48bf5SDavid du Colombier 			hval = 255;
31453ff48bf5SDavid du Colombier 
31463ff48bf5SDavid du Colombier 			if ( htone->mval == 127 )
31473ff48bf5SDavid du Colombier 
31483ff48bf5SDavid du Colombier 				pixel = ( ( pixel - htone->mval ) * 2 - 1 ) / 2;
31493ff48bf5SDavid du Colombier 			else
31503ff48bf5SDavid du Colombier 				pixel = ( pixel - htone->mval ) * 255 / ( 255 - htone->mval );
31513ff48bf5SDavid du Colombier 		}
31523ff48bf5SDavid du Colombier 		else {
31533ff48bf5SDavid du Colombier 
31543ff48bf5SDavid du Colombier 			lval = 0;
31553ff48bf5SDavid du Colombier 			hval = htone->mval;
31563ff48bf5SDavid du Colombier 
31573ff48bf5SDavid du Colombier 			if ( htone->mval != 255 ) {
31583ff48bf5SDavid du Colombier 
31593ff48bf5SDavid du Colombier 				if ( htone->mval == 127 )
31603ff48bf5SDavid du Colombier 
31613ff48bf5SDavid du Colombier 					pixel = ( pixel * 4 + 1 ) / 2;
31623ff48bf5SDavid du Colombier 				else
31633ff48bf5SDavid du Colombier 					pixel = pixel * 255 / htone->mval;
31643ff48bf5SDavid du Colombier 			}
31653ff48bf5SDavid du Colombier 		}
31663ff48bf5SDavid du Colombier 
31673ff48bf5SDavid du Colombier 		if ( block && *block ) {
31683ff48bf5SDavid du Colombier 
31693ff48bf5SDavid du Colombier 			*res = 0;
31703ff48bf5SDavid du Colombier 		}
31713ff48bf5SDavid du Colombier 		else {
31723ff48bf5SDavid du Colombier 
31733ff48bf5SDavid du Colombier 			if ( pixel >= matrix[ mx ] )
31743ff48bf5SDavid du Colombier 
31753ff48bf5SDavid du Colombier 				*res = hval;
31763ff48bf5SDavid du Colombier 			else
31773ff48bf5SDavid du Colombier 				*res = lval;
31783ff48bf5SDavid du Colombier 		}
31793ff48bf5SDavid du Colombier 
31803ff48bf5SDavid du Colombier 		res++;
31813ff48bf5SDavid du Colombier 		if ( ++mx == DMATRIX_X ) mx = 0;
31823ff48bf5SDavid du Colombier 		if ( block ) block++;
31833ff48bf5SDavid du Colombier 		data += htone->step;
31843ff48bf5SDavid du Colombier 	}
31853ff48bf5SDavid du Colombier }
31863ff48bf5SDavid du Colombier 
31873ff48bf5SDavid du Colombier /****************************************************************************/
31883ff48bf5SDavid du Colombier /*					Bendor's error diffusion								*/
31893ff48bf5SDavid du Colombier /****************************************************************************/
31903ff48bf5SDavid du Colombier 
31913ff48bf5SDavid du Colombier /*
31923ff48bf5SDavid du Colombier *	This function returns the empty range threshold
31933ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31943ff48bf5SDavid du Colombier */
31953ff48bf5SDavid du Colombier 
BendorThold(RENDER * p)31963ff48bf5SDavid du Colombier private	int		BendorThold( RENDER *p )
31973ff48bf5SDavid du Colombier {
31983ff48bf5SDavid du Colombier 	return( 5 );
31993ff48bf5SDavid du Colombier }
32003ff48bf5SDavid du Colombier 
32013ff48bf5SDavid du Colombier /*
32023ff48bf5SDavid du Colombier *	This function initialises the halftoner
32033ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32043ff48bf5SDavid du Colombier */
32053ff48bf5SDavid du Colombier 
BendorStart(RENDER * p,int line)32063ff48bf5SDavid du Colombier private	void	BendorStart( RENDER *p, int line )
32073ff48bf5SDavid du Colombier {
32083ff48bf5SDavid du Colombier 	memset( p->err, 0, 2 * ICOLN * MAX_PIXELS*2 );
32093ff48bf5SDavid du Colombier 	p->error[ 0 ] = p->err[ 0 ];
32103ff48bf5SDavid du Colombier 	p->error[ 1 ] = p->err[ 1 ];
32113ff48bf5SDavid du Colombier }
32123ff48bf5SDavid du Colombier 
32133ff48bf5SDavid du Colombier /*
32143ff48bf5SDavid du Colombier *	This function does the end-of-line processing
32153ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32163ff48bf5SDavid du Colombier */
32173ff48bf5SDavid du Colombier 
BendorEol(RENDER * p,int line)32183ff48bf5SDavid du Colombier private	void	BendorEol( RENDER *p, int line )
32193ff48bf5SDavid du Colombier {
32203ff48bf5SDavid du Colombier void	*x;
32213ff48bf5SDavid du Colombier 
32223ff48bf5SDavid du Colombier 	x = p->error[ 0 ];
32233ff48bf5SDavid du Colombier 	p->error[ 0 ] = p->error[ 1 ];
32243ff48bf5SDavid du Colombier 	p->error[ 1 ] = x;
32253ff48bf5SDavid du Colombier }
32263ff48bf5SDavid du Colombier 
32273ff48bf5SDavid du Colombier /*
32283ff48bf5SDavid du Colombier *	Error diffusion of a particular colour of a line
32293ff48bf5SDavid du Colombier *	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32303ff48bf5SDavid du Colombier *
32313ff48bf5SDavid du Colombier *	This is not yet finished (the matrix is bad, actually).
32323ff48bf5SDavid du Colombier *
32333ff48bf5SDavid du Colombier *	The matrix is the following (the normalisation factor is 1/128,
32343ff48bf5SDavid du Colombier *	'*' represents the current pixel, r is the truncation residual):
32353ff48bf5SDavid du Colombier *
32363ff48bf5SDavid du Colombier *				 *	20	10  r
32373ff48bf5SDavid du Colombier *		8	14	20	14	 8
32383ff48bf5SDavid du Colombier *		4	 8	10	 8	 4
32393ff48bf5SDavid du Colombier *
32403ff48bf5SDavid du Colombier *	We also try to take the splashing effect into account (the ink disperses
32413ff48bf5SDavid du Colombier *	when it hits the paper so it partially covers surrounding pixels).
32423ff48bf5SDavid du Colombier *	We use an other matrix for that, which is very simple:
32433ff48bf5SDavid du Colombier *
32443ff48bf5SDavid du Colombier *			*	3
32453ff48bf5SDavid du Colombier *		2	3	2
32463ff48bf5SDavid du Colombier *
32473ff48bf5SDavid du Colombier *	and the normalisation factor can be set by the user.
32483ff48bf5SDavid du Colombier *	The splash matrix is only applied if we have actually deposited
32493ff48bf5SDavid du Colombier *	ink and the amount added to the errors is independent that of the
32503ff48bf5SDavid du Colombier *	actual image value, it only depends on the ink applied.
32513ff48bf5SDavid du Colombier *	Of course, the ink spreads up and left as well and we could compensate
32523ff48bf5SDavid du Colombier *	for this for a certain extent by keeping track of the errors caused in
32533ff48bf5SDavid du Colombier *	previous pixels and lines and modifying them accordingly but it
32543ff48bf5SDavid du Colombier *	would lead to a horrible code mess and it wouldn't be worth the effort.
32553ff48bf5SDavid du Colombier *
32563ff48bf5SDavid du Colombier *	A further enhancement that we allow the error to 'leak'. Experimental
32573ff48bf5SDavid du Colombier *	results show that with a 5-15% loss of error the image quality
32583ff48bf5SDavid du Colombier *	increases and the colour distortion remains very low. If you think
32593ff48bf5SDavid du Colombier *	about it, this, in effect stops the error to spread its effect over
32603ff48bf5SDavid du Colombier *	large areas but it will have almost undisturbed effect on neighbouring
32613ff48bf5SDavid du Colombier *	areas (you allow for an exponential error decay).
32623ff48bf5SDavid du Colombier *	This parameter is user definable, too.
32633ff48bf5SDavid du Colombier */
32643ff48bf5SDavid du Colombier 
BendorLine(HTONE * htone,int y)32653ff48bf5SDavid du Colombier private	void   BendorLine( HTONE *htone, int y )
32663ff48bf5SDavid du Colombier {
32673ff48bf5SDavid du Colombier int		x;							/* Counts the pixels					*/
32683ff48bf5SDavid du Colombier int		pixel;						/* Current pixel value					*/
32693ff48bf5SDavid du Colombier int		pixerr;						/* Error value							*/
32703ff48bf5SDavid du Colombier int		pixe14;						/* 14 * err value						*/
32713ff48bf5SDavid du Colombier int		sval;						/* Splash correction value				*/
32723ff48bf5SDavid du Colombier int		splash;						/* Splash factor						*/
32733ff48bf5SDavid du Colombier int		leakage;					/* Leakage factor						*/
32743ff48bf5SDavid du Colombier int		length;						/* Number of pixels to process			*/
32753ff48bf5SDavid du Colombier byte	*res;						/* Result								*/
32763ff48bf5SDavid du Colombier byte	*data;						/* Input data							*/
32773ff48bf5SDavid du Colombier byte	*block;						/* Block pixel							*/
32783ff48bf5SDavid du Colombier int		lim1, lim2;					/* Limits								*/
32793ff48bf5SDavid du Colombier short	e0, e1;						/* Propagating errors in current line	*/
32803ff48bf5SDavid du Colombier short	*l0, *l1;					/* Error buffer pointers				*/
32813ff48bf5SDavid du Colombier 
32823ff48bf5SDavid du Colombier 	splash  = htone->render->dev->splash;
32833ff48bf5SDavid du Colombier 	leakage = htone->render->dev->splash;
32843ff48bf5SDavid du Colombier 	length  = htone->render->width;
32853ff48bf5SDavid du Colombier 
32863ff48bf5SDavid du Colombier 	res		= htone->res;
32873ff48bf5SDavid du Colombier 	data	= htone->data;
32883ff48bf5SDavid du Colombier 	block	= htone->block;
32893ff48bf5SDavid du Colombier 
32903ff48bf5SDavid du Colombier 	lim1	= htone->mval / 2;
32913ff48bf5SDavid du Colombier 	lim2	= ( htone->mval + 256 ) / 2;
32923ff48bf5SDavid du Colombier 
32933ff48bf5SDavid du Colombier 	l0		= htone->err[ 0 ];
32943ff48bf5SDavid du Colombier 	l1		= htone->err[ 1 ];
32953ff48bf5SDavid du Colombier 
32963ff48bf5SDavid du Colombier 	e0		= l0[ 2 ];
32973ff48bf5SDavid du Colombier 	e1		= l0[ 3 ];
32983ff48bf5SDavid du Colombier 
32993ff48bf5SDavid du Colombier 	l0[ 2 ] = 0;
33003ff48bf5SDavid du Colombier 	l0[ 3 ] = 0;
33013ff48bf5SDavid du Colombier 
33023ff48bf5SDavid du Colombier 	for ( x = 0 ; x < length ; x++ ) {
33033ff48bf5SDavid du Colombier 
33043ff48bf5SDavid du Colombier 		/* First, clear the res byte. It is needed for the black */
33053ff48bf5SDavid du Colombier 
33063ff48bf5SDavid du Colombier 		*res = 0;
33073ff48bf5SDavid du Colombier 
33083ff48bf5SDavid du Colombier 		/* Add the actual error to the pixel, normalise, init, whatever. */
33093ff48bf5SDavid du Colombier 
33103ff48bf5SDavid du Colombier 		pixel = ( ( *data << 7 ) + e0 );
33113ff48bf5SDavid du Colombier 		e0 = e1;
33123ff48bf5SDavid du Colombier 		e1 = l0[ 4 ] + ( pixel & 127 );			/* This is the residual */
33133ff48bf5SDavid du Colombier 
33143ff48bf5SDavid du Colombier 		l0[ 4 ] = 0;
33153ff48bf5SDavid du Colombier 		pixel >>= 7;
33163ff48bf5SDavid du Colombier 
33173ff48bf5SDavid du Colombier 		if ( ( block && *block ) || ( pixel < lim1 ) )
33183ff48bf5SDavid du Colombier 
33193ff48bf5SDavid du Colombier 			*res = 0;
33203ff48bf5SDavid du Colombier 
33213ff48bf5SDavid du Colombier 		else if ( pixel >= lim2 )
33223ff48bf5SDavid du Colombier 
33233ff48bf5SDavid du Colombier 			*res = 255;
33243ff48bf5SDavid du Colombier 		else
33253ff48bf5SDavid du Colombier 			*res = htone->mval;
33263ff48bf5SDavid du Colombier 
33273ff48bf5SDavid du Colombier 		/* Calculate the err */
33283ff48bf5SDavid du Colombier 
33293ff48bf5SDavid du Colombier 		pixerr = pixel - *res;
33303ff48bf5SDavid du Colombier 
33313ff48bf5SDavid du Colombier 		/* If leakage is defined, apply it */
33323ff48bf5SDavid du Colombier 
33333ff48bf5SDavid du Colombier 		if ( leakage ) pixerr -= ( pixerr * leakage ) / 100;
33343ff48bf5SDavid du Colombier 
33353ff48bf5SDavid du Colombier 		/* Diffuse the err */
33363ff48bf5SDavid du Colombier 
33373ff48bf5SDavid du Colombier 		pixerr <<= 1;							/* Multiplier is 2	*/
33383ff48bf5SDavid du Colombier 		pixe14 = pixerr;						/* pixe14 now 2		*/
33393ff48bf5SDavid du Colombier 		pixerr <<= 1;							/* Multiplier is 4	*/
33403ff48bf5SDavid du Colombier 		pixe14 += pixerr;						/* pixe14 now 6		*/
33413ff48bf5SDavid du Colombier 
33423ff48bf5SDavid du Colombier 		l0[ 0 ] += pixerr;
33433ff48bf5SDavid du Colombier 		l0[ 4 ] += pixerr;
33443ff48bf5SDavid du Colombier 
33453ff48bf5SDavid du Colombier 		pixerr <<= 1;							/* Multiplier is 8	*/
33463ff48bf5SDavid du Colombier 		pixe14 += pixerr;						/* pixe14 now 14	*/
33473ff48bf5SDavid du Colombier 
33483ff48bf5SDavid du Colombier 		l0[ 1 ] += pixerr;
33493ff48bf5SDavid du Colombier 		l0[ 3 ] += pixerr;
33503ff48bf5SDavid du Colombier 		l1[ 0 ] += pixerr;
33513ff48bf5SDavid du Colombier 		l1[ 4 ] += pixerr;
33523ff48bf5SDavid du Colombier 
33533ff48bf5SDavid du Colombier 		pixerr += pixerr >> 2;					/* Multiplier is 10	*/
33543ff48bf5SDavid du Colombier 
33553ff48bf5SDavid du Colombier 		l0[ 2 ] += pixerr;
33563ff48bf5SDavid du Colombier 		e1		+= pixerr;
33573ff48bf5SDavid du Colombier 
33583ff48bf5SDavid du Colombier 		pixerr <<= 1;							/* Multiplier is 20 */
33593ff48bf5SDavid du Colombier 
33603ff48bf5SDavid du Colombier 		l1[ 2 ] += pixerr;
33613ff48bf5SDavid du Colombier 		e0		+= pixerr;
33623ff48bf5SDavid du Colombier 
33633ff48bf5SDavid du Colombier 		/* pixe14 already contains 14 * err */
33643ff48bf5SDavid du Colombier 
33653ff48bf5SDavid du Colombier 		l1[ 1 ] += pixe14;
33663ff48bf5SDavid du Colombier 		l1[ 3 ] += pixe14;
33673ff48bf5SDavid du Colombier 
33683ff48bf5SDavid du Colombier 		/* If splashing is defined, apply the splash matrix.
33693ff48bf5SDavid du Colombier 		   The splash value is normalised to the same level as the err */
33703ff48bf5SDavid du Colombier 
33713ff48bf5SDavid du Colombier 		if ( splash && *res ) {
33723ff48bf5SDavid du Colombier 
33733ff48bf5SDavid du Colombier 			sval = splash * *res;				/* This is the 2x value	*/
33743ff48bf5SDavid du Colombier 
33753ff48bf5SDavid du Colombier 			l1[ 1 ] -= sval;
33763ff48bf5SDavid du Colombier 			l1[ 3 ] -= sval;
33773ff48bf5SDavid du Colombier 
33783ff48bf5SDavid du Colombier 			sval += sval >> 1;					/* This represents 3x	*/
33793ff48bf5SDavid du Colombier 
33803ff48bf5SDavid du Colombier 			e0		-= sval;
33813ff48bf5SDavid du Colombier 			l1[ 2 ] -= sval;
33823ff48bf5SDavid du Colombier 		}
33833ff48bf5SDavid du Colombier 
33843ff48bf5SDavid du Colombier 		/* We have done everything, move the pointers */
33853ff48bf5SDavid du Colombier 
33863ff48bf5SDavid du Colombier 		res++;
33873ff48bf5SDavid du Colombier 		if ( block ) block++;
33883ff48bf5SDavid du Colombier 		data += htone->step;
33893ff48bf5SDavid du Colombier 		l0++, l1++;
33903ff48bf5SDavid du Colombier 	}
33913ff48bf5SDavid du Colombier }
3392