1 /* Copyright (C) 2002 artofcode LLC. 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 /*$Id: gxwts.c,v 1.5 2002/11/02 07:31:45 raph Exp $ */ 17 /* Rendering using Well Tempered Screening. */ 18 #include "stdpre.h" 19 #include "memory_.h" /* for memcmp */ 20 #include <stdlib.h> /* for malloc */ 21 #include "gx.h" 22 #include "gxstate.h" 23 #include "gsht.h" 24 #include "math_.h" 25 #include "gserrors.h" 26 #include "gxdcolor.h" 27 #include "gxdevcli.h" 28 #include "gxdht.h" 29 #include "gxwts.h" 30 31 #define GXWTS_USE_DOUBLE 32 33 #ifndef UNIT_TEST 34 /* device color type for wts. */ 35 36 /* todo: trace and relocate pointers */ 37 gs_private_st_simple(st_dc_wts, gx_device_color, "dc_wts"); 38 private dev_color_proc_save_dc(gx_dc_wts_save_dc); 39 private dev_color_proc_get_dev_halftone(gx_dc_wts_get_dev_halftone); 40 private dev_color_proc_load(gx_dc_wts_load); 41 private dev_color_proc_fill_rectangle(gx_dc_wts_fill_rectangle); 42 private dev_color_proc_equal(gx_dc_wts_equal); 43 private dev_color_proc_write(gx_dc_wts_write); 44 private dev_color_proc_read(gx_dc_wts_read); 45 private dev_color_proc_get_nonzero_comps(gx_dc_wts_get_nonzero_comps); 46 const gx_device_color_type_t gx_dc_type_data_wts = { 47 &st_dc_wts, 48 gx_dc_wts_save_dc, gx_dc_wts_get_dev_halftone, 49 gx_dc_ht_get_phase, 50 gx_dc_wts_load, gx_dc_wts_fill_rectangle, 51 gx_dc_default_fill_masked, gx_dc_wts_equal, 52 gx_dc_wts_write, gx_dc_wts_read, 53 gx_dc_wts_get_nonzero_comps 54 }; 55 #undef gx_dc_type_wts 56 const gx_device_color_type_t *const gx_dc_type_wts = 57 &gx_dc_type_data_wts; 58 #endif 59 60 /* Low-level implementation follows. */ 61 62 /** 63 * mul_shr_16: Multiply and shift right 16. 64 * @a: 32-bit signed number. 65 * @b: 32-bit signed number. 66 * 67 * Multiply @a and @b, then shift right 16 bits. Allow intermediate value 68 * to overflow 32 bits. 69 * 70 * Return value: result. 71 **/ 72 #ifdef GXWTS_USE_DOUBLE 73 private int 74 mul_shr_16 (int a, int b) 75 { 76 return (int)floor(((double) a) * ((double) b) * (1.0 / (1 << 16))); 77 } 78 #else 79 #error todo: supply mul_shr_16 based on 64 bit integer type 80 #endif 81 82 /* Implementation of wts_get_samples for rational cells. */ 83 #if 0 84 private int 85 wts_get_samples_rat(const wts_screen_t *ws, int x, int y, 86 wts_screen_sample_t **samples, int *p_nsamples) 87 { 88 int d = y / ws->cell_height; 89 int r = y % ws->cell_height; 90 int x_ix = ((d * ws->cell_shift) + x) % ws->cell_width; 91 *p_nsamples = ws->cell_width - x_ix; 92 *samples = ws->samples + x_ix + r * ws->cell_width; 93 return 0; 94 } 95 #endif 96 97 /* Implementation of wts_get_samples for Screen J. */ 98 private int 99 wts_get_samples_j(const wts_screen_t *ws, int x, int y, 100 wts_screen_sample_t **samples, int *p_nsamples) 101 { 102 const wts_screen_j_t *wsj = (const wts_screen_j_t *)ws; 103 /* int d = y / ws->cell_height; */ 104 int y_ix = y; 105 int x_ix = x; 106 double pad = (wsj->pa) * (1.0 / (1 << 16)); 107 double pbd = (wsj->pb) * (1.0 / (1 << 16)); 108 double afrac = x * pad; 109 double bfrac = x * pbd; 110 int acount = (int)floor(afrac); 111 int bcount = (int)floor(bfrac); 112 int ccount = mul_shr_16(y, wsj->pc); 113 int dcount = mul_shr_16(y, wsj->pd); 114 int nsamples; 115 116 x_ix += acount * wsj->XA + bcount * wsj->XB + 117 ccount * wsj->XC + dcount * wsj->XD; 118 y_ix += acount * wsj->YA + bcount * wsj->YB + 119 ccount * wsj->YC + dcount * wsj->YD; 120 121 x_ix += (y_ix / ws->cell_height) * ws->cell_shift; 122 x_ix %= ws->cell_width; 123 y_ix %= ws->cell_height; 124 125 nsamples = ws->cell_width - x_ix; 126 if (floor (afrac + (nsamples - 1) * pad) > acount) 127 nsamples = (int)ceil((acount + 1 - afrac) / pad); 128 129 if (floor (bfrac + (nsamples - 1) * pbd) > bcount) 130 nsamples = (int)ceil((bcount + 1 - bfrac) / pbd); 131 #if 0 132 printf("get_samples: (%d, %d) -> (%d, %d) %d (cc=%d)\n", 133 x, y, x_ix, y_ix, nsamples, ccount); 134 #endif 135 *p_nsamples = nsamples; 136 *samples = ws->samples + x_ix + y_ix * ws->cell_width; 137 return 0; 138 } 139 140 private int 141 wts_screen_h_offset(int x, double p1, int m1, int m2) 142 { 143 /* todo: this is a linear search; constant time should be feasible */ 144 double running_p = 0; 145 int width_so_far; 146 int this_width; 147 148 for (width_so_far = 0;; width_so_far += this_width) { 149 running_p += p1; 150 if (running_p >= 0.5) { 151 this_width = m1; 152 running_p -= 1; 153 } else { 154 this_width = m2; 155 } 156 if (width_so_far + this_width > x) 157 break; 158 } 159 return x - width_so_far + (this_width == m1 ? 0 : m1); 160 } 161 162 /* Implementation of wts_get_samples for Screen H. */ 163 private int 164 wts_get_samples_h(const wts_screen_t *ws, int x, int y, 165 wts_screen_sample_t **samples, int *p_nsamples) 166 { 167 const wts_screen_h_t *wsh = (const wts_screen_h_t *)ws; 168 int x_ix = wts_screen_h_offset(x, wsh->px, 169 wsh->x1, ws->cell_width - wsh->x1); 170 int y_ix = wts_screen_h_offset(y, wsh->py, 171 wsh->y1, ws->cell_height - wsh->y1); 172 *p_nsamples = (x_ix >= wsh->x1 ? ws->cell_width : wsh->x1) - x_ix; 173 *samples = ws->samples + x_ix + y_ix * ws->cell_width; 174 return 0; 175 } 176 177 /** 178 * wts_get_samples: Get samples from Well Tempered Screening cell. 179 * @ws: Well Tempered Screening cell. 180 * @x: X coordinate of starting point. 181 * @y: Y coordinate of starting point. 182 * @samples: Where to store pointer to samples. 183 * @p_nsamples: Where to store number of valid samples. 184 * 185 * Finds samples from the cell for use in halftoning. On success, 186 * @p_nsamples is set to the number of valid samples, ie for 0 <= i < 187 * nsamples, samples[i] is a valid sample for coordinate (x + i, y). 188 * p_nsamples is guaranteed to at least 1. The samples in @samples 189 * are valid for the lifetime of the cell, or until the next garbage 190 * collection, whichever comes first. 191 * 192 * Todo: describe meaning of wts_screen_sample_t (particularly edge 193 * cases). 194 * 195 * Note: may want to add a "cursor" to the api as an optimization. It 196 * can wait, though. 197 * 198 * Return value: 0 on success. 199 **/ 200 int 201 wts_get_samples(const wts_screen_t *ws, int x, int y, 202 wts_screen_sample_t **samples, int *p_nsamples) 203 { 204 if (ws->type == WTS_SCREEN_J) 205 return wts_get_samples_j(ws, x, y, samples, p_nsamples); 206 if (ws->type == WTS_SCREEN_H) 207 return wts_get_samples_h(ws, x, y, samples, p_nsamples); 208 else 209 return -1; 210 } 211 212 /* Device color methods follow. */ 213 214 private void 215 gx_dc_wts_save_dc(const gx_device_color * pdevc, gx_device_color_saved * psdc) 216 { 217 psdc->type = pdevc->type; 218 memcpy( psdc->colors.wts.levels, 219 pdevc->colors.wts.levels, 220 sizeof(psdc->colors.wts.levels) ); 221 psdc->phase = pdevc->phase; 222 } 223 224 private const gx_device_halftone * 225 gx_dc_wts_get_dev_halftone(const gx_device_color * pdevc) 226 { 227 return pdevc->colors.wts.w_ht; 228 } 229 230 private int 231 gx_dc_wts_load(gx_device_color *pdevc, const gs_imager_state * pis, 232 gx_device *ignore_dev, gs_color_select_t select) 233 { 234 return 0; 235 } 236 237 /** 238 * wts_draw: Draw a halftoned shade into a 1 bit deep buffer. 239 * @ws: WTS screen. 240 * @shade: Gray shade to draw. 241 * @data: Destination buffer. 242 * @data_raster: Rowstride for destination buffer. 243 * @x, @y, @w, @h: coordinates of rectangle to draw. 244 * 245 * This is close to an implementation of the "draw" method for the 246 * gx_ht_order class. Currently, only WTS screens implement this 247 * method, and only WTS device colors invoke it. However, implementing 248 * this for legacy order objects is probably a good idea, to improve 249 * halftoning performance as the cell size scales up. 250 * 251 * However, it's not exactly an implementation of the "draw" method 252 * for the gx_ht_order class because the "self" type would need to be 253 * gx_ht_order. Currently, however, device colors don't hold a pointer 254 * to the order object. Some amount of refactoring seems to be in 255 * order. 256 * 257 * Return value: 0 on success. 258 **/ 259 private int 260 wts_draw(wts_screen_t *ws, wts_screen_sample_t shade, 261 byte *data, int data_raster, 262 int x, int y, int w, int h) 263 { 264 int xo, yo; 265 unsigned char *line_start = data; 266 267 for (yo = 0; yo < h; yo++) { 268 unsigned char *line_ptr = line_start; 269 int mask = 0x80; 270 unsigned char b = 0; 271 int imax; 272 273 for (xo = 0; xo < w; xo += imax) { 274 wts_screen_sample_t *samples; 275 int n_samples, i; 276 277 wts_get_samples(ws, x + xo, y + yo, &samples, &n_samples); 278 imax = min(w - xo, n_samples); 279 for (i = 0; i < imax; i++) { 280 if (shade > samples[i]) 281 b |= mask; 282 mask >>= 1; 283 if (mask == 0) { 284 *line_ptr++ = b; 285 b = 0; 286 mask = 0x80; 287 } 288 } 289 } 290 if (mask != 0x80) 291 *line_ptr = b; 292 line_start += data_raster; 293 } 294 return 0; 295 } 296 297 /** 298 * Special case implementation for one component. When we do plane_mask, 299 * we'll want to generalize this to handle any single-bit plane_mask. 300 **/ 301 private int 302 gx_dc_wts_fill_rectangle_1(const gx_device_color *pdevc, 303 int x, int y, int w, int h, 304 gx_device *dev, gs_logical_operation_t lop, 305 const gx_rop_source_t *source) 306 { 307 /* gx_rop_source_t no_source; */ 308 int tile_raster = ((w + 31) & -32) >> 3; 309 int tile_size = tile_raster * h; 310 unsigned char *tile_data; 311 int code = 0; 312 gx_ht_order_component *components = pdevc->colors.wts.w_ht->components; 313 wts_screen_t *ws = components[0].corder.wts; 314 wts_screen_sample_t shade = pdevc->colors.wts.levels[0]; 315 gx_color_index color0, color1; 316 317 color0 = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ? 0 : 318 pdevc->colors.wts.plane_vector[1]; 319 color1 = pdevc->colors.wts.plane_vector[0]; 320 321 tile_data = malloc(tile_size); 322 323 wts_draw(ws, shade, tile_data, tile_raster, x, y, w, h); 324 325 /* See gx_dc_ht_binary_fill_rectangle() for explanation. */ 326 if (dev->color_info.depth > 1) 327 lop &= ~lop_T_transparent; 328 329 /* Interesting question: should data_x be (x & 7), rather than 0, 330 to improve alignment? */ 331 if (source == NULL && lop_no_S_is_T(lop)) 332 code = (*dev_proc(dev, copy_mono)) 333 (dev, tile_data, 0, tile_raster, gx_no_bitmap_id, 334 x, y, w, h, color0, color1); 335 336 free(tile_data); 337 return code; 338 } 339 340 private int 341 gx_dc_wts_write( 342 const gx_device_color * pdevc, 343 const gx_device_color_saved * psdc, 344 const gx_device * dev, 345 byte * pdata, 346 uint * psize ) 347 { 348 /* not yet implemented */ 349 return_error(gs_error_unknownerror); 350 } 351 352 private int 353 gx_dc_wts_read( 354 gx_device_color * pdevc, 355 const gs_imager_state * pis, 356 const gx_device_color * prior_devc, 357 const gx_device * dev, 358 const byte * pdata, 359 uint size, 360 gs_memory_t * mem ) 361 { 362 /* not yet implemented */ 363 return_error(gs_error_unknownerror); 364 } 365 366 367 /** 368 * wts_repack_tile_4: Repack four 1-bit tiles into chunky nibbles. 369 * Note: argument list will change. plane_mask and base_color will 370 * probably get added as an optimization. 371 * 372 * Note: we round w up to an even value. We're counting on the 373 * subsequent copy_color to ignore any extra bits. 374 **/ 375 private void 376 wts_repack_tile_4(unsigned char *ctile_data, int ctile_raster, 377 const unsigned char **tile_data, int tile_raster, 378 const gx_color_index *plane_vector, bool invert, 379 int w, int h) 380 { 381 int y; 382 int tile_idx_start = 0; 383 unsigned char *ctile_start = ctile_data; 384 byte inv_byte = invert ? 0xff : 0; 385 386 for (y = 0; y < h; y++) { 387 int x; 388 int tile_idx = tile_idx_start; 389 390 for (x = 0; x < w; x += 2) { 391 byte b = 0; 392 byte m0 = 0x80 >> (x & 6); 393 byte m1 = m0 >> 1; 394 byte td; 395 396 td = tile_data[0][tile_idx] ^ inv_byte; 397 if (td & m0) b |= plane_vector[0] << 4; 398 if (td & m1) b |= plane_vector[0]; 399 400 td = tile_data[1][tile_idx] ^ inv_byte; 401 if (td & m0) b |= plane_vector[1] << 4; 402 if (td & m1) b |= plane_vector[1]; 403 404 td = tile_data[2][tile_idx] ^ inv_byte; 405 if (td & m0) b |= plane_vector[2] << 4; 406 if (td & m1) b |= plane_vector[2]; 407 408 td = tile_data[3][tile_idx] ^ inv_byte; 409 if (td & m0) b |= plane_vector[3] << 4; 410 if (td & m1) b |= plane_vector[3]; 411 412 if ((x & 6) == 6) 413 tile_idx++; 414 ctile_start[x >> 1] = b; 415 } 416 tile_idx_start += tile_raster; 417 ctile_start += ctile_raster; 418 } 419 } 420 421 /* Special case implementation for four components. Intermediate color 422 * to the order objecttile (for copy_color) is packed 2 to a byte. 423 * 424 * Looking at this code, it should generalize to more than four 425 * components. Probably the repack code should get factored out. 426 */ 427 private int 428 gx_dc_wts_fill_rectangle_4(const gx_device_color *pdevc, 429 int x, int y, int w, int h, 430 gx_device *dev, gs_logical_operation_t lop, 431 const gx_rop_source_t *source) 432 { 433 int num_comp = pdevc->colors.wts.num_components; 434 /* gx_rop_source_t no_source; */ 435 436 int tile_raster = ((w + 31) & -32) >> 3; 437 int tile_size = tile_raster * h; 438 unsigned char *tile_data[4]; 439 440 int ctile_raster = ((w + 7) & -8) >> 1; 441 int ctile_size = ctile_raster * h; 442 unsigned char *ctile_data; 443 444 int code = 0; 445 bool invert = 0 && dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE; 446 int i; 447 448 for (i = 0; i < num_comp; i++) { 449 wts_screen_sample_t shade = pdevc->colors.wts.levels[i]; 450 gx_ht_order_component *components = pdevc->colors.wts.w_ht->components; 451 wts_screen_t *ws = components[i].corder.wts; 452 453 tile_data[i] = malloc(tile_size); 454 wts_draw(ws, shade, tile_data[i], tile_raster, x, y, w, h); 455 } 456 457 ctile_data = malloc(ctile_size); 458 wts_repack_tile_4(ctile_data, ctile_raster, 459 (const unsigned char **)tile_data, tile_raster, 460 pdevc->colors.wts.plane_vector, invert, w, h); 461 462 /* See gx_dc_ht_binary_fill_rectangle() for explanation. */ 463 if (dev->color_info.depth > 1) 464 lop &= ~lop_T_transparent; 465 466 if (source == NULL && lop_no_S_is_T(lop)) 467 code = (*dev_proc(dev, copy_color)) 468 (dev, ctile_data, 0, ctile_raster, gx_no_bitmap_id, 469 x, y, w, h); 470 471 free(ctile_data); 472 for (i = 0; i < num_comp; i++) { 473 free(tile_data[i]); 474 } 475 476 return code; 477 } 478 479 private int 480 gx_dc_wts_fill_rectangle(const gx_device_color *pdevc, 481 int x, int y, int w, int h, 482 gx_device *dev, gs_logical_operation_t lop, 483 const gx_rop_source_t *source) 484 { 485 int num_comp = pdevc->colors.wts.num_components; 486 487 if (num_comp == 1) 488 return gx_dc_wts_fill_rectangle_1(pdevc, x, y, w, h, dev, lop, source); 489 else if (num_comp <= 4) 490 return gx_dc_wts_fill_rectangle_4(pdevc, x, y, w, h, dev, lop, source); 491 else 492 return -1; 493 } 494 495 /* Compare two wts colors for equality. */ 496 private int 497 gx_dc_wts_equal(const gx_device_color *pdevc1, 498 const gx_device_color *pdevc2) 499 { 500 uint num_comp = pdevc1->colors.wts.num_components; 501 502 if (pdevc2->type != pdevc1->type || 503 pdevc1->phase.x != pdevc2->phase.x || 504 pdevc1->phase.y != pdevc2->phase.y || 505 num_comp != pdevc2->colors.wts.num_components 506 ) 507 return false; 508 return 509 !memcmp(pdevc1->colors.wts.levels, 510 pdevc2->colors.wts.levels, 511 num_comp * sizeof(pdevc1->colors.wts.levels[0])); 512 } 513 514 /* 515 * Get the nonzero components of a wts halftone. This is used to 516 * distinguish components that are given zero intensity due to halftoning 517 * from those for which the original color intensity was in fact zero. 518 */ 519 int 520 gx_dc_wts_get_nonzero_comps( 521 const gx_device_color * pdevc, 522 const gx_device * dev_ignored, 523 gx_color_index * pcomp_bits ) 524 { 525 int i, ncomps = pdevc->colors.wts.num_components; 526 gx_color_index comp_bits = 0; /* todo: plane_mask */ 527 528 for (i = 0; i < ncomps; i++) { 529 if (pdevc->colors.wts.levels[i] != 0) 530 comp_bits |= ((gx_color_index)1) << i; 531 } 532 *pcomp_bits = comp_bits; 533 534 return 0; 535 } 536