/*
* 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, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#define STPI_TESTDITHER
#include "../src/main/gutenprint-internal.h"
#include
#include
#include
#include
/*
* Definitions for dither test...
*/
#define MAX_IMAGE_WIDTH 5760 /* 8in * 720dpi */
#define MAX_IMAGE_HEIGHT 2880 /* 4in * 720dpi */
#define BUFFER_SIZE MAX_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 */
#define DITHER_CMYK 3 /* Dither photo pixels */
#define DITHER_PHOTO_CMYK 4 /* Dither photo pixels */
/*
* Globals...
*/
int image_type = IMAGE_MIXED;
int dither_type = DITHER_COLOR;
const char *dither_name = NULL;
int dither_bits = 1;
int write_image = 1;
int quiet = 0;
int dont_regenerate_input = 0;
int dimage_width = MAX_IMAGE_WIDTH;
int dimage_height = MAX_IMAGE_HEIGHT;
unsigned short white_line[MAX_IMAGE_WIDTH * 6],
black_line[MAX_IMAGE_WIDTH * 6],
color_line[MAX_IMAGE_WIDTH * 6],
random_line[MAX_IMAGE_WIDTH * 6];
static const char *dither_types[] = /* Different dithering modes */
{
"gray",
"color",
"photo",
"cmyk",
"photocmyk"
};
static const char *image_types[] = /* Different image types */
{
"mixed",
"white",
"black",
"colorimage",
"random"
};
#define SHADE(density, name) \
{ density, sizeof(name)/sizeof(stp_dotsize_t), name }
static const stp_dotsize_t single_dotsize[] =
{
{ 0x1, 1.0 }
};
static const stp_dotsize_t variable_dotsizes[] =
{
{ 0x1, 0.28 },
{ 0x2, 0.58 },
{ 0x3, 1.0 }
};
static const stp_shade_t normal_1bit_shades[] =
{
SHADE(1.0, single_dotsize)
};
static const stp_shade_t photo_1bit_shades[] =
{
SHADE(0.33, single_dotsize),
SHADE(1.0, single_dotsize)
};
static const stp_shade_t normal_2bit_shades[] =
{
SHADE(1.0, variable_dotsizes)
};
static const stp_shade_t photo_2bit_shades[] =
{
SHADE(0.33, variable_dotsizes),
SHADE(1.0, variable_dotsizes)
};
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.);
}
static void
writefunc(void *file, const char *buf, size_t bytes)
{
FILE *prn = (FILE *)file;
fwrite(buf, 1, bytes, prn);
}
static int
image_width(stp_image_t *image)
{
return dimage_width;
}
static stp_image_t theImage =
{
NULL,
NULL,
image_width,
NULL,
NULL,
NULL,
};
/*
* 'main()' - Test dithering code for performance measurement.
*/
static int
run_one_testdither(void)
{
int print_progress = 0;
int i; /* 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 */
unsigned short rgb[MAX_IMAGE_WIDTH * 6], /* RGB buffer */
gray[MAX_IMAGE_WIDTH]; /* Grayscale buffer */
FILE *fp = NULL; /* PPM/PGM output file */
char filename[1024]; /* Name of file */
stp_vars_t *v; /* Dither variables */
stp_parameter_t desc;
struct timeval tv1, tv2;
/*
* Initialise libgutenprint
*/
stp_init();
v = stp_vars_create();
stp_set_driver(v, "escp2-ex");
stp_describe_parameter(v, "DitherAlgorithm", &desc);
/*
* Setup the image and color functions...
*/
image_init();
stp_set_outfunc(v, writefunc);
stp_set_errfunc(v, writefunc);
stp_set_outdata(v, stdout);
stp_set_errdata(v, stderr);
/*
* Output the page...
*/
if (dither_name)
stp_set_string_parameter(v, "DitherAlgorithm", dither_name);
stp_set_string_parameter(v, "ChannelBitDepth", "8");
switch (dither_type)
{
case DITHER_GRAY:
stp_set_string_parameter(v, "PrintingMode", "BW");
stp_set_string_parameter(v, "InputImageType", "Grayscale");
break;
case DITHER_COLOR:
case DITHER_PHOTO:
stp_set_string_parameter(v, "PrintingMode", "Color");
stp_set_string_parameter(v, "InputImageType", "RGB");
break;
case DITHER_CMYK:
case DITHER_PHOTO_CMYK:
stp_set_string_parameter(v, "PrintingMode", "Color");
stp_set_string_parameter(v, "InputImageType", "CMYK");
break;
}
stp_dither_init(v, &theImage, dimage_width, 1, 1);
/*
* Now dither the "page"...
*/
switch (dither_type)
{
case DITHER_PHOTO:
stp_dither_add_channel(v, lcyan, STP_ECOLOR_C, 1);
stp_dither_add_channel(v, lmagenta, STP_ECOLOR_M, 1);
/* FALLTHROUGH */
case DITHER_COLOR:
stp_dither_add_channel(v, cyan, STP_ECOLOR_C, 0);
stp_dither_add_channel(v, magenta, STP_ECOLOR_M, 0);
stp_dither_add_channel(v, yellow, STP_ECOLOR_Y, 0);
break;
case DITHER_PHOTO_CMYK :
stp_dither_add_channel(v, lcyan, STP_ECOLOR_C, 1);
stp_dither_add_channel(v, lmagenta, STP_ECOLOR_M, 1);
/* FALLTHROUGH */
case DITHER_CMYK :
stp_dither_add_channel(v, cyan, STP_ECOLOR_C, 0);
stp_dither_add_channel(v, magenta, STP_ECOLOR_M, 0);
stp_dither_add_channel(v, yellow, STP_ECOLOR_Y, 0);
/* FALLTHROUGH */
case DITHER_GRAY:
stp_dither_add_channel(v, black, STP_ECOLOR_K, 0);
}
if (dither_type == DITHER_PHOTO)
stp_set_float_parameter(v, "GCRLower", 0.4 / dither_bits + 0.1);
else
stp_set_float_parameter(v, "GCRLower", 0.25 / dither_bits);
stp_set_float_parameter(v, "GCRUpper", .5);
switch (dither_type)
{
case DITHER_GRAY :
switch (dither_bits)
{
case 1 :
stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0);
break;
case 2 :
stp_dither_set_transition(v, 0.5);
stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0);
break;
}
break;
case DITHER_COLOR :
switch (dither_bits)
{
case 1 :
stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_1bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_1bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
break;
case 2 :
stp_dither_set_transition(v, 0.5);
stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_2bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_2bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
break;
}
break;
case DITHER_CMYK :
switch (dither_bits)
{
case 1 :
stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_1bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_1bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0);
break;
case 2 :
stp_dither_set_transition(v, 0.5);
stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_2bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_2bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0);
break;
}
break;
case DITHER_PHOTO :
switch (dither_bits)
{
case 1 :
stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_1bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_1bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
break;
case 2 :
stp_dither_set_transition(v, 0.7);
stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_2bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_2bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
break;
}
break;
case DITHER_PHOTO_CMYK :
switch (dither_bits)
{
case 1 :
stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_1bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_1bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0);
break;
case 2 :
stp_dither_set_transition(v, 0.7);
stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_2bit_shades, 1.0, 0.65);
stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_2bit_shades, 1.0, 0.6);
stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0);
break;
}
break;
}
stp_dither_set_ink_spread(v, 12 + dither_bits);
/*
* Open the PPM/PGM file...
*/
sprintf(filename, "%s-%s-%s-%dbit.%s", image_types[image_type],
dither_types[dither_type],
dither_name ? dither_name : desc.deflt.str, dither_bits,
(dither_type == DITHER_GRAY) ? "pgm" : "ppm");
stp_parameter_description_destroy(&desc);
if (isatty(1))
print_progress = 1;
if (print_progress && !quiet)
printf("%s ", filename);
if (write_image)
{
if ((fp = fopen(filename, "wb")) != NULL)
{
if (dither_type == DITHER_GRAY)
fputs("P5\n", fp);
else
fputs("P6\n", fp);
fprintf(fp, "%d\n%d\n255\n", dimage_width, dimage_height);
}
else
perror("Create");
}
(void) gettimeofday(&tv1, NULL);
for (i = 0; i < dimage_height; i ++)
{
if (print_progress && !quiet && (i & 63) == 0)
{
printf("\rProcessing row %d...", i);
fflush(stdout);
}
switch (dither_type)
{
case DITHER_GRAY :
image_get_row(gray, i);
stp_dither_internal(v, i, gray, 0, 0, NULL);
if (fp)
write_gray(fp, black);
break;
case DITHER_COLOR :
case DITHER_CMYK :
image_get_row(rgb, i);
stp_dither_internal(v, i, rgb, 0, 0, NULL);
if (fp)
write_color(fp, cyan, magenta, yellow, black);
break;
case DITHER_PHOTO :
case DITHER_PHOTO_CMYK :
image_get_row(rgb, i);
stp_dither_internal(v, i, rgb, 0, 0, NULL);
if (fp)
write_photo(fp, cyan, lcyan, magenta, lmagenta, yellow, black);
break;
}
}
(void) gettimeofday(&tv2, NULL);
stp_vars_destroy(v);
if (fp != NULL)
fclose(fp);
if (!quiet)
{
if (print_progress)
fputc('\r', stdout);
printf("%-30s %d pix %.3f sec %.2f pix/sec\n",
filename, dimage_width * dimage_height, compute_interval(&tv1, &tv2),
(float)(dimage_width * dimage_height) / compute_interval(&tv1, &tv2));
fflush(stdout);
}
return 0;
}
static int
run_testdither_from_cmdline(int argc, char **argv)
{
int i, j;
int status;
for (i = 1; i < argc; i ++)
{
if (strcmp(argv[i], "no-image") == 0)
{
write_image = 0;
continue;
}
if (strcmp(argv[i], "quiet") == 0)
{
quiet = 1;
continue;
}
if (strcmp(argv[i], "1-bit") == 0)
{
dither_bits = 1;
continue;
}
if (strcmp(argv[i], "2-bit") == 0)
{
dither_bits = 2;
continue;
}
if (strcmp(argv[i], "dont_regenerate_input") == 0)
{
dont_regenerate_input = 1;
continue;
}
for (j = 0; j < 5; j ++)
if (strcmp(argv[i], dither_types[j]) == 0)
break;
if (j < 5)
{
dither_type = j;
continue;
}
for (j = 0; j < 5; j ++)
if (strcmp(argv[i], image_types[j]) == 0)
break;
if (j < 5)
{
image_type = j;
continue;
}
dither_name = argv[i];
}
status = run_one_testdither();
if (status)
return 1;
else
return 0;
}
static int
run_standard_testdithers(void)
{
stp_vars_t *v = stp_vars_create();
stp_parameter_t desc;
int j;
int failures = 0;
int status;
stp_set_driver(v, "escp2-ex");
stp_describe_parameter(v, "DitherAlgorithm", &desc);
write_image = 0;
quiet = 1;
dont_regenerate_input = 1;
/* For automatic test purposes, this should suffice -- rlk 20171230 */
dimage_width = dimage_width / 8;
dimage_height = dimage_height / 8;
for (j = 0; j < stp_string_list_count(desc.bounds.str); j ++)
{
dither_name = stp_string_list_param(desc.bounds.str, j)->name;
if (strcmp(dither_name, "None") == 0)
continue;
printf("%s", dither_name);
fflush(stdout);
for (dither_bits = 1; dither_bits <= 2; dither_bits++)
for (dither_type = 0;
dither_type < sizeof(dither_types) / sizeof(const char *);
dither_type++)
for (image_type = 0;
image_type < sizeof(image_types) / sizeof(const char *);
image_type++)
{
status = run_one_testdither();
if (status)
{
printf("%s %d %s %s\n", dither_name, dither_bits,
dither_types[dither_type],
image_types[image_type]);
failures++;
}
else
printf(".");
fflush(stdout);
}
printf("\n");
fflush(stdout);
}
stp_parameter_description_destroy(&desc);
stp_vars_destroy(v);
return (failures ? 1 : 0);
}
int
main(int argc, char **argv)
{
stp_init();
if (argc == 1)
return run_standard_testdithers();
else
return run_testdither_from_cmdline(argc, argv);
}
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;
}
switch (dither_type)
{
case DITHER_GRAY:
memcpy(data, src, dimage_width * 2);
break;
case DITHER_COLOR:
memcpy(data, src, dimage_width * 6);
break;
case DITHER_CMYK:
memcpy(data, src, dimage_width * 8);
break;
case DITHER_PHOTO:
memcpy(data, src, dimage_width * 10);
break;
case DITHER_PHOTO_CMYK:
memcpy(data, src, dimage_width * 12);
break;
}
}
/*
* Much faster than built-in rand(), and quite good enough.
* From rand(3), attributed to POSIX.1-2001.
*/
static unsigned long next = 1;
static unsigned
myrand(void)
{
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 256);
}
static int image_is_initialized = 0;
void
image_init(void)
{
int i, j;
unsigned short *cptr,
*rptr;
if (image_is_initialized && dont_regenerate_input)
return;
image_is_initialized = 1;
/*
* Set the white and black line data...
*/
memset(white_line, 0, sizeof(white_line));
memset(black_line, 255, sizeof(black_line));
/*
* Fill in the color and random data...
*/
for (i = dimage_width, cptr = color_line, rptr = random_line; i > 0; i --)
{
/*
* Do 64 color or grayscale blocks over the line...
*/
j = i / (dimage_width / 64);
switch (dither_type)
{
case DITHER_GRAY:
*cptr++ = 65535 * j / 63;
*rptr++ = 65535 * myrand() / 255;
break;
case DITHER_COLOR:
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*cptr++ = 65535 * (j & 3) / 3;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
break;
case DITHER_CMYK:
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*cptr++ = 65535 * (j & 3) / 3;
*cptr++ = 65535 * j / 63;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
break;
case DITHER_PHOTO:
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*cptr++ = 65535 * (j & 3) / 3;
*cptr++ = 65535 * j / 63;
*cptr++ = 65535 * (j >> 4) / 3;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
break;
case DITHER_PHOTO_CMYK:
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*cptr++ = 65535 * (j & 3) / 3;
*cptr++ = 65535 * j / 63;
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
*rptr++ = 65535 * myrand() / 255;
break;
}
}
}
void
write_gray(FILE *fp,
unsigned char *black)
{
int count;
unsigned char byte,
bit,
shift;
if (dither_bits == 1)
{
for (count = dimage_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
{
unsigned char kb[BUFFER_SIZE];
unsigned char *kbuf = kb;
stp_fold(black, dimage_width / 8, kbuf);
for (count = dimage_width, byte = *kbuf++, shift = 6; count > 0; count --)
{
putc(255 - 255 * ((byte >> shift) & 3) / 3, fp);
if (shift > 0)
shift -= 2;
else
{
byte = *kbuf++;
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 = dimage_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
{
unsigned char kb[BUFFER_SIZE];
unsigned char cb[BUFFER_SIZE];
unsigned char mb[BUFFER_SIZE];
unsigned char yb[BUFFER_SIZE];
unsigned char *kbuf = kb;
unsigned char *cbuf = cb;
unsigned char *mbuf = mb;
unsigned char *ybuf = yb;
stp_fold(black, dimage_width / 8, kbuf);
stp_fold(cyan, dimage_width / 8, cbuf);
stp_fold(magenta, dimage_width / 8, mbuf);
stp_fold(yellow, dimage_width / 8, ybuf);
for (count = dimage_width, cbyte = *cbuf++, mbyte = *mbuf++,
ybyte = *ybuf++, kbyte = *kbuf++, 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 = *cbuf++;
mbyte = *mbuf++;
ybyte = *ybuf++;
kbyte = *kbuf++;
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 = dimage_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
{
unsigned char kb[BUFFER_SIZE];
unsigned char cb[BUFFER_SIZE];
unsigned char mb[BUFFER_SIZE];
unsigned char lcb[BUFFER_SIZE];
unsigned char lmb[BUFFER_SIZE];
unsigned char yb[BUFFER_SIZE];
unsigned char *kbuf = kb;
unsigned char *cbuf = cb;
unsigned char *mbuf = mb;
unsigned char *lcbuf = lcb;
unsigned char *lmbuf = lmb;
unsigned char *ybuf = yb;
stp_fold(black, dimage_width / 8, kbuf);
stp_fold(cyan, dimage_width / 8, cbuf);
stp_fold(magenta, dimage_width / 8, mbuf);
stp_fold(yellow, dimage_width / 8, ybuf);
stp_fold(lcyan, dimage_width / 8, lcbuf);
stp_fold(lmagenta, dimage_width / 8, lmbuf);
for (count = dimage_width, cbyte = *cbuf++, mbyte = *mbuf++,
ybyte = *ybuf++, kbyte = *kbuf++, lmbyte = *lmbuf++,
lcbyte = *lcyan++, 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 = *cbuf++;
mbyte = *mbuf++;
ybyte = *ybuf++;
kbyte = *kbuf++;
lmbyte = *lmbuf++;
lcbyte = *lcbuf++;
shift = 6;
}
}
}
}