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