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