1/* 2 * "$Id: testdither.c,v 1.49 2006/05/07 13:26:27 rlk Exp $" 3 * 4 * Test/profiling program for dithering code. 5 * 6 * Copyright 1997-2000 Michael Sweet (mike@easysw.com) 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the Free 10 * Software Foundation; either version 2 of the License, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 */ 22 23#ifdef HAVE_CONFIG_H 24#include <config.h> 25#endif 26#include <gutenprint/gutenprint.h> 27#define STPI_TESTDITHER 28 29#include "../src/main/gutenprint-internal.h" 30#include <stdio.h> 31#include <sys/time.h> 32#include <unistd.h> 33#include <string.h> 34 35/* 36 * Definitions for dither test... 37 */ 38 39#define IMAGE_WIDTH 5760 /* 8in * 720dpi */ 40#define IMAGE_HEIGHT 2880 /* 4in * 720dpi */ 41#define BUFFER_SIZE IMAGE_WIDTH 42 43#define IMAGE_MIXED 0 /* Mix of line types */ 44#define IMAGE_WHITE 1 /* All white image */ 45#define IMAGE_BLACK 2 /* All black image */ 46#define IMAGE_COLOR 3 /* All color image */ 47#define IMAGE_RANDOM 4 /* All random image */ 48 49#define DITHER_GRAY 0 /* Dither grayscale pixels */ 50#define DITHER_COLOR 1 /* Dither color pixels */ 51#define DITHER_PHOTO 2 /* Dither photo pixels */ 52#define DITHER_CMYK 3 /* Dither photo pixels */ 53#define DITHER_PHOTO_CMYK 4 /* Dither photo pixels */ 54 55 56/* 57 * Globals... 58 */ 59 60int image_type = IMAGE_MIXED; 61int stpi_dither_type = DITHER_COLOR; 62const char *dither_name = NULL; 63int dither_bits = 1; 64int write_image = 1; 65int quiet; 66unsigned short white_line[IMAGE_WIDTH * 6], 67 black_line[IMAGE_WIDTH * 6], 68 color_line[IMAGE_WIDTH * 6], 69 random_line[IMAGE_WIDTH * 6]; 70 71static const char *stpi_dither_types[] = /* Different dithering modes */ 72 { 73 "gray", 74 "color", 75 "photo", 76 "cmyk", 77 "photocmyk" 78 }; 79static const char *image_types[] = /* Different image types */ 80 { 81 "mixed", 82 "white", 83 "black", 84 "colorimage", 85 "random" 86 }; 87 88 89#define SHADE(density, name) \ 90{ density, sizeof(name)/sizeof(stp_dotsize_t), name } 91 92static const stp_dotsize_t single_dotsize[] = 93{ 94 { 0x1, 1.0 } 95}; 96 97static const stp_dotsize_t variable_dotsizes[] = 98{ 99 { 0x1, 0.28 }, 100 { 0x2, 0.58 }, 101 { 0x3, 1.0 } 102}; 103 104static const stp_shade_t normal_1bit_shades[] = 105{ 106 SHADE(1.0, single_dotsize) 107}; 108 109static const stp_shade_t photo_1bit_shades[] = 110{ 111 SHADE(0.33, single_dotsize), 112 SHADE(1.0, single_dotsize) 113}; 114 115static const stp_shade_t normal_2bit_shades[] = 116{ 117 SHADE(1.0, variable_dotsizes) 118}; 119 120static const stp_shade_t photo_2bit_shades[] = 121{ 122 SHADE(0.33, variable_dotsizes), 123 SHADE(1.0, variable_dotsizes) 124}; 125 126 127double compute_interval(struct timeval *tv1, struct timeval *tv2); 128void image_init(void); 129void image_get_row(unsigned short *data, int row); 130void write_gray(FILE *fp, unsigned char *black); 131void write_color(FILE *fp, unsigned char *cyan, unsigned char *magenta, 132 unsigned char *yellow, unsigned char *black); 133void write_photo(FILE *fp, unsigned char *cyan, unsigned char *lcyan, 134 unsigned char *magenta, unsigned char *lmagenta, 135 unsigned char *yellow, unsigned char *black); 136 137 138double 139compute_interval(struct timeval *tv1, struct timeval *tv2) 140{ 141 return ((double) tv2->tv_sec + (double) tv2->tv_usec / 1000000.) - 142 ((double) tv1->tv_sec + (double) tv1->tv_usec / 1000000.); 143} 144 145static void 146writefunc(void *file, const char *buf, size_t bytes) 147{ 148 FILE *prn = (FILE *)file; 149 fwrite(buf, 1, bytes, prn); 150} 151 152static int 153image_width(stp_image_t *image) 154{ 155 return IMAGE_WIDTH; 156} 157 158static stp_image_t theImage = 159{ 160 NULL, 161 NULL, 162 image_width, 163 NULL, 164 NULL, 165 NULL, 166}; 167 168/* 169 * 'main()' - Test dithering code for performance measurement. 170 */ 171 172static int 173run_one_testdither(void) 174{ 175 int print_progress = 0; 176 int i; /* Looping vars */ 177 unsigned char black[BUFFER_SIZE], /* Black bitmap data */ 178 cyan[BUFFER_SIZE], /* Cyan bitmap data */ 179 magenta[BUFFER_SIZE], /* Magenta bitmap data */ 180 lcyan[BUFFER_SIZE], /* Light cyan bitmap data */ 181 lmagenta[BUFFER_SIZE], /* Light magenta bitmap data */ 182 yellow[BUFFER_SIZE]; /* Yellow bitmap data */ 183 unsigned short rgb[IMAGE_WIDTH * 6], /* RGB buffer */ 184 gray[IMAGE_WIDTH]; /* Grayscale buffer */ 185 FILE *fp = NULL; /* PPM/PGM output file */ 186 char filename[1024]; /* Name of file */ 187 stp_vars_t *v; /* Dither variables */ 188 stp_parameter_t desc; 189 struct timeval tv1, tv2; 190 191 /* 192 * Initialise libgutenprint 193 */ 194 195 stp_init(); 196 v = stp_vars_create(); 197 stp_set_driver(v, "escp2-ex"); 198 stp_describe_parameter(v, "DitherAlgorithm", &desc); 199 200 /* 201 * Setup the image and color functions... 202 */ 203 204 image_init(); 205 stp_set_outfunc(v, writefunc); 206 stp_set_errfunc(v, writefunc); 207 stp_set_outdata(v, stdout); 208 stp_set_errdata(v, stderr); 209 210 /* 211 * Output the page... 212 */ 213 214 if (dither_name) 215 stp_set_string_parameter(v, "DitherAlgorithm", dither_name); 216 217 stp_set_string_parameter(v, "ChannelBitDepth", "8"); 218 switch (stpi_dither_type) 219 { 220 case DITHER_GRAY: 221 stp_set_string_parameter(v, "PrintingMode", "BW"); 222 stp_set_string_parameter(v, "InputImageType", "Grayscale"); 223 break; 224 case DITHER_COLOR: 225 case DITHER_PHOTO: 226 stp_set_string_parameter(v, "PrintingMode", "Color"); 227 stp_set_string_parameter(v, "InputImageType", "RGB"); 228 break; 229 case DITHER_CMYK: 230 case DITHER_PHOTO_CMYK: 231 stp_set_string_parameter(v, "PrintingMode", "Color"); 232 stp_set_string_parameter(v, "InputImageType", "CMYK"); 233 break; 234 } 235 236 stp_dither_init(v, &theImage, IMAGE_WIDTH, 1, 1); 237 238 /* 239 * Now dither the "page"... 240 */ 241 242 switch (stpi_dither_type) 243 { 244 case DITHER_PHOTO: 245 stp_dither_add_channel(v, lcyan, STP_ECOLOR_C, 1); 246 stp_dither_add_channel(v, lmagenta, STP_ECOLOR_M, 1); 247 /* FALLTHROUGH */ 248 case DITHER_COLOR: 249 stp_dither_add_channel(v, cyan, STP_ECOLOR_C, 0); 250 stp_dither_add_channel(v, magenta, STP_ECOLOR_M, 0); 251 stp_dither_add_channel(v, yellow, STP_ECOLOR_Y, 0); 252 break; 253 case DITHER_PHOTO_CMYK : 254 stp_dither_add_channel(v, lcyan, STP_ECOLOR_C, 1); 255 stp_dither_add_channel(v, lmagenta, STP_ECOLOR_M, 1); 256 /* FALLTHROUGH */ 257 case DITHER_CMYK : 258 stp_dither_add_channel(v, cyan, STP_ECOLOR_C, 0); 259 stp_dither_add_channel(v, magenta, STP_ECOLOR_M, 0); 260 stp_dither_add_channel(v, yellow, STP_ECOLOR_Y, 0); 261 /* FALLTHROUGH */ 262 case DITHER_GRAY: 263 stp_dither_add_channel(v, black, STP_ECOLOR_K, 0); 264 } 265 266 if (stpi_dither_type == DITHER_PHOTO) 267 stp_set_float_parameter(v, "GCRLower", 0.4 / dither_bits + 0.1); 268 else 269 stp_set_float_parameter(v, "GCRLower", 0.25 / dither_bits); 270 271 stp_set_float_parameter(v, "GCRUpper", .5); 272 273 switch (stpi_dither_type) 274 { 275 case DITHER_GRAY : 276 switch (dither_bits) 277 { 278 case 1 : 279 stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0); 280 break; 281 case 2 : 282 stp_dither_set_transition(v, 0.5); 283 stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0); 284 break; 285 } 286 break; 287 case DITHER_COLOR : 288 switch (dither_bits) 289 { 290 case 1 : 291 stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_1bit_shades, 1.0, 0.65); 292 stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_1bit_shades, 1.0, 0.6); 293 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08); 294 break; 295 case 2 : 296 stp_dither_set_transition(v, 0.5); 297 stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_2bit_shades, 1.0, 0.65); 298 stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_2bit_shades, 1.0, 0.6); 299 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08); 300 break; 301 } 302 break; 303 case DITHER_CMYK : 304 switch (dither_bits) 305 { 306 case 1 : 307 stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_1bit_shades, 1.0, 0.65); 308 stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_1bit_shades, 1.0, 0.6); 309 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08); 310 stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0); 311 break; 312 case 2 : 313 stp_dither_set_transition(v, 0.5); 314 stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_2bit_shades, 1.0, 0.65); 315 stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_2bit_shades, 1.0, 0.6); 316 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08); 317 stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0); 318 break; 319 } 320 break; 321 case DITHER_PHOTO : 322 switch (dither_bits) 323 { 324 case 1 : 325 stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_1bit_shades, 1.0, 0.65); 326 stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_1bit_shades, 1.0, 0.6); 327 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08); 328 break; 329 case 2 : 330 stp_dither_set_transition(v, 0.7); 331 stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_2bit_shades, 1.0, 0.65); 332 stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_2bit_shades, 1.0, 0.6); 333 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08); 334 break; 335 } 336 break; 337 case DITHER_PHOTO_CMYK : 338 switch (dither_bits) 339 { 340 case 1 : 341 stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_1bit_shades, 1.0, 0.65); 342 stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_1bit_shades, 1.0, 0.6); 343 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08); 344 stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0); 345 break; 346 case 2 : 347 stp_dither_set_transition(v, 0.7); 348 stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_2bit_shades, 1.0, 0.65); 349 stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_2bit_shades, 1.0, 0.6); 350 stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08); 351 stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0); 352 break; 353 } 354 break; 355 } 356 357 stp_dither_set_ink_spread(v, 12 + dither_bits); 358 359 /* 360 * Open the PPM/PGM file... 361 */ 362 363 364 sprintf(filename, "%s-%s-%s-%dbit.%s", image_types[image_type], 365 stpi_dither_types[stpi_dither_type], 366 dither_name ? dither_name : desc.deflt.str, dither_bits, 367 (stpi_dither_type == DITHER_GRAY) ? "pgm" : "ppm"); 368 369 stp_parameter_description_destroy(&desc); 370 371 if (isatty(1)) 372 print_progress = 1; 373 374 if (print_progress && !quiet) 375 printf("%s ", filename); 376 377 if (write_image) 378 { 379 if ((fp = fopen(filename, "wb")) != NULL) 380 { 381 if (stpi_dither_type == DITHER_GRAY) 382 fputs("P5\n", fp); 383 else 384 fputs("P6\n", fp); 385 386 fprintf(fp, "%d\n%d\n255\n", IMAGE_WIDTH, IMAGE_HEIGHT); 387 } 388 else 389 perror("Create"); 390 } 391 392 (void) gettimeofday(&tv1, NULL); 393 394 for (i = 0; i < IMAGE_HEIGHT; i ++) 395 { 396 if (print_progress && !quiet && (i & 63) == 0) 397 { 398 printf("\rProcessing row %d...", i); 399 fflush(stdout); 400 } 401 402 switch (stpi_dither_type) 403 { 404 case DITHER_GRAY : 405 image_get_row(gray, i); 406 stp_dither_internal(v, i, gray, 0, 0, NULL); 407 if (fp) 408 write_gray(fp, black); 409 break; 410 case DITHER_COLOR : 411 case DITHER_CMYK : 412 image_get_row(rgb, i); 413 stp_dither_internal(v, i, rgb, 0, 0, NULL); 414 if (fp) 415 write_color(fp, cyan, magenta, yellow, black); 416 break; 417 case DITHER_PHOTO : 418 case DITHER_PHOTO_CMYK : 419 image_get_row(rgb, i); 420 stp_dither_internal(v, i, rgb, 0, 0, NULL); 421 if (fp) 422 write_photo(fp, cyan, lcyan, magenta, lmagenta, yellow, black); 423 break; 424 } 425 } 426 427 (void) gettimeofday(&tv2, NULL); 428 429 stp_vars_destroy(v); 430 431 if (fp != NULL) 432 fclose(fp); 433 434 if (!quiet) 435 { 436 if (print_progress) 437 fputc('\r', stdout); 438 printf("%-30s %d pix %.3f sec %.2f pix/sec\n", 439 filename, IMAGE_WIDTH * IMAGE_HEIGHT, compute_interval(&tv1, &tv2), 440 (float)(IMAGE_WIDTH * IMAGE_HEIGHT) / compute_interval(&tv1, &tv2)); 441 fflush(stdout); 442 } 443 return 0; 444} 445 446static int 447run_testdither_from_cmdline(int argc, char **argv) 448{ 449 int i, j; 450 int status; 451 for (i = 1; i < argc; i ++) 452 { 453 if (strcmp(argv[i], "no-image") == 0) 454 { 455 write_image = 0; 456 continue; 457 } 458 459 if (strcmp(argv[i], "quiet") == 0) 460 { 461 quiet = 1; 462 continue; 463 } 464 465 if (strcmp(argv[i], "1-bit") == 0) 466 { 467 dither_bits = 1; 468 continue; 469 } 470 471 if (strcmp(argv[i], "2-bit") == 0) 472 { 473 dither_bits = 2; 474 continue; 475 } 476 477 for (j = 0; j < 5; j ++) 478 if (strcmp(argv[i], stpi_dither_types[j]) == 0) 479 break; 480 481 if (j < 5) 482 { 483 stpi_dither_type = j; 484 continue; 485 } 486 487 for (j = 0; j < 5; j ++) 488 if (strcmp(argv[i], image_types[j]) == 0) 489 break; 490 491 if (j < 5) 492 { 493 image_type = j; 494 continue; 495 } 496 497 dither_name = argv[i]; 498 } 499 status = run_one_testdither(); 500 if (status) 501 return 1; 502 else 503 return 0; 504} 505 506static int 507run_standard_testdithers(void) 508{ 509 stp_vars_t *v = stp_vars_create(); 510 stp_parameter_t desc; 511 int j; 512 int failures = 0; 513 int status; 514 515 stp_set_driver(v, "escp2-ex"); 516 stp_describe_parameter(v, "DitherAlgorithm", &desc); 517 518 write_image = 0; 519 quiet = 1; 520 for (j = 0; j < stp_string_list_count(desc.bounds.str); j ++) 521 { 522 dither_name = stp_string_list_param(desc.bounds.str, j)->name; 523 if (strcmp(dither_name, "None") == 0) 524 continue; 525 printf("%s", dither_name); 526 fflush(stdout); 527 for (dither_bits = 1; dither_bits <= 2; dither_bits++) 528 for (stpi_dither_type = 0; 529 stpi_dither_type < sizeof(stpi_dither_types) / sizeof(const char *); 530 stpi_dither_type++) 531 for (image_type = 0; 532 image_type < sizeof(image_types) / sizeof(const char *); 533 image_type++) 534 { 535 status = run_one_testdither(); 536 if (status) 537 { 538 printf("%s %d %s %s\n", dither_name, dither_bits, 539 stpi_dither_types[stpi_dither_type], 540 image_types[image_type]); 541 failures++; 542 } 543 else 544 printf("."); 545 fflush(stdout); 546 } 547 printf("\n"); 548 fflush(stdout); 549 } 550 stp_parameter_description_destroy(&desc); 551 stp_vars_destroy(v); 552 return (failures ? 1 : 0); 553} 554 555int 556main(int argc, char **argv) 557{ 558 stp_init(); 559 560 if (argc == 1) 561 return run_standard_testdithers(); 562 else 563 return run_testdither_from_cmdline(argc, argv); 564} 565 566 567void 568image_get_row(unsigned short *data, 569 int row) 570{ 571 unsigned short *src; 572 573 574 switch (image_type) 575 { 576 case IMAGE_MIXED : 577 switch ((row / 100) & 3) 578 { 579 case 0 : 580 src = white_line; 581 break; 582 case 1 : 583 src = color_line; 584 break; 585 case 2 : 586 src = black_line; 587 break; 588 case 3 : 589 default: 590 src = random_line; 591 break; 592 } 593 break; 594 case IMAGE_WHITE : 595 src = white_line; 596 break; 597 case IMAGE_BLACK : 598 src = black_line; 599 break; 600 case IMAGE_COLOR : 601 src = color_line; 602 break; 603 case IMAGE_RANDOM : 604 default: 605 src = random_line; 606 break; 607 } 608 609 switch (stpi_dither_type) 610 { 611 case DITHER_GRAY: 612 memcpy(data, src, IMAGE_WIDTH * 2); 613 break; 614 case DITHER_COLOR: 615 memcpy(data, src, IMAGE_WIDTH * 6); 616 break; 617 case DITHER_CMYK: 618 memcpy(data, src, IMAGE_WIDTH * 8); 619 break; 620 case DITHER_PHOTO: 621 memcpy(data, src, IMAGE_WIDTH * 10); 622 break; 623 case DITHER_PHOTO_CMYK: 624 memcpy(data, src, IMAGE_WIDTH * 12); 625 break; 626 } 627} 628 629 630void 631image_init(void) 632{ 633 int i, j; 634 unsigned short *cptr, 635 *rptr; 636 637 638 /* 639 * Set the white and black line data... 640 */ 641 642 memset(white_line, 0, sizeof(white_line)); 643 memset(black_line, 255, sizeof(black_line)); 644 645 /* 646 * Fill in the color and random data... 647 */ 648 649 for (i = IMAGE_WIDTH, cptr = color_line, rptr = random_line; i > 0; i --) 650 { 651 /* 652 * Do 64 color or grayscale blocks over the line... 653 */ 654 655 j = i / (IMAGE_WIDTH / 64); 656 657 switch (stpi_dither_type) 658 { 659 case DITHER_GRAY: 660 *cptr++ = 65535 * j / 63; 661 *rptr++ = 65535 * (rand() & 255) / 255; 662 break; 663 case DITHER_COLOR: 664 *cptr++ = 65535 * (j >> 4) / 3; 665 *cptr++ = 65535 * ((j >> 2) & 3) / 3; 666 *cptr++ = 65535 * (j & 3) / 3; 667 *rptr++ = 65535 * (rand() & 255) / 255; 668 *rptr++ = 65535 * (rand() & 255) / 255; 669 *rptr++ = 65535 * (rand() & 255) / 255; 670 break; 671 case DITHER_CMYK: 672 *cptr++ = 65535 * (j >> 4) / 3; 673 *cptr++ = 65535 * ((j >> 2) & 3) / 3; 674 *cptr++ = 65535 * (j & 3) / 3; 675 *cptr++ = 65535 * j / 63; 676 *rptr++ = 65535 * (rand() & 255) / 255; 677 *rptr++ = 65535 * (rand() & 255) / 255; 678 *rptr++ = 65535 * (rand() & 255) / 255; 679 *rptr++ = 65535 * (rand() & 255) / 255; 680 break; 681 case DITHER_PHOTO: 682 *cptr++ = 65535 * (j >> 4) / 3; 683 *cptr++ = 65535 * ((j >> 2) & 3) / 3; 684 *cptr++ = 65535 * (j & 3) / 3; 685 *cptr++ = 65535 * j / 63; 686 *cptr++ = 65535 * (j >> 4) / 3; 687 *rptr++ = 65535 * (rand() & 255) / 255; 688 *rptr++ = 65535 * (rand() & 255) / 255; 689 *rptr++ = 65535 * (rand() & 255) / 255; 690 *rptr++ = 65535 * (rand() & 255) / 255; 691 *rptr++ = 65535 * (rand() & 255) / 255; 692 break; 693 case DITHER_PHOTO_CMYK: 694 *cptr++ = 65535 * (j >> 4) / 3; 695 *cptr++ = 65535 * ((j >> 2) & 3) / 3; 696 *cptr++ = 65535 * (j & 3) / 3; 697 *cptr++ = 65535 * j / 63; 698 *cptr++ = 65535 * (j >> 4) / 3; 699 *cptr++ = 65535 * ((j >> 2) & 3) / 3; 700 *rptr++ = 65535 * (rand() & 255) / 255; 701 *rptr++ = 65535 * (rand() & 255) / 255; 702 *rptr++ = 65535 * (rand() & 255) / 255; 703 *rptr++ = 65535 * (rand() & 255) / 255; 704 *rptr++ = 65535 * (rand() & 255) / 255; 705 *rptr++ = 65535 * (rand() & 255) / 255; 706 break; 707 } 708 } 709} 710 711 712void 713write_gray(FILE *fp, 714 unsigned char *black) 715{ 716 int count; 717 unsigned char byte, 718 bit, 719 shift; 720 721 722 if (dither_bits == 1) 723 { 724 for (count = IMAGE_WIDTH, byte = *black++, bit = 128; count > 0; count --) 725 { 726 if (byte & bit) 727 putc(0, fp); 728 else 729 putc(255, fp); 730 731 if (bit > 1) 732 bit >>= 1; 733 else 734 { 735 byte = *black++; 736 bit = 128; 737 } 738 } 739 } 740 else 741 { 742 unsigned char kb[BUFFER_SIZE]; 743 unsigned char *kbuf = kb; 744 stp_fold(black, IMAGE_WIDTH / 8, kbuf); 745 for (count = IMAGE_WIDTH, byte = *kbuf++, shift = 6; count > 0; count --) 746 { 747 putc(255 - 255 * ((byte >> shift) & 3) / 3, fp); 748 749 if (shift > 0) 750 shift -= 2; 751 else 752 { 753 byte = *kbuf++; 754 shift = 6; 755 } 756 } 757 } 758} 759 760 761void 762write_color(FILE *fp, 763 unsigned char *cyan, 764 unsigned char *magenta, 765 unsigned char *yellow, 766 unsigned char *black) 767{ 768 int count; 769 unsigned char cbyte, 770 mbyte, 771 ybyte, 772 kbyte, 773 bit, 774 shift; 775 int r, g, b, k; 776 777 778 if (dither_bits == 1) 779 { 780 for (count = IMAGE_WIDTH, cbyte = *cyan++, mbyte = *magenta++, 781 ybyte = *yellow++, kbyte = *black++, bit = 128; 782 count > 0; 783 count --) 784 { 785 if (kbyte & bit) 786 { 787 putc(0, fp); 788 putc(0, fp); 789 putc(0, fp); 790 } 791 else 792 { 793 if (cbyte & bit) 794 putc(0, fp); 795 else 796 putc(255, fp); 797 798 if (mbyte & bit) 799 putc(0, fp); 800 else 801 putc(255, fp); 802 803 if (ybyte & bit) 804 putc(0, fp); 805 else 806 putc(255, fp); 807 } 808 809 if (bit > 1) 810 bit >>= 1; 811 else 812 { 813 cbyte = *cyan++; 814 mbyte = *magenta++; 815 ybyte = *yellow++; 816 kbyte = *black++; 817 bit = 128; 818 } 819 } 820 } 821 else 822 { 823 unsigned char kb[BUFFER_SIZE]; 824 unsigned char cb[BUFFER_SIZE]; 825 unsigned char mb[BUFFER_SIZE]; 826 unsigned char yb[BUFFER_SIZE]; 827 unsigned char *kbuf = kb; 828 unsigned char *cbuf = cb; 829 unsigned char *mbuf = mb; 830 unsigned char *ybuf = yb; 831 stp_fold(black, IMAGE_WIDTH / 8, kbuf); 832 stp_fold(cyan, IMAGE_WIDTH / 8, cbuf); 833 stp_fold(magenta, IMAGE_WIDTH / 8, mbuf); 834 stp_fold(yellow, IMAGE_WIDTH / 8, ybuf); 835 for (count = IMAGE_WIDTH, cbyte = *cbuf++, mbyte = *mbuf++, 836 ybyte = *ybuf++, kbyte = *kbuf++, shift = 6; 837 count > 0; 838 count --) 839 { 840 k = 255 * ((kbyte >> shift) & 3) / 3; 841 r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - k; 842 g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - k; 843 b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k; 844 845 if (r < 0) 846 putc(0, fp); 847 else 848 putc(r, fp); 849 850 if (g < 0) 851 putc(0, fp); 852 else 853 putc(g, fp); 854 855 if (b < 0) 856 putc(0, fp); 857 else 858 putc(b, fp); 859 860 if (shift > 0) 861 shift -= 2; 862 else 863 { 864 cbyte = *cbuf++; 865 mbyte = *mbuf++; 866 ybyte = *ybuf++; 867 kbyte = *kbuf++; 868 shift = 6; 869 } 870 } 871 } 872} 873 874 875void 876write_photo(FILE *fp, 877 unsigned char *cyan, 878 unsigned char *lcyan, 879 unsigned char *magenta, 880 unsigned char *lmagenta, 881 unsigned char *yellow, 882 unsigned char *black) 883{ 884 int count; 885 unsigned char cbyte, 886 lcbyte, 887 mbyte, 888 lmbyte, 889 ybyte, 890 kbyte, 891 bit, 892 shift; 893 int r, g, b, k; 894 895 896 if (dither_bits == 1) 897 { 898 for (count = IMAGE_WIDTH, cbyte = *cyan++, lcbyte = *lcyan++, 899 mbyte = *magenta++, lmbyte = *lmagenta++, 900 ybyte = *yellow++, kbyte = *black++, bit = 128; 901 count > 0; 902 count --) 903 { 904 if (kbyte & bit) 905 { 906 putc(0, fp); 907 putc(0, fp); 908 putc(0, fp); 909 } 910 else 911 { 912 if (cbyte & bit) 913 putc(0, fp); 914 else if (lcbyte & bit) 915 putc(127, fp); 916 else 917 putc(255, fp); 918 919 if (mbyte & bit) 920 putc(0, fp); 921 else if (lmbyte & bit) 922 putc(127, fp); 923 else 924 putc(255, fp); 925 926 if (ybyte & bit) 927 putc(0, fp); 928 else 929 putc(255, fp); 930 } 931 932 if (bit > 1) 933 bit >>= 1; 934 else 935 { 936 cbyte = *cyan++; 937 lcbyte = *lcyan++; 938 mbyte = *magenta++; 939 lmbyte = *lmagenta++; 940 ybyte = *yellow++; 941 kbyte = *black++; 942 bit = 128; 943 } 944 } 945 } 946 else 947 { 948 unsigned char kb[BUFFER_SIZE]; 949 unsigned char cb[BUFFER_SIZE]; 950 unsigned char mb[BUFFER_SIZE]; 951 unsigned char lcb[BUFFER_SIZE]; 952 unsigned char lmb[BUFFER_SIZE]; 953 unsigned char yb[BUFFER_SIZE]; 954 unsigned char *kbuf = kb; 955 unsigned char *cbuf = cb; 956 unsigned char *mbuf = mb; 957 unsigned char *lcbuf = lcb; 958 unsigned char *lmbuf = lmb; 959 unsigned char *ybuf = yb; 960 stp_fold(black, IMAGE_WIDTH / 8, kbuf); 961 stp_fold(cyan, IMAGE_WIDTH / 8, cbuf); 962 stp_fold(magenta, IMAGE_WIDTH / 8, mbuf); 963 stp_fold(yellow, IMAGE_WIDTH / 8, ybuf); 964 stp_fold(lcyan, IMAGE_WIDTH / 8, lcbuf); 965 stp_fold(lmagenta, IMAGE_WIDTH / 8, lmbuf); 966 for (count = IMAGE_WIDTH, cbyte = *cbuf++, mbyte = *mbuf++, 967 ybyte = *ybuf++, kbyte = *kbuf++, lmbyte = *lmbuf++, 968 lcbyte = *lcyan++, shift = 6; 969 count > 0; 970 count --) 971 { 972 k = 255 * ((kbyte >> shift) & 3) / 3; 973 r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - 974 127 * ((lcbyte >> shift) & 3) / 3 - k; 975 g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - 976 127 * ((lmbyte >> shift) & 3) / 3 - k; 977 b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k; 978 979 if (r < 0) 980 putc(0, fp); 981 else 982 putc(r, fp); 983 984 if (g < 0) 985 putc(0, fp); 986 else 987 putc(g, fp); 988 989 if (b < 0) 990 putc(0, fp); 991 else 992 putc(b, fp); 993 994 if (shift > 0) 995 shift -= 2; 996 else 997 { 998 cbyte = *cbuf++; 999 mbyte = *mbuf++; 1000 ybyte = *ybuf++; 1001 kbyte = *kbuf++; 1002 lmbyte = *lmbuf++; 1003 lcbyte = *lcbuf++; 1004 shift = 6; 1005 } 1006 } 1007 } 1008} 1009 1010 1011/* 1012 * End of "$Id: testdither.c,v 1.49 2006/05/07 13:26:27 rlk Exp $". 1013 */ 1014