1 /* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevstc4.c,v 1.4 2002/02/21 22:24:52 giles Exp $*/
18 /* Epson Stylus-Color Printer-Driver */
19
20 /***
21 This file holds a byte-Implementation of the Floyd-Steinberg error
22 diffusion-algorithm. This algorithm is an alternative for high quality
23 printing in conjunction with the PostScript-Header stcolor.ps:
24
25 gs -sDEVICE=stcolor -sDithering=fs2 <other options> stcolor.ps ...
26
27 THIS ALGORIHM WAS WRITTEN BY STEVEN SINGER (S.Singer@ph.surrey.ac.uk)
28 AS PART OF escp2cfs2.
29 THIS IMPLEMENTATION INCORPORATES ONLY FEW CHANGES TO THE ORIGINAL CODE.
30
31 ***/
32
33 #include "gdevstc.h"
34
35 /*
36 * escp2c_pick best scans for best matching color
37 */
38 private byte *
escp2c_pick_best(byte * col)39 escp2c_pick_best(byte *col)
40 {
41 static byte colour[8][3] = {
42 { 0, 0, 0},{255, 0, 0},{ 0,255, 0},{255,255, 0},
43 { 0, 0,255},{255, 0,255},{ 0,255,255},{255,255,255}};
44 register int x, y, z, dx, dy, dz, dz2, dx2, dx3, dx4;
45 register byte *p;
46 register long md, d;
47
48 md = 16777216; /* plenty */
49
50 /*
51 Note that I don't use a simple distance algorithm. That can lead to a block
52 of (130,127,127) being dithered as red-cyan. This algorithm should make
53 it use black-white-red. This is very important, as a coloured block in
54 the middle of a grey block can, via error diffusion, perturb the
55 surrounding colours sufficiently for this to happen.
56 */
57
58 /*
59 The next bit is equivalent to this, but faster.
60
61 x = col[0];
62 y = col[1];
63 z = col[2];
64 for(n=8; n--; )
65 {
66 dx = x - colour[n][0];
67 dy = y - colour[n][1];
68 dz = z - colour[n][2];
69 d = dx*(dx-(dy>>1)) + dy*(dy-(dz>>1)) + dz*(dz-(dx>>1));
70 if (d < md)
71 {
72 md = d;
73 p = n;
74 }
75 }
76 */
77
78 /*
79 * Test colours in gray code order to reduce number of recalculations.
80 * I bet you can't find an optimiser that would do this automatically.
81 */
82
83 x = col[0];
84 y = col[1];
85 z = col[2];
86 dx = x*(x-(y>>1));
87 dy = y*(y-(z>>1));
88 dz = z*(z-(x>>1));
89 md = dx + dy + dz;
90 p = colour[0];
91 x -= 255;
92 dx2 = x*(x-(y>>1));
93 dz2 = z*(z-(x>>1));
94 if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[1];}
95 y -= 255;
96 dx3 = x*(x-(y>>1));
97 dy = y*(y-(z>>1));
98 if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[3];}
99 x += 255;
100 dx4 = x*(x-(y>>1));
101 if ((d = dx4 + dy + dz) < md) {md = d; p = colour[2];}
102 z -= 255;
103 dy = y*(y-(z>>1));
104 dz = z*(z-(x>>1));
105 if ((d = dx4 + dy + dz) < md) {md = d; p = colour[6];}
106 x -= 255;
107 dz2 = z*(z-(x>>1));
108 if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[7];}
109 y += 255;
110 dy = y*(y-(z>>1));
111 if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[5];}
112 if ((d = dx + dy + dz) < md) {p = colour[4];}
113 return(p);
114 }
115
116 /*
117 * escp2c_conv_stc converts into the ouput format used by stcolor
118 */
119 private void
escp2c_conv_stc(byte * p,byte * q,int i)120 escp2c_conv_stc(byte *p, byte *q, int i)
121 {
122 for(; i; p+=3, i-=3)
123 *q++ = (*p & RED) | (p[1] & GREEN) | (p[2] & BLUE);
124 }
125
126
127 /*
128 * Limit byte-values
129 */
130 #define LIMIT(a) if (a > 255) a = 255; if (a < 0) a = 0
131 #define LIMIT2(a) if (a > 127) a = 127; if (a < -128) a = -128; \
132 if (a < 0) a += 256
133 /*
134 * Main routine of the algorithm
135 */
136 int
stc_fs2(stcolor_device * sd,int npixel,byte * in,byte * buf,byte * out)137 stc_fs2(stcolor_device *sd,int npixel,byte *in,byte *buf,byte *out)
138 {
139 int fullcolor_line_size = npixel*3;
140
141 /* ============================================================= */
142 if(npixel > 0) { /* npixel > 0 -> scanline-processing */
143 /* ============================================================= */
144
145 /* -------------------------------------------------------------------- */
146 if(in == NULL) { /* clear the error-buffer upon white-lines */
147 /* -------------------------------------------------------------------- */
148
149 memset(buf,0,fullcolor_line_size);
150
151 /* ------------------------------------------------------------------- */
152 } else { /* do the actual dithering */
153 /* ------------------------------------------------------------------- */
154 int i, j, k, e, l, i2, below[3][3], *fb, *b, *bb, *tb;
155 byte *p, *q, *cp;
156 static int dir = 1;
157
158 p = buf;
159 if (*p != 0 || memcmp((char *) p, (char *) p + 1, fullcolor_line_size - 1))
160 {
161 for(p = in, q=buf, i=fullcolor_line_size;
162 i--; p++, q++ )
163 {
164 j = *p + ((*q & 128) ? *q - 256 : *q);
165 LIMIT(j);
166 *p = j;
167 }
168 }
169
170 p = in;
171
172 fb = below[2];
173 b = below[1];
174 bb = below[0];
175 *b = b[1] = b[2] = *bb = bb[1] = bb[2] = 0;
176
177 if (dir)
178 {
179 for(p = in, q=buf-3,
180 i=fullcolor_line_size; i; i-=3)
181 {
182 cp = escp2c_pick_best(p);
183 for(i2=3; i2--; p++, q++, fb++, b++, bb++)
184 {
185 j = *p;
186 *p = *cp++;
187 j -= *p;
188 if (j != 0)
189 {
190 l = (e = (j>>1)) - (*fb = (j>>4));
191 if (i > 2)
192 {
193 k = p[3] + l;
194 LIMIT(k);
195 p[3] = k;
196 }
197 *b += e - (l = (j>>2) - *fb);
198 if (i < fullcolor_line_size)
199 {
200 l += *bb;
201 LIMIT2(l);
202 *q = l;
203 }
204 }
205 else
206 *fb = 0;
207 }
208 tb = bb-3;
209 bb = b-3;
210 b = fb-3;
211 fb = tb;
212 }
213 *q = *bb;
214 q[1] = bb[1];
215 q[2] = bb[2];
216 dir = 0;
217 }
218 else
219 {
220 for(p = in+fullcolor_line_size-1,
221 q = buf+fullcolor_line_size+2, i=fullcolor_line_size;
222 i; i-=3)
223 {
224 cp = escp2c_pick_best(p-2) + 2;
225 for(i2=3; i2--; p--, q--, fb++, b++, bb++)
226 {
227 j = *p;
228 *p = *cp--;
229 j -= *p;
230 if (j != 0)
231 {
232 l = (e = (j>>1)) - (*fb = (j>>4));
233 if (i > 2)
234 {
235 k = p[-3] + l;
236 LIMIT(k);
237 p[-3] = k;
238 }
239 *b += e - (l = (j>>2) - *fb);
240 if (i < fullcolor_line_size)
241 {
242 l += *bb;
243 LIMIT2(l);
244 *q = l;
245 }
246 }
247 else
248 *fb = 0;
249 }
250 tb = bb-3;
251 bb = b-3;
252 b = fb-3;
253 fb = tb;
254 }
255 *q = *bb;
256 q[1] = bb[1];
257 q[2] = bb[2];
258 dir = 1;
259 }
260
261 escp2c_conv_stc(in, out, fullcolor_line_size);
262
263 /* ------------------------------------------------------------------- */
264 } /* buffer-reset | dithering */
265 /* ------------------------------------------------------------------- */
266
267
268 /* ============================================================= */
269 } else { /* npixel <= 0 -> initialisation */
270 /* ============================================================= */
271
272
273 /*
274 * check wether the number of components is valid
275 */
276 if(sd->color_info.num_components != 3) return -1;
277
278 /*
279 * check wether stcdither & TYPE are correct
280 */
281 if(( sd->stc.dither == NULL) ||
282 ((sd->stc.dither->flags & STC_TYPE) != STC_BYTE)) return -2;
283
284 /*
285 * check wether the buffer-size is sufficiently large
286 */
287 if((sd->stc.dither->flags/STC_SCAN) < 1) return -3;
288
289 /*
290 * finally clear the buffer
291 */
292 memset(buf,0,-fullcolor_line_size);
293
294 /* ============================================================= */
295 } /* scanline-processing or initialisation */
296 /* ============================================================= */
297
298 return 0;
299 }
300