diff options
Diffstat (limited to 'test/testdither.c')
-rw-r--r-- | test/testdither.c | 740 |
1 files changed, 740 insertions, 0 deletions
diff --git a/test/testdither.c b/test/testdither.c new file mode 100644 index 0000000..2733f8b --- /dev/null +++ b/test/testdither.c @@ -0,0 +1,740 @@ +/* + * "$Id: testdither.c,v 1.11 2001/09/02 13:30:27 rlk Exp $" + * + * Test/profiling program for dithering code. + * + * Copyright 1997-2000 Michael Sweet (mike@easysw.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifdef INCLUDE_GIMP_PRINT_H +#include INCLUDE_GIMP_PRINT_H +#else +#include <gimp-print/gimp-print.h> +#endif +#include "../lib/libprintut.h" +#include "../src/main/gimp-print-internal.h" +#include <stdio.h> +#include <sys/time.h> +#include <unistd.h> + +/* + * NOTE: writing of 2-bit dither images is currently broken due to the + * separated planes generated by the dither functions. + */ + + +/* + * Definitions for dither test... + */ + +#define IMAGE_WIDTH 5760 /* 8in * 720dpi */ +#define IMAGE_HEIGHT 720 /* 4in * 720dpi */ +#define BUFFER_SIZE IMAGE_WIDTH + +#define IMAGE_MIXED 0 /* Mix of line types */ +#define IMAGE_WHITE 1 /* All white image */ +#define IMAGE_BLACK 2 /* All black image */ +#define IMAGE_COLOR 3 /* All color image */ +#define IMAGE_RANDOM 4 /* All random image */ + +#define DITHER_GRAY 0 /* Dither grayscale pixels */ +#define DITHER_COLOR 1 /* Dither color pixels */ +#define DITHER_PHOTO 2 /* Dither photo pixels */ + + +/* + * Globals... + */ + +int image_type = IMAGE_MIXED; +int dither_type = DITHER_COLOR; +int dither_bits = 1; +unsigned short white_line[IMAGE_WIDTH * 3], + black_line[IMAGE_WIDTH * 3], + color_line[IMAGE_WIDTH * 3], + random_line[IMAGE_WIDTH * 3]; + + +stp_simple_dither_range_t normal_1bit_ranges[] = +{ + { 1.0, 0x1, 1, 1 } +}; + +stp_simple_dither_range_t normal_2bit_ranges[] = +{ + { 0.45, 0x1, 1, 1 }, + { 0.68, 0x2, 1, 2 }, + { 1.0, 0x3, 1, 3 } +}; + +stp_simple_dither_range_t photo_1bit_ranges[] = +{ + { 0.33, 0x1, 0, 1 }, + { 1.0, 0x1, 1, 1 } +}; + +stp_simple_dither_range_t photo_2bit_ranges[] = +{ + { 0.15, 0x1, 0, 1 }, + { 0.227, 0x2, 0, 2 }, + { 0.45, 0x1, 1, 1 }, + { 0.68, 0x2, 1, 2 }, + { 1.0, 0x3, 1, 3 } +}; + + +double compute_interval(struct timeval *tv1, struct timeval *tv2); +void image_init(void); +void image_get_row(unsigned short *data, int row); +void write_gray(FILE *fp, unsigned char *black); +void write_color(FILE *fp, unsigned char *cyan, unsigned char *magenta, + unsigned char *yellow, unsigned char *black); +void write_photo(FILE *fp, unsigned char *cyan, unsigned char *lcyan, + unsigned char *magenta, unsigned char *lmagenta, + unsigned char *yellow, unsigned char *black); + + +double +compute_interval(struct timeval *tv1, struct timeval *tv2) +{ + return ((double) tv2->tv_sec + (double) tv2->tv_usec / 1000000.) - + ((double) tv1->tv_sec + (double) tv1->tv_usec / 1000000.); +} + +/* + * 'main()' - Test dithering code for performance measurement. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j; /* Looping vars */ + unsigned char black[BUFFER_SIZE], /* Black bitmap data */ + cyan[BUFFER_SIZE], /* Cyan bitmap data */ + magenta[BUFFER_SIZE], /* Magenta bitmap data */ + lcyan[BUFFER_SIZE], /* Light cyan bitmap data */ + lmagenta[BUFFER_SIZE], /* Light magenta bitmap data */ + yellow[BUFFER_SIZE]; /* Yellow bitmap data */ + void *dither; /* Dither data */ + unsigned short rgb[IMAGE_WIDTH * 3], /* RGB buffer */ + gray[IMAGE_WIDTH]; /* Grayscale buffer */ + int write_image; /* Write the image to disk? */ + FILE *fp; /* PPM/PGM output file */ + char filename[1024]; /* Name of file */ + stp_vars_t v; /* Dither variables */ + static const char *dither_types[] = /* Different dithering modes */ + { + "gray", + "color", + "photo" + }; + static const char *image_types[] = /* Different image types */ + { + "mixed", + "white", + "black", + "color", + "random" + }; + struct timeval tv1, tv2; + + /* + * Initialise libgimpprint + */ + + stp_init(); + v = stp_allocate_vars(); + + /* + * Get command-line args... + */ + + write_image = 1; + + for (i = 1; i < argc; i ++) + { + if (strcmp(argv[i], "no-image") == 0) + { + write_image = 0; + continue; + } + + if (strcmp(argv[i], "1-bit") == 0) + { + dither_bits = 1; + continue; + } + + if (strcmp(argv[i], "2-bit") == 0) + { + dither_bits = 2; + continue; + } + + for (j = 0; j < 3; j ++) + if (strcmp(argv[i], dither_types[j]) == 0) + break; + + if (j < 3) + { + dither_type = j; + continue; + } + + for (j = 0; j < 5; j ++) + if (strcmp(argv[i], image_types[j]) == 0) + break; + + if (j < 3) + { + image_type = j; + continue; + } + + printf("Unknown option \"%s\" ignored!\n", argv[i]); + } + + /* + * Setup the image and color functions... + */ + + image_init(); + + /* + * Output the page... + */ + + stp_set_dither_algorithm(v, "Adaptive Hybrid"); + + dither = stp_init_dither(IMAGE_WIDTH, IMAGE_WIDTH, 1, 1, v); + + for (i = 0; i < NCOLORS; i++) + stp_dither_set_black_level(dither, i, 1.0); + + if (dither_type == DITHER_PHOTO) + stp_dither_set_black_lower(dither, 0.4 / dither_bits + 0.1); + else + stp_dither_set_black_lower(dither, 0.25 / dither_bits); + + stp_dither_set_black_upper(dither, 0.5); + + switch (dither_type) + { + case DITHER_GRAY : + switch (dither_bits) + { + case 1 : + stp_dither_set_ranges(dither, ECOLOR_K, 1, normal_1bit_ranges, 1.0); + break; + case 2 : + stp_dither_set_transition(dither, 0.5); + stp_dither_set_ranges(dither, ECOLOR_K, 3, normal_2bit_ranges, 1.0); + break; + } + break; + case DITHER_COLOR : + switch (dither_bits) + { + case 1 : + stp_dither_set_ranges(dither, ECOLOR_C, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 1, normal_1bit_ranges, 1.0); + break; + case 2 : + stp_dither_set_transition(dither, 0.5); + stp_dither_set_ranges(dither, ECOLOR_C, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 3, normal_2bit_ranges, 1.0); + break; + } + break; + case DITHER_PHOTO : + switch (dither_bits) + { + case 1 : + stp_dither_set_ranges(dither, ECOLOR_C, 2, photo_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 2, photo_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 1, normal_1bit_ranges, 1.0); + break; + case 2 : + stp_dither_set_transition(dither, 0.7); + stp_dither_set_ranges(dither, ECOLOR_C, 5, photo_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 5, photo_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 3, normal_2bit_ranges, 1.0); + break; + } + break; + } + + stp_dither_set_ink_spread(dither, 12 + dither_bits); + stp_dither_set_density(dither, 1.0); + + /* + * Open the PPM/PGM file... + */ + + if (write_image) + { + sprintf(filename, "%s-%s-%dbit.%s", image_types[image_type], + dither_types[dither_type], dither_bits, + dither_type == DITHER_GRAY ? "pgm" : "ppm"); + + if ((fp = fopen(filename, "wb")) != NULL) + { + puts(filename); + if (dither_type == DITHER_GRAY) + fputs("P5\n", fp); + else + fputs("P6\n", fp); + + fprintf(fp, "%d\n%d\n255\n", IMAGE_WIDTH, IMAGE_HEIGHT); + } + else + perror(filename); + } + else + fp = NULL; + + /* + * Now dither the "page"... + */ + + (void) gettimeofday(&tv1, NULL); + + for (i = 0; i < IMAGE_HEIGHT; i ++) + { + if ((i & 15) == 0) + { + printf("\rProcessing row %d...", i); + fflush(stdout); + } + + switch (dither_type) + { + case DITHER_GRAY : + image_get_row(gray, i); + stp_dither(gray, i, dither, 0, 0, 0, 0, 0, 0, black, 0, 0); + if (fp) + write_gray(fp, black); + break; + case DITHER_COLOR : + image_get_row(rgb, i); + stp_dither(rgb, i, dither, cyan, 0, magenta, 0, + yellow, 0, black, 0, 0); + if (fp) + write_color(fp, cyan, magenta, yellow, black); + break; + case DITHER_PHOTO : + image_get_row(rgb, i); + stp_dither(rgb, i, dither, cyan, lcyan, magenta, lmagenta, + yellow, 0, black, 0, 0); + if (fp) + write_photo(fp, cyan, lcyan, magenta, lmagenta, yellow, black); + break; + } + } + + (void) gettimeofday(&tv2, NULL); + + stp_free_dither(dither); + + if (fp != NULL) + fclose(fp); + + printf("\rTotal dither time for %d pixels is %.3f seconds, or %.2f pixels/sec.\n", + IMAGE_WIDTH * IMAGE_HEIGHT, compute_interval(&tv1, &tv2), + (float)(IMAGE_WIDTH * IMAGE_HEIGHT) / compute_interval(&tv1, &tv2)); + return 0; +} + + +void +image_get_row(unsigned short *data, + int row) +{ + unsigned short *src; + + + switch (image_type) + { + case IMAGE_MIXED : + switch ((row / 100) & 3) + { + case 0 : + src = white_line; + break; + case 1 : + src = color_line; + break; + case 2 : + src = black_line; + break; + case 3 : + default: + src = random_line; + break; + } + break; + case IMAGE_WHITE : + src = white_line; + break; + case IMAGE_BLACK : + src = black_line; + break; + case IMAGE_COLOR : + src = color_line; + break; + case IMAGE_RANDOM : + default: + src = random_line; + break; + } + + if (dither_type == DITHER_GRAY) + memcpy(data, src, IMAGE_WIDTH * 2); + else + memcpy(data, src, IMAGE_WIDTH * 6); +} + + +void +image_init(void) +{ + int i, j; + unsigned short *cptr, + *rptr; + + + /* + * Set the white and black line data... + */ + + memset(white_line, 255, sizeof(white_line)); + memset(black_line, 0, sizeof(black_line)); + + /* + * Fill in the color and random data... + */ + + for (i = IMAGE_WIDTH, cptr = color_line, rptr = random_line; i > 0; i --) + { + /* + * Do 64 color or grayscale blocks over the line... + */ + + j = i / (IMAGE_WIDTH / 64); + + if (dither_type == DITHER_GRAY) + *cptr++ = 65535 * j / 63; + else + { + *cptr++ = 65535 * (j >> 4) / 3; + *cptr++ = 65535 * ((j >> 2) & 3) / 3; + *cptr++ = 65535 * (j & 3) / 3; + } + + /* + * Do random colors over the line... + */ + + *rptr++ = 65535 * (rand() & 255) / 255; + if (dither_type != DITHER_GRAY) + { + *rptr++ = 65535 * (rand() & 255) / 255; + *rptr++ = 65535 * (rand() & 255) / 255; + } + } +} + + +void +write_gray(FILE *fp, + unsigned char *black) +{ + int count; + unsigned char byte, + bit, + shift; + + + if (dither_bits == 1) + { + for (count = IMAGE_WIDTH, byte = *black++, bit = 128; count > 0; count --) + { + if (byte & bit) + putc(0, fp); + else + putc(255, fp); + + if (bit > 1) + bit >>= 1; + else + { + byte = *black++; + bit = 128; + } + } + } + else + { + for (count = IMAGE_WIDTH, byte = *black++, shift = 6; count > 0; count --) + { + putc(255 - 255 * ((byte >> shift) & 3) / 3, fp); + + if (shift > 0) + shift -= 2; + else + { + byte = *black++; + shift = 6; + } + } + } +} + + +void +write_color(FILE *fp, + unsigned char *cyan, + unsigned char *magenta, + unsigned char *yellow, + unsigned char *black) +{ + int count; + unsigned char cbyte, + mbyte, + ybyte, + kbyte, + bit, + shift; + int r, g, b, k; + + + if (dither_bits == 1) + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, mbyte = *magenta++, + ybyte = *yellow++, kbyte = *black++, bit = 128; + count > 0; + count --) + { + if (kbyte & bit) + { + putc(0, fp); + putc(0, fp); + putc(0, fp); + } + else + { + if (cbyte & bit) + putc(0, fp); + else + putc(255, fp); + + if (mbyte & bit) + putc(0, fp); + else + putc(255, fp); + + if (ybyte & bit) + putc(0, fp); + else + putc(255, fp); + } + + if (bit > 1) + bit >>= 1; + else + { + cbyte = *cyan++; + mbyte = *magenta++; + ybyte = *yellow++; + kbyte = *black++; + bit = 128; + } + } + } + else + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, mbyte = *magenta++, + ybyte = *yellow++, kbyte = *black++, shift = 6; + count > 0; + count --) + { + k = 255 * ((kbyte >> shift) & 3) / 3; + r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - k; + g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - k; + b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k; + + if (r < 0) + putc(0, fp); + else + putc(r, fp); + + if (g < 0) + putc(0, fp); + else + putc(g, fp); + + if (b < 0) + putc(0, fp); + else + putc(b, fp); + + if (shift > 0) + shift -= 2; + else + { + cbyte = *cyan++; + mbyte = *magenta++; + ybyte = *yellow++; + kbyte = *black++; + shift = 6; + } + } + } +} + + +void +write_photo(FILE *fp, + unsigned char *cyan, + unsigned char *lcyan, + unsigned char *magenta, + unsigned char *lmagenta, + unsigned char *yellow, + unsigned char *black) +{ + int count; + unsigned char cbyte, + lcbyte, + mbyte, + lmbyte, + ybyte, + kbyte, + bit, + shift; + int r, g, b, k; + + + if (dither_bits == 1) + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, lcbyte = *lcyan++, + mbyte = *magenta++, lmbyte = *lmagenta++, + ybyte = *yellow++, kbyte = *black++, bit = 128; + count > 0; + count --) + { + if (kbyte & bit) + { + putc(0, fp); + putc(0, fp); + putc(0, fp); + } + else + { + if (cbyte & bit) + putc(0, fp); + else if (lcbyte & bit) + putc(127, fp); + else + putc(255, fp); + + if (mbyte & bit) + putc(0, fp); + else if (lmbyte & bit) + putc(127, fp); + else + putc(255, fp); + + if (ybyte & bit) + putc(0, fp); + else + putc(255, fp); + } + + if (bit > 1) + bit >>= 1; + else + { + cbyte = *cyan++; + lcbyte = *lcyan++; + mbyte = *magenta++; + lmbyte = *lmagenta++; + ybyte = *yellow++; + kbyte = *black++; + bit = 128; + } + } + } + else + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, lcbyte = *lcyan++, + mbyte = *magenta++, lmbyte = *lmagenta++, + ybyte = *yellow++, kbyte = *black++, shift = 6; + count > 0; + count --) + { + k = 255 * ((kbyte >> shift) & 3) / 3; + r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - + 127 * ((lcbyte >> shift) & 3) / 3 - k; + g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - + 127 * ((lmbyte >> shift) & 3) / 3 - k; + b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k; + + if (r < 0) + putc(0, fp); + else + putc(r, fp); + + if (g < 0) + putc(0, fp); + else + putc(g, fp); + + if (b < 0) + putc(0, fp); + else + putc(b, fp); + + if (shift > 0) + shift -= 2; + else + { + cbyte = *cyan++; + lcbyte = *lcyan++; + mbyte = *magenta++; + lmbyte = *lmagenta++; + ybyte = *yellow++; + kbyte = *black++; + shift = 6; + } + } + } +} + + +/* + * End of "$Id: testdither.c,v 1.11 2001/09/02 13:30:27 rlk Exp $". + */ |