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