#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>
#define IMAGE_WIDTH 5760
#define IMAGE_HEIGHT 720
#define BUFFER_SIZE IMAGE_WIDTH
#define IMAGE_MIXED 0
#define IMAGE_WHITE 1
#define IMAGE_BLACK 2
#define IMAGE_COLOR 3
#define IMAGE_RANDOM 4
#define DITHER_GRAY 0
#define DITHER_COLOR 1
#define DITHER_PHOTO 2
#define DITHER_MONOCHROME 3
#define DITHER_CMYK 4
#define DITHER_PHOTO_CMYK 5
int image_type = IMAGE_MIXED;
int dither_type = DITHER_COLOR;
const char *dither_name = NULL;
int dither_bits = 1;
unsigned short white_line[IMAGE_WIDTH * 4],
black_line[IMAGE_WIDTH * 4],
color_line[IMAGE_WIDTH * 4],
random_line[IMAGE_WIDTH * 4];
stp_simple_dither_range_t normal_1bit_ranges[] =
{
{ 1.0, 0x1, 0, 1 }
};
stp_simple_dither_range_t normal_2bit_ranges[] =
{
{ 0.45, 0x1, 0, 1 },
{ 0.68, 0x2, 0, 2 },
{ 1.0, 0x3, 0, 3 }
};
stp_simple_dither_range_t photo_1bit_ranges[] =
{
{ 0.33, 0x1, 1, 1 },
{ 1.0, 0x1, 0, 1 }
};
stp_simple_dither_range_t photo_2bit_ranges[] =
{
{ 0.15, 0x1, 1, 1 },
{ 0.227, 0x2, 1, 2 },
{ 0.45, 0x1, 0, 1 },
{ 0.68, 0x2, 0, 2 },
{ 1.0, 0x3, 0, 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.);
}
static void
writefunc(void *file, const char *buf, size_t bytes)
{
FILE *prn = (FILE *)file;
fwrite(buf, 1, bytes, prn);
}
int
main(int argc,
char *argv[])
{
int i, j;
unsigned char black[BUFFER_SIZE],
cyan[BUFFER_SIZE],
magenta[BUFFER_SIZE],
lcyan[BUFFER_SIZE],
lmagenta[BUFFER_SIZE],
yellow[BUFFER_SIZE];
void *dither;
unsigned short rgb[IMAGE_WIDTH * 4],
gray[IMAGE_WIDTH];
int write_image;
FILE *fp = NULL;
char filename[1024];
stp_vars_t v;
static const char *dither_types[] =
{
"gray",
"color",
"photo",
"monochrome",
"cmyk",
"photocmyk"
};
static const char *image_types[] =
{
"mixed",
"white",
"black",
"colorimage",
"random"
};
struct timeval tv1, tv2;
stp_dither_data_t *dt;
stp_init();
v = stp_allocate_vars();
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 < 6; j ++)
if (strcmp(argv[i], dither_types[j]) == 0)
break;
if (j < 6)
{
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;
}
for (j = 0; j < stp_dither_algorithm_count(); j ++)
if (strcmp(argv[i], stp_dither_algorithm_name(j)) == 0)
break;
if (j < stp_dither_algorithm_count())
{
dither_name = stp_dither_algorithm_name(j);
continue;
}
printf("Unknown option \"%s\" ignored!\n", argv[i]);
}
image_init();
stp_set_outfunc(v, writefunc);
stp_set_errfunc(v, writefunc);
stp_set_outdata(v, stdout);
stp_set_errdata(v, stderr);
if (dither_name)
stp_set_dither_algorithm(v, dither_name);
switch (dither_type)
{
case DITHER_GRAY:
stp_set_output_type(v, OUTPUT_GRAY);
break;
case DITHER_MONOCHROME:
stp_set_output_type(v, OUTPUT_MONOCHROME);
break;
case DITHER_COLOR:
case DITHER_PHOTO:
stp_set_output_type(v, OUTPUT_COLOR);
break;
case DITHER_CMYK:
case DITHER_PHOTO_CMYK:
stp_set_output_type(v, OUTPUT_RAW_CMYK);
break;
}
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 :
case DITHER_MONOCHROME :
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 :
case DITHER_CMYK :
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 :
case DITHER_PHOTO_CMYK :
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);
sprintf(filename, "%s-%s-%s-%dbit.%s", image_types[image_type],
dither_types[dither_type],
dither_name ? dither_name : stp_default_dither_algorithm(),
dither_bits,
(dither_type == DITHER_GRAY || dither_type == DITHER_MONOCHROME) ?
"pgm" : "ppm");
printf("%s ", filename);
if (write_image)
{
if ((fp = fopen(filename, "wb")) != NULL)
{
puts(filename);
if (dither_type == DITHER_GRAY || dither_type == DITHER_MONOCHROME)
fputs("P5\n", fp);
else
fputs("P6\n", fp);
fprintf(fp, "%d\n%d\n255\n", IMAGE_WIDTH, IMAGE_HEIGHT);
}
else
perror("Create");
}
dt = stp_create_dither_data();
switch (dither_type)
{
case DITHER_PHOTO:
case DITHER_PHOTO_CMYK :
stp_add_channel(dt, lcyan, ECOLOR_C, 1);
stp_add_channel(dt, lmagenta, ECOLOR_M, 1);
case DITHER_COLOR:
case DITHER_CMYK :
stp_add_channel(dt, cyan, ECOLOR_C, 0);
stp_add_channel(dt, magenta, ECOLOR_M, 0);
stp_add_channel(dt, yellow, ECOLOR_Y, 0);
case DITHER_GRAY:
case DITHER_MONOCHROME:
stp_add_channel(dt, black, ECOLOR_K, 0);
}
(void) gettimeofday(&tv1, NULL);
for (i = 0; i < IMAGE_HEIGHT; i ++)
{
if ((i & 63) == 0)
{
printf("\rProcessing row %d...", i);
fflush(stdout);
}
switch (dither_type)
{
case DITHER_GRAY :
case DITHER_MONOCHROME :
image_get_row(gray, i);
stp_dither(gray, i, dither, dt, 0, 0);
if (fp)
write_gray(fp, black);
break;
case DITHER_COLOR :
case DITHER_CMYK :
image_get_row(rgb, i);
stp_dither(rgb, i, dither, dt, 0, 0);
if (fp)
write_color(fp, cyan, magenta, yellow, black);
break;
case DITHER_PHOTO :
case DITHER_PHOTO_CMYK :
image_get_row(rgb, i);
stp_dither(rgb, i, dither, dt, 0, 0);
if (fp)
write_photo(fp, cyan, lcyan, magenta, lmagenta, yellow, black);
break;
}
}
(void) gettimeofday(&tv2, NULL);
stp_free_dither_data(dt);
stp_free_dither(dither);
if (fp != NULL)
fclose(fp);
printf("\r%-40s Total dither time for %d pixels is %.3f seconds, or %.2f pixels/sec.\n",
filename, 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;
}
switch (dither_type)
{
case DITHER_GRAY:
case DITHER_MONOCHROME:
memcpy(data, src, IMAGE_WIDTH * 2);
break;
case DITHER_COLOR:
case DITHER_PHOTO:
memcpy(data, src, IMAGE_WIDTH * 6);
break;
case DITHER_CMYK:
case DITHER_PHOTO_CMYK:
memcpy(data, src, IMAGE_WIDTH * 8);
break;
}
}
void
image_init(void)
{
int i, j;
unsigned short *cptr,
*rptr;
memset(white_line, 0, sizeof(white_line));
memset(black_line, 255, sizeof(black_line));
for (i = IMAGE_WIDTH, cptr = color_line, rptr = random_line; i > 0; i --)
{
j = i / (IMAGE_WIDTH / 64);
switch (dither_type)
{
case DITHER_GRAY:
case DITHER_MONOCHROME:
*cptr++ = 65535 * j / 63;
*rptr++ = 65535 * (rand() & 255) / 255;
break;
case DITHER_COLOR:
case DITHER_PHOTO:
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*cptr++ = 65535 * (j & 3) / 3;
*rptr++ = 65535 * (rand() & 255) / 255;
*rptr++ = 65535 * (rand() & 255) / 255;
*rptr++ = 65535 * (rand() & 255) / 255;
break;
case DITHER_CMYK:
case DITHER_PHOTO_CMYK:
*cptr++ = 65535 * (j >> 4) / 3;
*cptr++ = 65535 * ((j >> 2) & 3) / 3;
*cptr++ = 65535 * (j & 3) / 3;
*cptr++ = 65535 * j / 63;
*rptr++ = 65535 * (rand() & 255) / 255;
*rptr++ = 65535 * (rand() & 255) / 255;
*rptr++ = 65535 * (rand() & 255) / 255;
*rptr++ = 65535 * (rand() & 255) / 255;
break;
}
}
}
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
{
unsigned char kb[BUFFER_SIZE];
unsigned char *kbuf = kb;
stp_fold(black, IMAGE_WIDTH / 8, kbuf);
for (count = IMAGE_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 = 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
{
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, IMAGE_WIDTH / 8, kbuf);
stp_fold(cyan, IMAGE_WIDTH / 8, cbuf);
stp_fold(magenta, IMAGE_WIDTH / 8, mbuf);
stp_fold(yellow, IMAGE_WIDTH / 8, ybuf);
for (count = IMAGE_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 = 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
{
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, IMAGE_WIDTH / 8, kbuf);
stp_fold(cyan, IMAGE_WIDTH / 8, cbuf);
stp_fold(magenta, IMAGE_WIDTH / 8, mbuf);
stp_fold(yellow, IMAGE_WIDTH / 8, ybuf);
stp_fold(lcyan, IMAGE_WIDTH / 8, lcbuf);
stp_fold(lmagenta, IMAGE_WIDTH / 8, lmbuf);
for (count = IMAGE_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;
}
}
}
}