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