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