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