home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume4
/
8to1
/
8to1.c
next >
Wrap
C/C++ Source or Header
|
1989-02-03
|
17KB
|
585 lines
/**************************************************************************
Copyright (c) 1988 by Hong Min
compile : cc -O -o 8to1 8to1.c -lpixrect
The program 8to1 converts a 8-bit depth sun raster file (both color,
i.e. rgb are different, and grey, i.e. rgb are the same, and both
standard format and byte-encoded format) to a 1-bit depth mono sun
raster file. If your color image has no colormap, this program would
provide a default grey scale color map. It implements several halftone
algorithms from Digital Halftones by Dot Diffusion in acm Transactions
on Graphics, such as error diffusion, ordered dither and dot diffusion
with and without edge enhancement. Just type 8to1, it will give you
the usage.
This program was written by :
Hong Min
Computer Science Department
SUNY at Stony Brook
e-mail address :
UUCP: {allegra, philabs, pyramid, research}!sbcs!rainbow
ARPA-Internet: rainbow@sbcs.sunysb.edu
CSnet: rainbow@suny-sb
Everyone is welcome to write to me if you like the program or not.
And welcome to optimize the code, as I haven't fooled with it to
make it efficient yet.
Enjoy!
****************************************************************************/
#include <stdio.h>
#include <sys/types.h>
#include <pixrect/pixrect.h>
#include <pixrect/memvar.h>
#include <pixrect/pr_util.h>
#include <pixrect/pr_io.h>
#include <rasterfile.h>
#define ORDER 16 /* dither matrix order */
#define WHITE 0 /* background color */
#define BLACK ~0 /* foreground color */
#define FALSE 0
#define TRUE 1
#define ALPHA 7
#define BETA 3
#define GAMMA 5
#define DELTA 1
short **A, **B;
int ordered_dither[8][8] = { 0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21 };
int dot_diffusion[8][8] = { 34, 48, 40, 32, 29, 15, 23, 31,
42, 58, 56, 53, 21, 5, 7, 10,
50, 62, 61, 45, 13, 1, 2, 18,
38, 46, 54, 37, 25, 17, 9, 26,
28, 14, 22, 30, 35, 49, 41, 33,
20, 4, 6, 11, 43, 59, 57, 52,
12, 0, 3, 19, 51, 63, 60, 44,
24, 16, 8, 27, 39, 47, 55, 36 };
int reverse_matrix[64] = { 49, 21, 22, 50, 41, 13, 42, 14,
58, 30, 15, 43, 48, 20, 33, 5,
57, 29, 23, 51, 40, 12, 34, 6,
56, 28, 31, 59, 32, 4, 35, 7,
3, 39, 0, 36, 63, 27, 24, 60,
2, 38, 8, 44, 55, 19, 25, 61,
1, 37, 16, 52, 47, 11, 26, 62,
10, 46, 9, 45, 54, 18, 17, 53 };
main(argc, argv)
int argc;
char *argv[];
{
register colormap_t colormap;
register unsigned char *map;
register struct rasterfile rh;
register Pixrect *pr = 0;
register int i, default_map = FALSE;
int option;
if ((argc > 4) || (argc < 2)) {
fprintf(stderr, "Usage: %s option [infile [outfile]]\n", argv[0]);
fprintf(stderr, "option : 0 -- error diffusion for grey scale\n");
fprintf(stderr, " 1 -- ordered dither for grey scale\n");
fprintf(stderr, " 2 -- dot diffusion for grey scale\n");
fprintf(stderr, " 3 -- error diffusion for grey scale with edge enhancement\n");
fprintf(stderr, " 4 -- ordered dither for grey scale with edge enhancement\n");
fprintf(stderr, " 5 -- dot diffusion for grey scale with edge enhancement\n");
fprintf(stderr, " 6 -- error diffusion for color\n");
fprintf(stderr, " 7 -- ordered dither for color\n");
fprintf(stderr, " 8 -- dot diffusion for color\n");
fprintf(stderr, " 9 -- error diffusion for color with edge enhancement\n");
fprintf(stderr, " 10 -- ordered dither for color with edge enhancement\n");
fprintf(stderr, " 11 -- dot diffusion for color with edge enhancement\n");
exit(1);
}
sscanf(argv[1], "%d", &option);
/* open the input file if specified */
if ((argc > 2) && (freopen(argv[2], "r", stdin) == NULL)) {
fprintf(stderr, "can't open infile %s for read!\n", argv[2]);
exit(1);
}
/* open the output file if specified */
if ((argc > 3) && (freopen(argv[3], "w", stdout) == NULL)) {
fprintf(stderr, "can't open outfile %s for write!\n", argv[3]);
exit(1);
}
/* Load the input rasterfile header */
if (pr_load_header(stdin, &rh)) {
fprintf(stderr, "read rasterfile header error\n");
exit(1);
}
if (rh.ras_depth != 8) {
fprintf(stderr, "input file is not a 8 bits deep\n");
exit(1);
}
/* Load the colormap */
colormap.type = RMT_NONE;
if (pr_load_colormap(stdin, &rh, &colormap)) {
fprintf(stderr, "read rasterfile header error\n");
exit(1);
}
if (colormap.type != RMT_NONE &&
(colormap.type != RMT_EQUAL_RGB || colormap.length < 256)) {
fprintf(stderr,"input has unsupported colormap type or length\n");
exit(1);
}
if ((colormap.type == RMT_NONE) && (colormap.length == 0)) {
default_map = TRUE;
map = (unsigned char *) malloc(256);
for (i=0; i<256; i++)
map[i] = i;
}
if (rh.ras_type != RT_OLD && rh.ras_type != RT_STANDARD &&
!(pr = pr_load_image(stdin, &rh, &colormap))) {
fprintf(stderr, "error reading rasterfile\n");
exit(1);
}
/* Write new header */
rh.ras_type = RT_STANDARD;
rh.ras_depth = 1;
rh.ras_length = mpr_linebytes(rh.ras_width, 1) * rh.ras_height;
rh.ras_maptype = RMT_NONE;
rh.ras_maplength = 0;
if (pr_dump_header(stdout, &rh, (colormap_t *) 0) == PIX_ERR) {
fprintf(stderr, "error saving raster file header!\n");
exit(1);
}
if (rh.ras_width <= 0 || rh.ras_height <= 0)
exit(1);
else {
A = (short **) malloc((rh.ras_width+3)*sizeof(short *));
B = (short **) malloc((rh.ras_width+3)*sizeof(short *));
for(i=0; i<rh.ras_width+3; i++) {
A[i] = (short *)malloc((rh.ras_height+3)*sizeof(short));
B[i] = (short *)malloc((rh.ras_height+3)*sizeof(short));
}
}
if (!default_map)
map = colormap.map[0];
if (pr)
switch (option) {
case 6 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 0 : error_diffusion_image(rh.ras_width, rh.ras_height,
map, (u_char *) mpr_d(pr)->md_image, stdout,
0, mpr_d(pr)->md_linebytes - rh.ras_width);
break;
case 7 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 1 : ordered_dither_image(rh.ras_width, rh.ras_height,
map, (u_char *) mpr_d(pr)->md_image, stdout,
0, mpr_d(pr)->md_linebytes - rh.ras_width);
break;
case 8 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 2 : dot_diffusion_image(rh.ras_width, rh.ras_height,
map, (u_char *) mpr_d(pr)->md_image, stdout,
0, mpr_d(pr)->md_linebytes - rh.ras_width);
break;
case 9 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 3 : error_diffusion_image(rh.ras_width, rh.ras_height,
map, (u_char *) mpr_d(pr)->md_image, stdout,
1, mpr_d(pr)->md_linebytes - rh.ras_width);
break;
case 10 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 4 : ordered_dither_image(rh.ras_width, rh.ras_height,
map, (u_char *) mpr_d(pr)->md_image, stdout,
1, mpr_d(pr)->md_linebytes - rh.ras_width);
break;
case 11 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 5 : dot_diffusion_image(rh.ras_width, rh.ras_height,
map, (u_char *) mpr_d(pr)->md_image, stdout,
1, mpr_d(pr)->md_linebytes - rh.ras_width);
break;
}
else
switch (option) {
case 6 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 0 : error_diffusion_file(rh.ras_width, rh.ras_height,
map, stdin, stdout, 0,
mpr_linebytes(rh.ras_width, 8) - rh.ras_width);
break;
case 7 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 1 : ordered_dither_file(rh.ras_width, rh.ras_height,
map, stdin, stdout, 0,
mpr_linebytes(rh.ras_width, 8) - rh.ras_width);
break;
case 8 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 2 : dot_diffusion_file(rh.ras_width, rh.ras_height,
map, stdin, stdout, 0,
mpr_linebytes(rh.ras_width, 8) - rh.ras_width);
break;
case 9 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 3 : error_diffusion_file(rh.ras_width, rh.ras_height,
map, stdin, stdout, 1,
mpr_linebytes(rh.ras_width, 8) - rh.ras_width);
break;
case 10 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 4 : ordered_dither_file(rh.ras_width, rh.ras_height,
map, stdin, stdout, 1,
mpr_linebytes(rh.ras_width, 8) - rh.ras_width);
break;
case 11 : map = (unsigned char *) malloc(256);
color_map_3_to_1(colormap, map);
case 5 : dot_diffusion_file(rh.ras_width, rh.ras_height,
map, stdin, stdout, 1,
mpr_linebytes(rh.ras_width, 8) - rh.ras_width);
break;
}
}
color_map_3_to_1(colormap, map)
register colormap_t colormap;
register unsigned char *map;
{
register unsigned long tmp, i;
for (i=0; i<256; i++) {
tmp = colormap.map[0][i]*77 + colormap.map[1][i]*151 + colormap.map[2][i]*28;
map[i] = tmp >> 8;
}
}
edge_enhancement(width, height, off)
register int width, height, off;
{
register int i, j, x, y;
B[off][off] = A[off][off]*6 - A[off][off+1] - A[off+1][off] - A[off+1][off+1];
B[off][off+height-1] = A[off][off+height-1]*6 - A[off][off+height-2] - A[off+1][off+height-1] - A[off+1][off+height-2];
B[off+width-1][off] = A[off+width-1][off]*6 - A[off+width-1][off+1] - A[off+width-2][off] - A[off+width-2][off+1];
B[off+width-1][off+height-1] = A[off+width-1][off+height-1]*6 - A[off+width-1][off+height-2] - A[off+width-2][off+height-1] - A[off+width-2][off+height-2];
for (i=1; i<width-1; i++)
B[off+i][off+0] = A[off+i][off+0]*6 - A[off+i-1][off+0] - A[off+i+1][off+0] - A[off+i-1][off+1] - A[off+i][off+1] - A[off+i+1][off+1];
for (i=1; i<width-1; i++)
B[off+i][off+height-1] = A[off+i][off+height-1]*6 - A[off+i-1][off+height-1] - A[off+i+1][off+height-2] - A[off+i-1][off+height-2] - A[off+i][off+1] - A[off+i+1][off+height-2];
for (i=1; i<height-1; i++)
B[off+0][off+i] = A[off+0][off+i]*6 - A[off+0][off+i-1] - A[off+0][off+i+1] - A[off+1][off+i-1] - A[off+1][off+i] - A[off+1][off+i+1];
for (i=1; i<height-1; i++)
B[off+width-1][off+i] = A[off+width-1][off+i]*6 - A[off+width-1][off+i-1] - A[off+width-1][off+i+1] - A[off+width-2][off+i-1] - A[off+width-2][off+i] - A[off+width-2][off+i+1];
for(i=1; i<width-1; i++)
for(j=1; j<height-1; j++) {
B[off+i][off+j] = A[off+i][off+j]*10;
for(x=i-1; x<=i+1; x++)
for(y=j-1; y<=j+1; y++)
B[off+i][off+j] -= A[off+x][off+y];
}
for(i=0; i<width; i++)
for(j=0; j<height; j++)
A[off+i][off+j] = B[off+i][off+j];
}
int index(x, y, w, pad)
register int x, y, w, pad;
{
return(x+y*(w+pad));
}
error_diffusion(width, height, out, edge)
register int width, height;
register FILE *out;
register int edge;
{
register int err, mono_pad;
register u_short dtmp;
register u_long i, j;
mono_pad = mpr_linebytes(width, 1)*8 - width;
if (edge)
edge_enhancement(width, height, 1);
for(j=1; j<height+1; j++) {
for(i=1; i<width+1; i++) {
dtmp <<= 1;
if (A[i][j] > 128)
err = A[i][j] - 256;
else {
err = A[i][j];
dtmp |= 1;
}
A[i+1][j] += (err*ALPHA) >> 4;
A[i-1][j+1] += (err*BETA) >> 4;
A[i][j+1] += (err*GAMMA) >> 4;
A[i+1][j+1] += (err*DELTA) >> 4;
if (((i-1) % 16) == 15) {
putc(dtmp >> 8, out);
putc(dtmp, out);
}
}
for(i=width+1; i<=width+mono_pad; i++) {
dtmp <<= 1;
if (((i-1) % 16) == 15) {
putc(dtmp >> 8, out);
putc(dtmp, out);
}
}
}
}
/* Compute pixel values using error diffusion */
error_diffusion_image(width, height, map, in, out, edge_enhance, pad)
register int width, height;
register unsigned char *map;
register u_char *in;
register FILE *out;
register int edge_enhance, pad;
{
register int i, j;
for(j=1; j<height+1; j++)
for(i=1; i<width+1; i++)
A[i][j] = map[*(in+index(i-1, j-1, width, pad))];
error_diffusion(width, height, out, edge_enhance);
}
/* Compute pixel values using error diffusion */
error_diffusion_file(width, height, map, in, out, edge_enhance, pad)
register int width, height;
register unsigned char *map;
register FILE *in, *out;
register int edge_enhance, pad;
{
register int i, j, c;
for(j=1; j<height+1; j++) {
for(i=1; i<width+1; i++) {
if ((c = getc(in)) == EOF) {
fprintf(stderr, "error reading raster data!\n");
exit(1);
}
A[i][j] = map[c];
}
for(i=width; i<width+pad; i++)
if ((c = getc(in)) == EOF)
fprintf(stderr, "error reading raster data!\n");
}
error_diffusion(width, height, out, edge_enhance);
}
ordered(width, height, out, edge)
register int width, height;
register FILE *out;
register int edge;
{
register int mono_pad;
register u_short dtmp;
register u_long i, j;
mono_pad = mpr_linebytes(width, 1)*8 - width;
if (edge)
edge_enhancement(width, height, 0);
for(j=0; j<8; j++)
for(i=0; i<8; i++)
ordered_dither[i][j] = ordered_dither[i][j]*4 + 2;
for(j=0; j<height; j++) {
for(i=0; i<width; i++) {
dtmp <<= 1;
if (A[i][j] >= ordered_dither[i%8][j%8])
dtmp |= 1;
if ((i % 16) == 15) {
putc(dtmp >> 8, out);
putc(dtmp, out);
}
}
for(i=width; i<width+mono_pad; i++) {
dtmp <<= 1;
if ((i % 16) == 15) {
putc(dtmp >> 8, out);
putc(dtmp, out);
}
}
}
}
ordered_dither_image(width, height, map, in, out, edge_enhance, pad)
register int width, height;
register unsigned char *map;
register u_char *in;
register FILE *out;
register int edge_enhance, pad;
{
register int i, j;
for(j=0; j<height; j++)
for(i=0; i<width; i++)
A[i][j] = 256 - map[*(in+index(i, j, width, pad))];
ordered(width, height, out, edge_enhance);
}
ordered_dither_file(width, height, map, in, out, edge_enhance, pad)
register int width, height;
register unsigned char *map;
register FILE *in, *out;
register int edge_enhance, pad;
{
register int i, j, c;
for(j=0; j<height; j++) {
for(i=0; i<width; i++) {
if ((c = getc(in)) == EOF) {
fprintf(stderr, "error reading raster data!\n");
exit(1);
}
A[i][j] = 256 - map[c];
}
for(i=width; i<width+pad; i++)
if ((c = getc(in)) == EOF)
fprintf(stderr, "error reading raster data!\n");
}
ordered(width, height, out, edge_enhance);
}
int weight(x, y)
register int x,y;
{
return(3 - x*x - y*y);
}
dot(width, height, out, edge)
register int width, height;
register FILE *out;
register int edge;
{
register int k, u, v, err, w, mono_pad;
register u_short dtmp;
register u_long i, j;
mono_pad = mpr_linebytes(width, 1)*8 - width;
if (edge)
edge_enhancement(width, height, 0);
for(k=0; k<64; k++) {
for(i=reverse_matrix[k]/8; i<width; i+=8)
for(j=reverse_matrix[k]%8; j<height; j+=8) {
if (A[i][j] > 128)
B[i][j] = 0;
else
B[i][j] = 1;
err = A[i][j] - (1 - B[i][j])*256;
w = 0;
for(u=i-1; u<=i+1; u++)
for(v=j-1; v<=j+1; v++)
if ((u>=0) && (v>=0) && (dot_diffusion[u%8][v%8] > k))
w += weight(u-i, v-j);
if (w > 0) {
for(u=i-1; u<=i+1; u++)
for(v=j-1; v<=j+1; v++)
if ((u>=0)&&(v>=0)&&(dot_diffusion[u%8][v%8]>k))
A[u][v] += err * weight(u-i, v-j) / w;
}
}
}
for(j=0; j<height; j++) {
for(i=0; i<width; i++) {
dtmp <<= 1;
if (B[i][j])
dtmp |= 1;
if ((i % 16) == 15) {
putc(dtmp >> 8, out);
putc(dtmp, out);
}
}
for(i=width; i<width+mono_pad; i++) {
dtmp <<= 1;
if ((i % 16) == 15) {
putc(dtmp >> 8, out);
putc(dtmp, out);
}
}
}
}
dot_diffusion_image(width, height, map, in, out, edge_enhance, pad)
register int width, height;
register unsigned char *map;
register u_char *in;
register FILE *out;
register int edge_enhance, pad;
{
register int i, j;
for(j=0; j<height; j++)
for(i=0; i<width; i++)
A[i][j] = map[*(in+index(i, j, width, pad))];
dot(width, height, out, edge_enhance);
}
dot_diffusion_file(width, height, map, in, out, edge_enhance, pad)
register int width, height;
register unsigned char *map;
register FILE *in, *out;
register int edge_enhance, pad;
{
register int i, j, c;
for(j=0; j<height; j++) {
for(i=0; i<width; i++) {
if ((c = getc(in)) == EOF) {
fprintf(stderr, "error reading raster data!\n");
exit(1);
}
A[i][j] = map[c];
}
for(i=width; i<width+pad; i++)
if ((c = getc(in)) == EOF)
fprintf(stderr, "error reading raster data!\n");
}
dot(width, height, out, edge_enhance);
}