sources-request@panda.UUCP (05/18/86)
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@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