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 * 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 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 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