Color Dither (ver 1.1)
sources-request at panda.UUCP
sources-request at panda.UUCP
Sun May 18 07:31:30 AEST 1986
Mod.sources: Volume 5, Issue 3
Submitted by: talcott!seismo!s3sun!sdcsvax!hutch (Jim Hutchison)
This works well on a sun, it converts 24bit images stored in
3 files into a screen image.
The usage is: display filename [wide [high]]
"filename" is assumed to be a name for 3 files filename{R,G,B} The
default width is set to 512. The path has a maximum length(1024
currently). Height defaults to width unless specified. The program
can be configured for various color limitations (and has been tested at
1/1/1, 2/2/1, and 3/3/2 bits of RGB) this fits in with some rgb
printers, the Amiga, and the Sun color frame buffer respectively.
This code was posted to net.sources a few weeks ago, but has improved
in usability and readability since then (not to mention speed and
configurability).
Jim Hutchison hutch at sdcsvax.UUCP
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# tcd.c
# This archive created: Tue May 13 03:36:33 1986
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'tcd.c'
then
echo shar: "will not over-write existing file 'tcd.c'"
else
cat << \SHAR_EOF > 'tcd.c'
#include <stdio.h>
#include <sys/file.h>
#include <pixrect/pixrect_hs.h>
/*
* Dither! Color dither a U.S.C. tape image.
*
* Original Tape code by Brian Kantor.
*
* The dithering is the product of madness and extrapolation
* from the concepts employed for black and white dithers,
* Jim Hutchison. Presumes 8bit bytes.
*/
#define LARGEST (0xff) /* 8 bits per color */
#define UNUSED_BITS 0 /* unused bits */
#define R_BITS 3 /* Bits of red */
#define R_ERR (8 - R_BITS) /* Bits of error, from true */
#define R_SHIFT (8 - R_BITS) /* shift to get usefull bits */
#define R_MASK (LARGEST >> R_BITS) /* masked off bits */
#define R_NEXT (R_MASK - 1) /* base_color + next = left */
#define R_TOP (LARGEST & ~R_MASK) /* maximal value, red */
#define R_NVAL (LARGEST >> R_SHIFT) /* shades of red + black */
#define R_MAP 0x07 /* mask to get color table */
#define G_BITS 3 /* Bits of green */
#define G_ERR (8 - G_BITS) /* Bits of error, from true */
#define G_SHIFT (8 - G_BITS) /* shift to get usefull bits */
#define G_MASK (LARGEST >> G_BITS) /* masked off bits */
#define G_NEXT (G_MASK - 1) /* base_color + next = left */
#define G_TOP (LARGEST & ~G_MASK) /* maximal value, green */
#define G_NVAL (LARGEST >> G_SHIFT) /* shades of green + black */
#define G_MAP (0x07 << 3) /* mask to get color table */
#define B_BITS 2 /* Bits of blue */
#define B_ERR (8 - B_BITS) /* Bits of error, from true */
#define B_SHIFT (8 - B_BITS) /* shift to get usefull bits */
#define B_MASK (LARGEST >> B_BITS) /* masked off bits */
#define B_NEXT (B_MASK - 1) /* base_color + next = left */
#define B_TOP (LARGEST & ~B_MASK) /* maximal value, blue */
#define B_NVAL (LARGEST >> B_SHIFT) /* shades of blue + black */
#define B_MAP (0x03 << 6) /* mask to get color table */
/*
* 2(4(8)) by 2(4(8)) ordered dither, it all hinges on this dither,
* and the color-table. Note that dithers larger than 4x4
* require changes in lower code.
*/
#ifdef LARGE_DITHER
#define DSIZE 4 /* must be a power of 2 */
#define DITH_LOG 4 /* log[2](DSIZE*DSIZE) */
#define DMASK DSIZE-1 /* Dither mask to get position in dither */
short dither[DSIZE][DSIZE] = {
0, 8, 3, 11,
12, 4, 15, 7,
2, 10, 1, 9,
14, 6, 13, 5
};
#else /* LARGE_DITHER */
#define DSIZE 2 /* must be a power of 2 */
#define DITH_LOG 2 /* log[2](DSIZE*DSIZE) */
#define DMASK DSIZE-1 /* Dither mask to get position in dither */
short dither[DSIZE][DSIZE] = {
0, 3,
2, 1
};
#endif /* LARGE_DITHER */
/* Huge dither to use with the 2 bit color, blue
*/
#ifdef BLUE_DITHER
#define BDSIZE 8 /* must be a power of 2 */
#define BDITH_LOG 6 /* log[2](BDSIZE*BDSIZE) */
#define BDMASK BDSIZE-1/* Dither mask to get position in dither */
short bdither[BDSIZE][BDSIZE] = {
0, 32, 12, 44, 3, 35, 15, 47,
48, 16, 60, 28, 51, 19, 63, 31,
8, 40, 4, 36, 11, 43, 7, 39,
56, 24, 52, 20, 59, 27, 55, 23,
2, 34, 14, 46, 1, 33, 13, 45,
50, 18, 62, 30, 49, 17, 61, 29,
10, 42, 6, 38, 9, 41, 5, 37,
58, 26, 54, 22, 57, 25, 53, 21
};
#else /* BLUE_DITHER */
#define BDITH_LOG DITH_LOG
#endif /* BLUE_DITHER */
/*
* Determine if we have more error than we have dither, and
* give the number of bits we shall have to shift down.
*/
#if (R_ERR - DITH_LOG) > 0
#define R_ISHIFT (R_ERR - DITH_LOG)
#else
#define R_ISHIFT (0)
#endif
#if (G_ERR - DITH_LOG) > 0
#define G_ISHIFT (G_ERR - DITH_LOG)
#else
#define G_ISHIFT (0)
#endif
#if (B_ERR - BDITH_LOG) > 0
#define B_ISHIFT (B_ERR - BDITH_LOG)
#else
#define B_ISHIFT (0)
#endif
/*
* Image/colormap definitions.
*/
#define MAPSIZE 256 /* size of pallet */
#define COLORS 256 /* number of colors */
#define IMAGESIZE 512 /* size of tape image */
#define IMAGE_VOL (IMAGESIZE*IMAGESIZE) /* volume of image */
#define MAXPATH 1024 /* max length of filename */
struct pixrect *display;
struct pixrect *memory_frame;
/* for palette (sun) generation */
unsigned char red[MAPSIZE], grn[MAPSIZE], blu[MAPSIZE];
/* shade tables (for speed) */
static unsigned int r_base_right[COLORS];
static unsigned int r_base_left[COLORS];
static unsigned int r_dval[COLORS];
static unsigned char g_base_right[COLORS];
static unsigned char g_base_left[COLORS];
static unsigned char g_dval[COLORS];
static unsigned char b_base_right[COLORS];
static unsigned char b_base_left[COLORS];
static unsigned char b_dval[COLORS];
/* nasty procedures */
int
min(a,b)
int a,b;
{
return((a > b)? b : a);
}
int
max(a,b)
int a,b;
{
return((a > b)? a : b);
}
main(argc,argv)
int argc;
char **argv;
{
register unsigned int color, dith_value;
register unsigned int r_color, g_color, b_color;
register unsigned char *pr, *pg, *pb;
#ifdef BLUE_DITHER
unsigned int b_dith_value;
#endif /* BLUE_DITHER */
int x_imagesize, y_imagesize, image_vol;
int fr, fg, fb;
int i, plen;
int x, y;
char buf[MAXPATH];
unsigned char *picture, *pict_row; /* keep row to avoid padding problems */
int row_bytes; /* bytes per scan-line */
if (argc < 2) {
fprintf(stderr, "Usage: %s rgb-imagefile [hsize] [vsize]\n", argv[0]);
exit(-1);
}
if (argc > 2) {
x_imagesize = atoi(argv[2]);
if (argc > 3) {
y_imagesize = atoi(argv[3]);
} else {
y_imagesize = x_imagesize;
}
image_vol = y_imagesize * x_imagesize;
pr = (unsigned char *) malloc(image_vol * sizeof(unsigned char));
pg = (unsigned char *) malloc(image_vol * sizeof(unsigned char));
pb = (unsigned char *) malloc(image_vol * sizeof(unsigned char));
} else {
x_imagesize = y_imagesize = IMAGESIZE;
pr = (unsigned char *) malloc(IMAGE_VOL);
pg = (unsigned char *) malloc(IMAGE_VOL);
pb = (unsigned char *) malloc(IMAGE_VOL);
image_vol = IMAGE_VOL;
}
printf("high %d wide %d vol %d\n", y_imagesize, x_imagesize, image_vol);
strcpy(buf,argv[1]);
plen = strlen(buf);
buf[plen] = 'R';
fr = open(buf, O_RDONLY, 0444);
if (fr < 0) {
perror(buf);
exit(1);
}
buf[plen] = 'G';
fg = open(buf, O_RDONLY, 0444);
if (fg == 0) {
perror(buf);
exit(1);
}
buf[plen] = 'B';
fb = open(buf, O_RDONLY, 0444);
if (fb < 0) {
perror(buf);
exit(1);
}
display = pr_open("/dev/cgone0");
if (display == NULL) {
fprintf(stderr,"Color Display not available, sorry\n");
exit (-1);
}
puts("Reading RGB files");
if (read(fr, pr, image_vol) <= 0)
perror("red");
if (read(fg, pg, image_vol) <= 0)
perror("grn");
if (read(fb, pb, image_vol) <= 0)
perror("blu");
puts("Creating memory pixrect");
/* Get a pointer to a memory pixrect */
memory_frame = mem_create(x_imagesize, y_imagesize, 8);
/* Get a pointer to the image buffer associated with the memory pixrect */
pict_row = picture = (unsigned char *) mpr_d(memory_frame)->md_image;
/* Get bytes per scan-line (note that padding exists) */
row_bytes = mpr_d(memory_frame)->md_linebytes;
puts("Initializing tables");
init_tables();
puts("Processing image");
for (y = 0; y < y_imagesize; y++, picture = pict_row += row_bytes) {
for (x = 0; x < x_imagesize; x++) {
r_color = *pr++;
g_color = *pg++;
b_color = *pb++;
#ifdef BLUE_DITHER
b_dith_value = bdither[x & BDMASK][y & BDMASK];
#endif /* BLUE_DITHER */
dith_value = dither[x & DMASK][y & DMASK];
if (r_dval[r_color] > dith_value)
color = r_base_left[r_color];
else
color = r_base_right[r_color];
if (g_dval[g_color] > dith_value)
color |= g_base_left[g_color];
else
color |= g_base_right[g_color];
#ifdef BLUE_DITHER
if (b_dval[b_color] > b_dith_value)
#else
if (b_dval[b_color] > dith_value)
#endif /* BLUE_DITHER */
color |= b_base_left[b_color];
else
color |= b_base_right[b_color];
*picture++ = color;
}
}
/*
* Generate colormap with (cycle is 8 values):
* 32 cycles of red
* 1 cycle of green
* 1/2 cycle of blue
* all varying smoothely, note that an improved
* map which employs better graduation of color
* can be employed, but on our interlaced monitor
* this caused an extremely painful flicker.
*/
puts("Building color lookup table");
for (i=0; i < MAPSIZE; i++) {
red[i] = (i & R_MAP) << R_SHIFT;
grn[i] = (i & G_MAP) << (G_SHIFT - R_BITS);
blu[i] = (i & B_MAP) << (B_SHIFT - R_BITS - G_BITS);
}
pr_putcolormap(display, 0, MAPSIZE, red, grn, blu);
/* copy the complete image to the display, center it also.
*/
puts("Displaying");
pr_rop(display,
max((display->pr_width - x_imagesize) >> 1, 0),
max((display->pr_height - y_imagesize) >> 1,0),
min(display->pr_width, x_imagesize),
min(display->pr_height, y_imagesize),
(PIX_SRC|PIX_DONTCLIP), memory_frame, 0, 0);
pr_close(display);
close(fr);
close(fg);
close(fb);
}
init_tables()
{
register unsigned int intensity, i;
register double true_i;
register double rfactor, gfactor, bfactor;
rfactor = ((double)R_NVAL) / ((double)R_NVAL+1);
gfactor = ((double)G_NVAL) / ((double)G_NVAL+1);
bfactor = ((double)B_NVAL) / ((double)B_NVAL+1);
for (i = 0; i < 256; i++) {
true_i = (double) i;
/*
* scale color to fit inside of range
* calculate right base shade by trimming off error.
*/
intensity = (unsigned int)(true_i * rfactor);
r_base_right[i] = intensity & ~R_MASK;
if (r_base_right[i] != R_TOP) {
r_dval[i] = (intensity & R_MASK) >> R_ISHIFT;
r_base_left[i] =
((intensity + R_NEXT) & R_TOP) >> (UNUSED_BITS+G_BITS+B_BITS);
} else
r_dval[i] = 0;
r_base_right[i] >>= (UNUSED_BITS + G_BITS + B_BITS);
/*
* scale color to fit inside of range
* calculate right base shade by trimming off error.
*/
intensity = (unsigned int)(true_i * gfactor);
g_base_right[i] = intensity & ~G_MASK;
if (g_base_right[i] != G_TOP) {
g_dval[i] = (intensity & G_MASK) >> G_ISHIFT;
g_base_left[i] =
((intensity + G_NEXT) & G_TOP) >> (UNUSED_BITS + B_BITS);
} else
g_dval[i] = 0;
g_base_right[i] >>= (UNUSED_BITS + B_BITS);
/*
* scale color to fit inside of range
* calculate right base shade by trimming off error.
*/
intensity = (unsigned int)(true_i * bfactor);
b_base_right[i] = intensity & ~B_MASK;
if (b_base_right[i] != B_TOP) {
b_dval[i] = (intensity & B_MASK) >> B_ISHIFT;
b_base_left[i] =
((intensity + B_NEXT) & B_TOP) >> UNUSED_BITS;
} else
b_dval[i] = 0;
b_base_right[i] >>= UNUSED_BITS;
}
}
SHAR_EOF
fi
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Makefile for tcd (Tape color dither)
#
CC = /bin/cc
CFLAGS = -O
tcd: tcd.c
$(CC) $(CFLAGS) -o $@ tcd.c -lpixrect
clean:
rm -f tcd.o
SHAR_EOF
fi
exit 0
# End of shell archive
More information about the Mod.sources
mailing list