1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Epson Stylus-Color Printer-Driver */
18
19 /***
20 This file holds two implementations of the Floyd-Steinberg error
21 diffusion-algorithm. This algorithms are intended for high quality
22 printing in conjunction with the PostScript-Header stcolor.ps:
23
24 gs -sDEVICE=stcolor <other options> stcolor.ps ...
25
26 Most prominent option is -sDithering=xxx, to select the algorithm:
27
28 fsmono - monochrome Floyd-Steinberg
29 fsrgb - 3-Component Floyd-Steinberg
30 fsx4 - 4-Component Floyd-Steinberg (Bad results)
31
32 fscmyk - Modified 4-Component Floyd-Steinberg
33 (Algorithmically identical with hscmyk, but slower)
34
35 ***/
36
37 #include "gdevstc.h"
38
39 #include <stdlib.h> /* for rand */
40
41 /*
42 Both algorithms require an error-buffer of
43
44 3 + 3*num_components +1*scan long-items.
45
46 and must consequently set up to work with longs.
47 It is just a Floyd-Steinberg-algorithm applied to each component.
48
49 */
50
51 /*
52 * Due to the -selfdefined- ugly coding of the output-data, we need
53 * some conversion. But since this includes the black-separation, I
54 * did not change the definition.
55 *
56 * This algorithm stores the 1st component in the LSB, thus it
57 * reverts the order used by the basic driver.
58 */
59
60 static const byte grayvals[2] = { 0, BLACK };
61
62 static const byte rgbvals[8] = {
63 0, RED, GREEN, RED|GREEN, BLUE, BLUE|RED, BLUE|GREEN, BLUE|RED|GREEN};
64
65 static const byte cmykvals[16] = {
66 0, CYAN,MAGENTA,CYAN|MAGENTA,YELLOW,YELLOW|CYAN,YELLOW|MAGENTA,BLACK,
67 BLACK,BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,BLACK};
68
69 static const byte *const pixelconversion[5] = {
70 NULL, grayvals, NULL, rgbvals, cmykvals};
71
72 int
stc_fs(stcolor_device * sdev,int npixel,byte * bin,byte * bbuf,byte * out)73 stc_fs(stcolor_device *sdev,int npixel,byte *bin,byte *bbuf,byte *out)
74 {
75
76 long *in = (long *) bin;
77 long *buf = (long *) bbuf;
78
79 /* ============================================================= */
80 if(npixel > 0) { /* npixel > 0 -> scanline-processing */
81 /* ============================================================= */
82
83 int bstep,pstart,pstop,pstep,p;
84 long spotsize,threshold,*errc,*errv;
85 const byte *pixel2stc;
86
87 if(buf[0] >= 0) { /* run forward */
88 buf[0] = -1;
89 bstep = 1;
90 pstep = sdev->color_info.num_components;
91 pstart = 0;
92 pstop = npixel * pstep;
93
94 } else { /* run backward */
95 buf[0] = 1;
96 bstep = -1;
97 pstep = -sdev->color_info.num_components;
98 pstop = pstep;
99 pstart = (1-npixel) * pstep;
100 out += npixel-1;
101 } /* forward / backward */
102
103 /* --------------------------------------------------------------------- */
104 if(in == NULL) return 0; /* almost ignore the 'white calls' */
105 /* --------------------------------------------------------------------- */
106
107 spotsize = buf[1];
108 threshold = buf[2];
109 errc = buf+3;
110 errv = errc + 2*sdev->color_info.num_components;
111 pixel2stc = pixelconversion[sdev->color_info.num_components];
112
113 for(p = pstart; p != pstop; p += pstep) { /* loop over pixels */
114 int c; /* component-number */
115 int pixel; /* internal pxel-value */
116
117 pixel = 0;
118
119 for(c = 0; c < sdev->color_info.num_components; c++) { /* comp */
120 long cv; /* component value */
121
122 cv = in[p+c] + errv[p+c] + errc[c] - ((errc[c]+4)>>3);
123 if(cv > threshold) {
124 pixel |= 1<<c;
125 cv -= spotsize;
126 }
127 errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
128 errv[p+c ] = ((5*cv )>>4) /* 5/16 */
129 + ((errc[c]+4)>>3); /* 1/16 (rest) */
130 errc[c] = cv /* 8/16 (neu) */
131 - ((5*cv )>>4)
132 - ((3*cv+8)>>4);
133 } /* comp */
134
135 *out = pixel2stc[pixel];
136 out += bstep;
137 } /* loop over pixels */
138
139 /* ============================================================= */
140 } else { /* npixel <= 0 -> initialisation */
141 /* ============================================================= */
142
143 int i,i2do;
144 long rand_max;
145 double offset,scale;
146
147 /*
148 * check wether the number of components is valid
149 */
150 if((sdev->color_info.num_components < 0) ||
151 (sdev->color_info.num_components >= countof(pixelconversion)) ||
152 (pixelconversion[sdev->color_info.num_components] == NULL)) return -1;
153
154 /*
155 * check wether stcdither & TYPE are correct
156 */
157 if(( sdev->stc.dither == NULL) ||
158 ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
159
160 /*
161 * check wether the buffer-size is sufficiently large
162 */
163 if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
164 ( sdev->stc.dither->bufadd <
165 (3 + 3*sdev->color_info.num_components))) return -3;
166 /*
167 * must neither have STC_DIRECT nor STC_WHITE
168 */
169 if(sdev->stc.dither->flags & (STC_DIRECT | STC_WHITE)) return -4;
170
171 /*
172 * compute initial values
173 */
174 /* -- direction */
175 buf[0] = 1;
176
177 /* -- "spotsize" */
178 scale = sdev->stc.dither->minmax[1];
179 buf[1] = (long)(scale + (scale > 0.0 ? 0.5 : -0.5));
180
181 /* -- "threshold" */
182 offset = sdev->stc.dither->minmax[0];
183 scale -= offset;
184 if((offset+0.5*scale) > 0.0) buf[2] = (long)(offset + 0.5*scale + 0.5);
185 else buf[2] = (long)(offset + 0.5*scale - 0.5);
186
187 /*
188 * random values, that do not exceed half of normal value
189 */
190 i2do = sdev->color_info.num_components * (3-npixel);
191 rand_max = 0;
192
193 if(sdev->stc.flags & STCDFLAG0) {
194
195 for(i = 0; i < i2do; ++i) buf[i+3] = 0;
196
197 } else {
198
199 for(i = 0; i < i2do; ++i) {
200 buf[i+3] = rand();
201 if(buf[i+3] > rand_max) rand_max = buf[i+3];
202 }
203
204 scale = (double) buf[1] / (double) rand_max;
205
206 for(i = 0; i < sdev->color_info.num_components; ++ i)
207 buf[i+3] = (long)(0.25000*scale*(buf[i+3]-rand_max/2));
208
209 for( ; i < i2do; ++i) /* includes 2 additional pixels ! */
210 buf[i+3] = (long)(0.28125*scale*(buf[i+3]-rand_max/2));
211
212 }
213
214 /* ============================================================= */
215 } /* scanline-processing or initialisation */
216 /* ============================================================= */
217
218 return 0;
219 }
220
221 /*
222 * Experimental CMYK-Algorithm
223 */
224
225 int
stc_fscmyk(stcolor_device * sdev,int npixel,byte * bin,byte * bbuf,byte * out)226 stc_fscmyk(stcolor_device *sdev,int npixel,byte *bin,byte *bbuf,byte *out)
227 {
228 long *in = (long *) bin;
229 long *buf = (long *) bbuf;
230
231 /* ============================================================= */
232 if(npixel > 0) { /* npixel > 0 -> scanline-processing */
233 /* ============================================================= */
234
235 int bstep,pstart,pstop,pstep,p;
236 long spotsize,threshold,*errc,*errv;
237
238 if(buf[0] >= 0) { /* run forward */
239 buf[0] = -1;
240 bstep = 1;
241 pstep = 4;
242 pstart = 0;
243 pstop = npixel * pstep;
244
245 } else { /* run backward */
246 buf[0] = 1;
247 bstep = -1;
248 pstep = -4;
249 pstop = pstep;
250 pstart = (1-npixel) * pstep;
251 out += npixel-1;
252 } /* forward / backward */
253
254 spotsize = buf[1];
255 threshold = buf[2];
256 errc = buf+3;
257 errv = errc + 2*4;
258
259 for(p = 0; p < 4; ++p) errc[p] = 0;
260
261 for(p = pstart; p != pstop; p += pstep) { /* loop over pixels */
262 int c; /* component-number */
263 int pixel; /* internal pxel-value */
264 long cv,k;
265
266 /*
267 * Black is treated first, with conventional Floyd-Steinberg
268 */
269 k = in[p+3];
270 cv = k + errv[p+3] + errc[3] - ((errc[3]+4)>>3);
271
272 if(cv > threshold) {
273 pixel = BLACK;
274 cv -= spotsize;
275 } else {
276 pixel = 0;
277 }
278
279 errv[p+3-pstep] += ((3*cv+8)>>4); /* 3/16 */
280 errv[p+3 ] = ((5*cv )>>4) /* 5/16 */
281 + ((errc[3]+4)>>3); /* 1/16 (rest) */
282 errc[3] = cv /* 8/16 (neu) */
283 - ((5*cv )>>4)
284 - ((3*cv+8)>>4);
285
286 /*
287 * color-handling changes with black fired or not
288 */
289 if(pixel) {
290
291 /* -------- firing of black causes all colors to fire too */
292
293 for(c = 0; c < 3; ++c) {
294 cv = in[p+c] > k ? in[p+c] : k;
295 cv += errv[p+c] + errc[c] - ((errc[c]+4)>>3)-spotsize;
296 if(cv <= (threshold-spotsize)) cv = threshold-spotsize+1;
297
298 errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
299 errv[p+c ] = ((5*cv )>>4) /* 5/16 */
300 + ((errc[c]+4)>>3); /* 1/16 (rest) */
301 errc[c] = cv /* 8/16 (neu) */
302 - ((5*cv )>>4)
303 - ((3*cv+8)>>4);
304 }
305
306 } else {
307
308 /* -------- if black did not fire, only colors w. larger values may fire */
309
310 for(c = 0; c < 3; ++c) {
311
312 cv = in[p+c];
313
314 if(cv > k) { /* May Fire */
315 cv += errv[p+c] + errc[c] - ((errc[c]+4)>>3);
316 if(cv > threshold) {
317 cv -= spotsize;
318 pixel |= CYAN>>c;
319 }
320 } else { /* Must not fire */
321 cv = k + errv[p+c] + errc[c] - ((errc[c]+4)>>3);
322 if(cv > threshold ) cv = threshold;
323 }
324
325 errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
326 errv[p+c ] = ((5*cv )>>4) /* 5/16 */
327 + ((errc[c]+4)>>3); /* 1/16 (rest) */
328 errc[c] = cv /* 8/16 (neu) */
329 - ((5*cv )>>4)
330 - ((3*cv+8)>>4);
331 }
332 }
333
334 *out = pixel;
335 out += bstep;
336 } /* loop over pixels */
337
338 /* ============================================================= */
339 } else { /* npixel <= 0 -> initialisation */
340 /* ============================================================= */
341
342 int i,i2do;
343 long rand_max;
344 double offset,scale;
345
346 /*
347 * check wether the number of components is valid
348 */
349 if(sdev->color_info.num_components != 4) return -1;
350
351 /*
352 * check wether stcdither & TYPE are correct
353 */
354 if(( sdev->stc.dither == NULL) ||
355 ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
356
357 /*
358 * check wether the buffer-size is sufficiently large
359 */
360 if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
361 ( sdev->stc.dither->bufadd <
362 (3 + 3*sdev->color_info.num_components))) return -3;
363 /*
364 * must neither have STC_DIRECT nor STC_WHITE
365 */
366 if(sdev->stc.dither->flags & (STC_DIRECT | STC_WHITE)) return -4;
367
368 /*
369 * compute initial values
370 */
371 /* -- direction */
372 buf[0] = 1;
373
374 /* -- "spotsize" */
375 scale = sdev->stc.dither->minmax[1];
376 buf[1] = (long)(scale + (scale > 0.0 ? 0.5 : -0.5));
377
378 /* -- "threshold" */
379 offset = sdev->stc.dither->minmax[0];
380 scale -= offset;
381 if(sdev->stc.flags & STCDFLAG1) {
382 buf[2] = (long)((sdev->stc.extv[0][sdev->stc.sizv[0]-1] -
383 sdev->stc.extv[0][0]) * scale / 2.0 + offset);
384 } else {
385 if((offset+0.5*scale) > 0.0) buf[2] = (long)(offset + 0.5*scale + 0.5);
386 else buf[2] = (long)(offset + 0.5*scale - 0.5);
387 }
388
389 /*
390 * random values, that do not exceed half of normal value
391 */
392 i2do = sdev->color_info.num_components * (3-npixel);
393 rand_max = 0;
394
395 if(sdev->stc.flags & STCDFLAG0) {
396
397 for(i = 0; i < i2do; ++i) buf[i+3] = 0;
398
399 } else {
400
401 for(i = 0; i < i2do; ++i) {
402 buf[i+3] = rand();
403 if(buf[i+3] > rand_max) rand_max = buf[i+3];
404 }
405
406 scale = (double) buf[1] / (double) rand_max;
407
408 for(i = 0; i < sdev->color_info.num_components; ++ i)
409 buf[i+3] = (long)(0.25000*scale*(buf[i+3]-rand_max/2));
410
411 for( ; i < i2do; ++i) /* includes 2 additional pixels ! */
412 buf[i+3] = (long)(0.28125*scale*(buf[i+3]-rand_max/2));
413
414 }
415
416 /* ============================================================= */
417 } /* scanline-processing or initialisation */
418 /* ============================================================= */
419
420 return 0;
421 }
422