schear@ttidca.TTI.COM (Steve Schear) (01/31/89)
Some engineers in my group have been assigned the task of creating a demo to demonstrate the effect of decreasing color space resolution on display quality. Has anyone out there written routines using some of the more popular algorithms (e.g., media slice, or quadtree) which permit a 24-bit/pixel color image to be reduced to less color resolution. One bit increments would be ideal. We at least plan to show 16-bit and 12-bit versions in addition to the obvious 8-bit/pixel images. BTW C sources code would be best. Thanks in advance. Steve Schear Product Planner Citicorp/TTI 3100 Ocean Park Blvd. Santa Monica, CA 90405 (213) 452-9191
quinn@killington.dartmouth.edu (Jerry Quinn) (02/01/89)
me too! jerry quinn quinn@sunapee.dartmouth.edu
falk@sun.uucp (Ed Falk) (02/02/89)
In article <3781@ttidca.TTI.COM>, schear@ttidca.TTI.COM (Steve Schear) writes: > Some engineers in my group have been assigned the task of creating a > demo to demonstrate the effect of decreasing color space resolution > on display quality. Has anyone out there written routines using some > of the more popular algorithms (e.g., media slice, or quadtree) which > permit a 24-bit/pixel color image to be reduced to less color > resolution. One bit increments would be ideal. We at least plan to > show 16-bit and 12-bit versions in addition to the obvious > 8-bit/pixel images. > OK, but only if you promise to put newlines in your postings from now on. Remember: this isn't MACWRITE. This has got to be the most commonly asked question in this newsgroup. In fact, I've posted all this stuff recently. Is there an archive service we should be using for this stuff? Here it is once again: "dither24to8" reduces a 24-bit sun rasterfile to 8 bits by defining a color cube in the color table and mapping pixels directly to color table entries. "median" is Heckbert's median-cut algorithm. Now, NOBODY ELSE IS ALLOWED TO ASK THIS QUESTION FOR THREE MONTHS. #! /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 to create the files: # dither24to8.c # median.c # pr_stream.c # This archive created: Wed Feb 1 18:15:56 PST 1989 by falk # # export PATH; PATH=/bin:$PATH # if test -f dither24to8.c then echo shar: will not over-write existing file dither24to8.c else echo shar: extracting 'dither24to8.c', 19177 characters sed 's/^X//' > dither24to8.c <<'SHAR_EOF' X/* quantize stuff: X * X * dither24to8 [-ctrim] [-od] [-fsd] [-size n n n] [-news] [-ofs n ] X * [ifile [ofile]] X * X */ X/* X XI should point out that the actual fractions we used were, assuming Xyou are at X, moving left to right: X X X 7/16 X 3/16 5/16 1/16 X XNote that the error goes to four neighbors, not three. I think this Xwill probably do better (at least for black and white) than the X3/8-3/8-1/4 distribution, at the cost of greater processing. I have Xseen the 3/8-3/8-1/4 distribution described as "our" algorithm before, Xbut I have no idea who the credit really belongs to. X XAlso, I should add that if you do zig-zag scanning (see my immediately Xprevious message), it is sufficient (but not quite as good) to send Xhalf the error one pixel ahead (e.g. to the right on lines you scan Xleft to right), and half one pixel straight down. Again, this is for Xblack and white; I've not tried it with color. X-- X Lou Steinberg X X*/ X X#include <stdio.h> X#include <sys/types.h> X#include <pixrect/pixrect_hs.h> X X#define MAX_CMAP_SIZE 256 X X#define MAX_REDS 5 X#define MAX_GREENS 9 X#define MAX_BLUES 5 X#define CUBE_OFFSET 30 X#define RSCALE 0 X#define GSCALE (MAX_BLUES*MAX_REDS) X#define BSCALE MAX_REDS X X X X Xstatic struct rasterfile rh; Xstatic colormap_t colormap, ocmap ; Xstatic unsigned char rm[MAX_CMAP_SIZE], X gm[MAX_CMAP_SIZE], X bm[MAX_CMAP_SIZE] ; Xstatic int bytes_per_pixel ; Xstatic int linebytes, olinebytes ; Xstatic int num_r, num_g, num_b ; Xstatic int special_case ; Xstatic int trim ; Xstatic int NeWS_offset ; Xstatic int min_r, max_r, min_g, max_g, min_b, max_b ; X Xstatic char *usage = X"usage: dither24to8 [-ctrim] [-od] [-fsd] [-size n n n] [ifile [ofile]]\n" ; X X X Xmain(argc, argv) X int argc; X char **argv; X{ Xstatic struct rasterfile outheader ; X int i, j ; X int dither = 0 ; X int odither = 0 ; X char *ifile_name = NULL, *ofile_name = NULL ; X X trim = 0 ; X num_r = 8; num_g = 8; num_b = 4 ; X special_case = 1 ; X NeWS_offset = 0 ; X min_r = min_g = min_b = 0 ; X max_r = max_g = max_b = 255 ; X X while(--argc) X { X ++argv ; X if(strcmp(*argv,"-od") == 0) X odither = 1 ; X X else if(strcmp(*argv,"-fsd") == 0) X dither = 1 ; X X else if(strcmp(*argv,"-size") == 0) X { X if(argc < 4) X { X fprintf(stderr,"-size requires 3 arguments\n%s",usage) ; X exit(1) ; X } X else X { X argc -= 3 ; X num_r = atoi(*++argv) ; X num_g = atoi(*++argv) ; X num_b = atoi(*++argv) ; X special_case = 0 ; X if(num_r * num_g * num_b + NeWS_offset > MAX_CMAP_SIZE) X { X fprintf(stderr,"-size specifies colormap greater than %d\n%s", X MAX_CMAP_SIZE,usage) ; X exit(1) ; X } X } X } X X else if(strcmp(*argv,"-ctrim") == 0) X { X trim = 1 ; X special_case = 0 ; X } X X else if(strcmp(*argv,"-news") == 0) X { X trim = 0 ; X special_case = 0 ; X num_r = 5 ; num_g = 9 ; num_b = 5 ; X NeWS_offset = CUBE_OFFSET ; X } X X else if(strcmp(*argv,"-ofs") == 0) X { X if( argc < 2 ) X { X fprintf(stderr,"-ofs requires an argument\n%s",usage) ; X exit(1) ; X } X else X { X special_case = 0 ; X NeWS_offset = atoi(*++argv) ; --argc ; X if(num_r * num_g * num_b + NeWS_offset > MAX_CMAP_SIZE) X { X fprintf(stderr,"-ofs specifies colormap greater than %d\n%s", X MAX_CMAP_SIZE,usage) ; X exit(1) ; X } X } X } X X else if(**argv == '-') X { X fprintf(stderr,"unknown argument '%s', %s",*argv, usage) ; X exit(1) ; X } X X else if(!ifile_name) X { X ifile_name = *argv ; X } X X else if(!ofile_name) X { X ofile_name = *argv ; X } X X else X { X fprintf(stderr, "Too many file names, %s",usage) ; X exit(1) ; X } X } X X if(ifile_name) X if (freopen(ifile_name, "r", stdin) == NULL) X { X fprintf(stderr,"Cannot open input file %s\n%s", ifile_name,usage); X exit(1); X } X X if(ofile_name) X if (freopen(ofile_name, "w", stdout) == NULL) X { X fprintf(stderr,"Cannot open output file %s\n%s", ofile_name,usage); X exit(1); X } X X X colormap.type = RMT_NONE ; X X X if( pr_load_header(stdin, &rh) != 0 || X pr_load_colormap(stdin, &rh, &colormap) != 0 ) X { X fprintf(stderr,"Error reading rasterfile header.\n"); X exit(1); X } X X X switch( rh.ras_depth ) X { X case 24: bytes_per_pixel = 3 ; break ; X case 32: bytes_per_pixel = 4 ; break ; X default: X fprintf(stderr, X "Image is %d bits deep, dither24to8 only works with 24 or 32\n"); X exit(1) ; X } X X if(trim) X { X if(fseek(stdin, 0L, 0) == 0) X { X trim_ctab() ; X rewind(stdin) ; X pr_load_header(stdin, &rh) ; X pr_load_colormap(stdin, &rh, NULL) ; X } X else X { X fprintf(stderr, "-t option only works if input from file\n") ; X } X } X X X ocmap.type = RMT_EQUAL_RGB ; X ocmap.length = num_r * num_g * num_b + NeWS_offset ; X ocmap.map[0] = rm ; X ocmap.map[1] = gm ; X ocmap.map[2] = bm ; X { X register int ir,ig,ib,ptr ; X int lr = max_r-min_r, lg=max_g-min_g, lb=max_b-min_b ; X int nr = num_r-1, ng=num_g-1, nb=num_b-1 ; X ptr = 0 ; X#ifdef COMMENT X for(ir = 0; ir < num_r; ++ir) X for(ig = 0; ig < num_g; ++ig) X for(ib = 0; ib < num_b; ++ib) X { X rm[ptr] = min_r + ir * lr / nr ; X gm[ptr] = min_g + ig * lg / ng ; X bm[ptr] = min_b + ib * lb / nb ; X ++ptr ; X } X#endif COMMENT X for(ig = 0; ig < num_g; ++ig) X for(ib = 0; ib < num_b; ++ib) X for(ir = 0; ir < num_r; ++ir) X { X rm[ptr+NeWS_offset] = min_r + ir * lr / nr ; X gm[ptr+NeWS_offset] = min_g + ig * lg / ng ; X bm[ptr+NeWS_offset] = min_b + ib * lb / nb ; X ++ptr ; X } X } X X X pr_read_init(&rh) ; X X linebytes = rh.ras_width * bytes_per_pixel ; X linebytes += linebytes%2 ; X olinebytes = rh.ras_width ; X olinebytes += olinebytes%2 ; X X outheader.ras_magic = RAS_MAGIC ; X outheader.ras_width = rh.ras_width ; X outheader.ras_height = rh.ras_height ; X outheader.ras_depth = 8 ; X outheader.ras_length = olinebytes * outheader.ras_height ; X outheader.ras_type = RT_STANDARD ; X outheader.ras_maptype = RMT_EQUAL_RGB ; X outheader.ras_maplength = ocmap.length*3 ; X pr_dump_header(stdout, &outheader, &ocmap) ; X X if(dither) X quant_fsdither() ; X else if(odither) X quant_odither() ; X else X quant() ; X X fclose(stdout) ; X} X X X X X X#define GETPIX(inptr,red,green,blue) \ X if(rh.ras_depth == 32) \ X ++inptr ; \ X blue = *inptr++ ; \ X green = *inptr++ ; \ X red = *inptr++ ; \ X \ X if (rh.ras_maplength > 0) \ X { \ X red = *(colormap.map[0]+red) ; \ X green = *(colormap.map[1]+green) ; \ X blue = *(colormap.map[2]+blue) ; \ X } X X X X X/* X * straight quantization. Each pixel is mapped to the colors X * closest to it. Color values are rounded to the nearest color X * table entry. X */ X Xquant() X{ X unsigned char *outline ; X unsigned char *inline ; Xregister unsigned char *outptr ; Xregister unsigned char *inptr ; Xregister int i, j ; X int nr = num_r-1, ng = num_g-1, nb = num_b-1 ; X int lr = max_r-min_r, lg = max_g-min_g, lb = max_b-min_b ; X int or = lr/nr/2 - min_r, X og = lg/ng/2 - min_g, X ob = lb/nb/2 - min_b ; X X X X X inline = (unsigned char *) malloc( linebytes ) ; X X outline = (unsigned char *) malloc( olinebytes ) ; X X for(i=0; i < rh.ras_height; ++i) X { X pr_get_bytes(stdin, &rh, linebytes, inline) ; X inptr = inline ; X outptr = outline; X for(j=0; j < rh.ras_width; ++j) X { X register int tmp,red,green,blue ; X X GETPIX(inptr,red,green,blue) ; X X#ifdef COMMENT X if(special_case) X tmp = (red & 0xe0) + ((green & 0xe0) >> 3) + (blue >> 6) ; X else X { X if(trim) X { X tmp = (red+or)*nr / lr ; X green = (green+og)*ng / lg ; X blue = (blue+ob)*nb / lb ; X } X else X { X tmp = (red+or)*nr / 256 ; X green = (green+og)*ng / 256 ; X blue = (blue+ob)*nb / 256 ; X } X#ifdef DEBUG X if(tmp > nr || green > ng || blue > nb) X fprintf(stderr,"ERROR: rgb = %d,%d,%d\n",tmp,green,blue) ; X#endif DEBUG X tmp = (((tmp * num_g) + green) * num_b) + blue ; X#endif COMMENT X if(special_case) X tmp = (red >> 5) + (green & 0xe0) + ((blue & 0xc0) >> 3) ; X else X { X if(trim) X { X red = (red+or)*nr / lr ; X tmp = (green+og)*ng / lg ; X blue = (blue+ob)*nb / lb ; X } X else X { X red = (red+or)*nr / 256 ; X tmp = (green+og)*ng / 256 ; X blue = (blue+ob)*nb / 256 ; X } X#ifdef DEBUG X if(red > nr || tmp > ng || blue > nb) X fprintf(stderr,"ERROR: rgb = %d,%d,%d\n",red,tmp,blue) ; X#endif DEBUG X tmp = (((tmp * num_b) + blue) * num_r) + red + NeWS_offset ; X } X *outptr++ = tmp ; X } X fwrite(outline, 1, olinebytes, stdout) ; X } X free(inline) ; X free(outline) ; X} X X X/* X * quantization with dither. Each color value is rounded up or down X * depending on the comparison of the error and the corresponding entry X * in the dither matrix X */ X Xquant_odither() X{ X unsigned char *outline ; X unsigned char *inline ; Xregister unsigned char *outptr ; Xregister unsigned char *inptr ; Xregister int i, j ; X int nr = num_r-1, ng = num_g-1, nb = num_b-1 ; X int lr = max_r-min_r, lg = max_g-min_g, lb = max_b-min_b ; X Xstatic int d16[16][16] = { X { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255}, X {128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127}, X { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223}, X {160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95}, X { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247}, X {136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119}, X { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215}, X {168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87}, X { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253}, X {130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125}, X { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221}, X {162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93}, X { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245}, X {138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117}, X { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213}, X {170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85}} ; X X int rdither[16][16], gdither[16][16], bdither[16][16] ; X X for(i=0; i<16; ++i) X for(j=0; j<16; ++j) X { X rdither[i][j] = d16[i][j]*lr / nr / 256 ; X gdither[i][j] = d16[i][j]*lg / ng / 256 ; X bdither[i][j] = d16[i][j]*lb / nb / 256 ; X } X X inline = (unsigned char *) malloc( linebytes ) ; X X outline = (unsigned char *) malloc( olinebytes ) ; X X for(i=0; i < rh.ras_height; ++i) X { X pr_get_bytes(stdin, &rh, linebytes, inline) ; X inptr = inline ; X outptr = outline; X for(j=0; j < rh.ras_width; ++j) X { X register int tmp,red,green,blue,r2,g2,b2 ; X X GETPIX(inptr,red,green,blue) ; X X if(special_case) X { X#ifdef COMMENT X tmp = (red & 0xe0) + ((green >> 3) & 0x1c) + (blue >> 6) ; X red -= rm[tmp] ; X green -= gm[tmp] ; X blue -= bm[tmp] ; X if(red > rdither[i%16][j%16]) X tmp += 0x20 ; X if(green > gdither[i%16][j%16]) X tmp += 0x4 ; X if(blue > bdither[i%16][j%16]) X ++tmp ; X#endif COMMENT X tmp = (green & 0xe0) + ((blue >> 3) & 0x18) + (red >> 5) ; X red -= rm[tmp] ; X green -= gm[tmp] ; X blue -= bm[tmp] ; X if(red > rdither[i%16][j%16]) X ++tmp ; X if(green > gdither[i%16][j%16]) X tmp += 0x20 ; X if(blue > bdither[i%16][j%16]) X tmp += 8 ; X } X else X { X if(trim) X { X r2 = (red-min_r)*nr / lr ; X g2 = (green-min_g)*ng / lg ; X b2 = (blue-min_b)*nb / lb ; X } X else X { X r2 = red*nr / 255 ; X g2 = green*ng / 255 ; X b2 = blue*nb / 255 ; X } X#ifdef COMMENT X tmp = (((r2 * num_g) + g2) * num_b) + b2 ; X#endif COMMENT X tmp = (((g2 * num_b) + b2) * num_r) + r2 + NeWS_offset ; X red -= rm[tmp] ; X green -= gm[tmp] ; X blue -= bm[tmp] ; X if(red > rdither[i%16][j%16]) X ++r2 ; X if(green > gdither[i%16][j%16]) X ++g2 ; X if(blue > bdither[i%16][j%16]) X ++b2 ; X#ifdef DEBUG X if(r2 > nr || g2 > ng || b2 > nb) X fprintf(stderr,"ERROR: %d,%d,%d => %d,%d,%d\n", X red,green,blue,r2,g2,b2) ; X#endif DEBUG X#ifdef COMMENT X tmp = (((r2 * num_g) + g2) * num_b) + b2 ; X#endif COMMENT X tmp = (((g2 * num_b) + b2) * num_r) + r2 + NeWS_offset ; X } X *outptr++ = tmp ; X } X fwrite(outline, 1, olinebytes, stdout) ; X } X free(inline) ; X free(outline) ; X} X X X#ifdef COMMENT X#define FS_GETPIX \ X blue = *thisptr++ ; \ X green = *thisptr++ ; \ X red = *thisptr++ ; \ X \ X if(special_case) \ X tmp = (red & 0xe0) + ((green & 0xe0) >> 3) + (blue >> 6) ; \ X else \ X { \ X if(trim) \ X { \ X r2 = (red-min_r)*nr / lr ; \ X g2 = (green-min_g)*ng / lg ; \ X b2 = (blue-min_b)*nb / lb ; \ X } \ X else \ X { \ X r2 = red*nr / 255 ; \ X g2 = green*ng / 255 ; \ X b2 = blue*nb / 255 ; \ X } \ X if(r2 > nr) r2 = nr ; \ X if(g2 > ng) g2 = ng ; \ X if(b2 > nb) b2 = nb ; \ X tmp = (((r2 * num_g) + g2) * num_b) + b2 ; \ X } \ X *outptr++ = tmp ; \ X \ X red -= rm[tmp] ; \ X green -= gm[tmp] ; \ X blue -= bm[tmp] ; X#endif COMMENT X#define FS_GETPIX \ X blue = *thisptr++ ; \ X green = *thisptr++ ; \ X red = *thisptr++ ; \ X \ X if(special_case) \ X tmp = (green & 0xe0) + ((blue & 0xc0) >> 3) + (red >> 5) ; \ X else \ X { \ X if(trim) \ X { \ X r2 = (red-min_r)*nr / lr ; \ X g2 = (green-min_g)*ng / lg ; \ X b2 = (blue-min_b)*nb / lb ; \ X } \ X else \ X { \ X r2 = red*nr / 255 ; \ X g2 = green*ng / 255 ; \ X b2 = blue*nb / 255 ; \ X } \ X if(r2 > nr) r2 = nr ; \ X if(g2 > ng) g2 = ng ; \ X if(b2 > nb) b2 = nb ; \ X tmp = (((g2 * num_b) + b2) * num_r) + r2 + NeWS_offset ; \ X } \ X *outptr++ = tmp ; \ X \ X red -= rm[tmp] ; \ X green -= gm[tmp] ; \ X blue -= bm[tmp] ; X X X X X Xquant_fsdither() X{ X unsigned char *outline, *inline ; X short *thisline, *nextline, *tmpptr ; X int nr = num_r-1, ng = num_g-1, nb = num_b-1 ; X int lr = max_r-min_r, lg = max_g-min_g, lb = max_b-min_b ; X unsigned char *inptr ; Xregister unsigned char *outptr ; Xregister short *thisptr, *nextptr ; Xregister int i, j ; X X X X inline = (unsigned char *) malloc( linebytes ) ; X thisline = (short *) malloc( rh.ras_width * 3 * sizeof(short)) ; X nextline = (short *) malloc( rh.ras_width * 3 * sizeof(short)) ; X X outline = (unsigned char *) malloc( olinebytes ) ; X X /* X * get first line X */ X pr_get_bytes(stdin, &rh, linebytes, inline) ; X { X register int tmp ; X inptr = inline ; X nextptr = nextline ; X for(j=0; j < rh.ras_width; ++j) X { X if(rh.ras_depth == 32) X ++inptr ; X if( rh.ras_maplength > 0) X { X *nextptr++ = *(colormap.map[0]+*inptr++) ; X *nextptr++ = *(colormap.map[1]+*inptr++) ; X *nextptr++ = *(colormap.map[2]+*inptr++) ; X } X else X { X *nextptr++ = *inptr++ ; X *nextptr++ = *inptr++ ; X *nextptr++ = *inptr++ ; X } X } X } X X for(i=0; i < rh.ras_height-1; ++i) X { X tmpptr = thisline ; X thisline = nextline ; X nextline = tmpptr ; X pr_get_bytes(stdin, &rh, linebytes, inline) ; X { X register int tmp ; X inptr = inline ; X nextptr = nextline ; X for(j=0; j < rh.ras_width; ++j) X { X if(rh.ras_depth == 32) X ++inptr ; X if( rh.ras_maplength > 0) X { X *nextptr++ = *(colormap.map[0]+*inptr++) ; X *nextptr++ = *(colormap.map[1]+*inptr++) ; X *nextptr++ = *(colormap.map[2]+*inptr++) ; X } X else X { X *nextptr++ = *inptr++ ; X *nextptr++ = *inptr++ ; X *nextptr++ = *inptr++ ; X } X } X } X X thisptr = thisline ; X nextptr = nextline ; X outptr = outline; X X /* X * special case: first pixel on line X */ X { X register int tmp,red,green,blue,r2,g2,b2 ; X X FS_GETPIX X X thisptr[0] += blue * 7 / 16 ; X thisptr[1] += green * 7 / 16 ; X thisptr[2] += red * 7 / 16 ; X nextptr[0] += blue * 5 / 16 ; X nextptr[1] += green * 5 / 16 ; X nextptr[2] += red * 5 / 16 ; X nextptr[3] += blue / 16 ; X nextptr[4] += green / 16 ; X nextptr[5] += red / 16 ; X nextptr += 3 ; X } X X X X X /* X * next case: most of the rest of the line X */ X for(j=1; j < rh.ras_width-1 ; ++j) X { X register int tmp,red,green,blue,r2,g2,b2 ; X X FS_GETPIX X thisptr[0] += blue * 7 / 16 ; X thisptr[1] += green * 7 / 16 ; X thisptr[2] += red * 7 / 16 ; X nextptr[-3] += blue * 3 / 16 ; X nextptr[-2] += green * 3 / 16 ; X nextptr[-1] += red * 3 / 16 ; X nextptr[0] += blue * 5 / 16 ; X nextptr[1] += green * 5 / 16 ; X nextptr[2] += red * 5 / 16 ; X nextptr[3] += blue / 16 ; X nextptr[4] += green / 16 ; X nextptr[5] += red / 16 ; X nextptr += 3 ; X } X X /* X * last case: last pixel on line X */ X { X register int tmp,red,green,blue,r2,g2,b2 ; X X FS_GETPIX X nextptr[-3] += blue * 3 / 16 ; X nextptr[-2] += green * 3 / 16 ; X nextptr[-1] += red * 3 / 16 ; X nextptr[0] += blue * 5 / 16 ; X nextptr[1] += green * 5 / 16 ; X nextptr[2] += red * 5 / 16 ; X } X fwrite(outline, 1, olinebytes, stdout) ; X } X X X X /* X * special case: last line: X */ X { X thisline = nextline ; X X thisptr = thisline ; X outptr = outline; X X X X /* X * first case: most of the line X */ X for(j=0; j < rh.ras_width-1 ; ++j) X { X register int tmp,red,green,blue,r2,g2,b2 ; X X FS_GETPIX X thisptr[0] += blue * 7 / 16 ; X thisptr[1] += green * 7 / 16 ; X thisptr[2] += red * 7 / 16 ; X } X X /* X * last case: last pixel on line X */ X { X register int tmp,red,green,blue,r2,g2,b2 ; X X FS_GETPIX X } X fwrite(outline, 1, olinebytes, stdout) ; X } X free(inline) ; X free(thisline) ; X free(nextline) ; X free(outline) ; X} X X X X Xtrim_ctab() X{ X unsigned char *inline ; Xregister unsigned char *inptr ; Xregister int i, j ; X X pr_load_header(stdin, &rh) ; X pr_load_colormap(stdin, &rh, NULL) ; X X pr_read_init(&rh) ; X X inline = (unsigned char *) malloc( linebytes ) ; X X min_r = min_g = min_b = 999 ; X max_r = max_g = max_b = -1 ; X X for(i=0; i < rh.ras_height; ++i) X { X pr_get_bytes(stdin, &rh, linebytes, inline) ; X inptr = inline ; X for(j=0; j < rh.ras_width; ++j) X { X register int red,green,blue ; X X if(rh.ras_depth == 32) X ++inptr ; X blue = *inptr++ ; X green = *inptr++ ; X red = *inptr++ ; X X if (rh.ras_maplength > 0) X { X red = *(colormap.map[0]+red) ; X green = *(colormap.map[1]+green) ; X blue = *(colormap.map[2]+blue) ; X } X X if(red < min_r) min_r = red ; X if(red > max_r) max_r = red ; X if(green < min_g) min_g = green ; X if(green > max_g) max_g = green ; X if(blue < min_b) min_b = blue ; X if(blue > max_b) max_b = blue ; X } X } X X fprintf(stderr,"%d<r<%d, %d<g<%d, %d<b<%d\n", X min_r,max_r, min_g,max_g, min_b,max_b) ; X free(inline) ; X} SHAR_EOF len=`wc -c < dither24to8.c` if test $len != 19177 ; then echo error: dither24to8.c was $len bytes long, should have been 19177 fi fi # end of overwriting check if test -f median.c then echo shar: will not over-write existing file median.c else echo shar: extracting 'median.c', 27988 characters sed 's/^X//' > median.c <<'SHAR_EOF' Xstatic char sccsid[] = "@(#)median.c 1.11 89/01/19 SMI"; X X/* quantize stuff: X * X * median [-csize n] [-fsd] [ifile [ofile]] X * X * -csize n - set colortable size. Default is 256. X * -fsd - use Floyd-Steinberg dithering. X * -ccube - add a 5x5x5 color cube; may reduce FSD artifacts X */ X X X/* Notes: X * X * [1] Floyd-Steinberg dither: X * X * X * I should point out that the actual fractions we used were, assuming X * you are at X, moving left to right: X * X * X 7/16 X * 3/16 5/16 1/16 X * X * Note that the error goes to four neighbors, not three. I think this X * will probably do better (at least for black and white) than the X * 3/8-3/8-1/4 distribution, at the cost of greater processing. I have X * seen the 3/8-3/8-1/4 distribution described as "our" algorithm before, X * but I have no idea who the credit really belongs to. X X * Also, I should add that if you do zig-zag scanning (see my immediately X * previous message), it is sufficient (but not quite as good) to send X * half the error one pixel ahead (e.g. to the right on lines you scan X * left to right), and half one pixel straight down. Again, this is for X * black and white; I've not tried it with color. X * -- X * Lou Steinberg X * X * X * [2] Color Image Quantization for Frame Buffer Display, Paul Heckbert, X * Siggraph '82 proceedings, pp. 297-307 X * X * X */ X X#include <stdio.h> X#include <sys/types.h> X#include <pixrect/pixrect_hs.h> X X#define MAX_CMAP_SIZE 256 X X#define COLOR_DEPTH 8 X#define MAX_COLOR 256 X X#define B_DEPTH 5 /* # bits/pixel to use */ X#define B_LEN (1<<B_DEPTH) X X#define C_DEPTH 2 X#define C_LEN (1<<C_DEPTH) /* # cells/color to use */ X X X Xtypedef struct colorbox { X struct colorbox *next, *prev ; X int rmin,rmax, gmin,gmax, bmin,bmax ; X int total ; X } Colorbox ; X Xtypedef struct { X int num_ents ; X int entries[MAX_CMAP_SIZE][2] ; X } C_cell ; X Xstatic struct rasterfile rh; Xstatic colormap_t colormap, ocmap ; Xstatic unsigned char rm[MAX_CMAP_SIZE], X gm[MAX_CMAP_SIZE], X bm[MAX_CMAP_SIZE] ; Xstatic int bytes_per_pixel ; Xstatic int linebytes, olinebytes ; Xstatic int num_colors ; X Xstatic int histogram[B_LEN][B_LEN][B_LEN] ; X Xstatic Colorbox *freeboxes ; Xstatic Colorbox *usedboxes ; Xstatic Colorbox *largest_box() ; X Xstatic C_cell **ColorCells ; X X Xstatic char *usage = X"usage: median [-csize n] [-fsd] [ifile [ofile]]\n" ; X X Xmain(argc, argv) X int argc; X char **argv; X{ Xstatic struct rasterfile outheader ; X int i, j ; X int dither = 0 ; X char *ifile_name = NULL, *ofile_name = NULL ; X Colorbox *box_list, *ptr ; X int ccube = 0 ; X X num_colors = MAX_CMAP_SIZE ; X X while(--argc) X { X ++argv ; X if(strcmp(*argv,"-fsd") == 0) X dither = 1 ; X X else if(strcmp(*argv,"-csize") == 0) X { X if(argc < 2) X { X fprintf(stderr,"-csize requires 2 arguments, %s",usage) ; X exit(1) ; X } X else X { X argc -= 1 ; X num_colors = atoi(*++argv) ; X if(num_colors > MAX_CMAP_SIZE) X { X fprintf(stderr,"-csize specifies colormap greater than %d\n%s", X MAX_CMAP_SIZE,usage) ; X exit(1) ; X } X } X } X X else if(strcmp(*argv,"-ccube") == 0) X ++ccube ; X X else if(**argv == '-') X { X fprintf(stderr,"unknown argument '%s'\n%s",*argv,usage) ; X exit(1) ; X } X X else if(!ifile_name) X { X ifile_name = *argv ; X } X X else if(!ofile_name) X { X ofile_name = *argv ; X } X X else X { X fprintf(stderr, "Too many file names\n%s",usage) ; X exit(1) ; X } X } X X if(ifile_name) X if (freopen(ifile_name, "r", stdin) == NULL) X { X fprintf(stderr,"Cannot open input file %s\n%s", ifile_name,usage); X exit(1); X } X X if(ofile_name) X if (freopen(ofile_name, "w", stdout) == NULL) X { X fprintf(stderr,"Cannot open output file %s\n%s", ofile_name,usage); X exit(1); X } X X X if (pr_load_header(stdin, &rh) != 0 || X pr_load_colormap(stdin, &rh, &colormap) != 0 ) X { X fprintf(stderr,"Error reading rasterfile header.\n"); X exit(1); X } X X X X switch( rh.ras_depth ) X { X case 8: bytes_per_pixel = 1 ; break ; X case 24: bytes_per_pixel = 3 ; break ; X case 32: bytes_per_pixel = 4 ; break ; X default: X fprintf(stderr, "median: unknown image depth: %d\n", rh.ras_depth); X exit(1) ; X } X X linebytes = rh.ras_width * bytes_per_pixel ; X linebytes += linebytes%2 ; X X/* X * PART I - Assign color table X */ X X /* X * STEP 1: create empty boxes X */ X X usedboxes = NULL ; X box_list = freeboxes = X (Colorbox *) malloc( num_colors * sizeof(Colorbox) ) ; X X freeboxes[0].next = &freeboxes[1] ; X freeboxes[0].prev = NULL ; X for(i=1; i<num_colors-1; ++i) X { X freeboxes[i].next = &freeboxes[i+1] ; X freeboxes[i].prev = &freeboxes[i-1] ; X } X freeboxes[num_colors-1].next = NULL ; X freeboxes[num_colors-1].prev = &freeboxes[num_colors-2] ; X X X X /* X * STEP 2: get histogram, initialize first box X */ X X ptr = freeboxes ; X freeboxes = ptr->next ; X if(freeboxes) freeboxes->prev = NULL ; X X ptr->next = usedboxes ; X usedboxes = ptr ; X if(ptr->next) ptr->next->prev = ptr ; X X get_histogram(ptr) ; X X if( fseek(stdin, 0L, 0) != 0) X { X fprintf(stderr, "median: input must be from file\n") ; X exit(1) ; X } X X X X /* X * STEP 3 (optional): assign color boxes from a 5x5x5 color X * cube. X */ X X if( ccube && num_colors > 125 ) X { X register int r,g,b ; X register Colorbox *tmp ; X for( r=0; r<=4; ++r ) X for( g=0; g<=4; ++g ) X for( b=0; b<=4; ++b ) X { X tmp = freeboxes ; X freeboxes = tmp->next ; X if(freeboxes) freeboxes->prev = NULL ; X tmp->next = usedboxes ; X usedboxes = tmp ; X if(tmp->next) tmp->next->prev = tmp ; X tmp->rmin = tmp->rmax = r*B_LEN/4 ; X tmp->gmin = tmp->gmax = g*B_LEN/4 ; X tmp->bmin = tmp->bmax = b*B_LEN/4 ; X tmp->total = 0 ; X } X } X X X X /* X * STEP 4: continually subdivide boxes until no more free X * boxes remain or until all colors assigned. X */ X X while(freeboxes != NULL) X { X ptr = largest_box() ; X if( ptr != NULL ) X splitbox(ptr) ; X else X freeboxes = NULL ; X } X X X X X X X /* X * STEP 5: assign colors to all boxes X */ X X /* extra feature: find dark box and put first */ X for(ptr=usedboxes->next; ptr != NULL; ) X if( ptr->rmax < B_LEN/4 && ptr->gmax < B_LEN/4 && X ptr->bmax < B_LEN/4 ) X { X ptr->prev->next = ptr->next ; X if( ptr->next != NULL ) X ptr->next->prev = ptr->prev ; X ptr->next = usedboxes ; X ptr->prev = NULL ; X ptr->next->prev = ptr ; X usedboxes = ptr ; X ptr = NULL ; X } X else X ptr = ptr->next ; X X for(i=0, ptr=usedboxes; ptr != NULL; ++i, ptr=ptr->next) X assign_color(ptr,&rm[i],&gm[i],&bm[i]) ; X X /* We're done with the boxes now */ X X free(box_list) ; X box_list = freeboxes = usedboxes = NULL ; X X X X X /* X * STEP 6: scan histogram and map all values to closest color X */ X X /* 6a: create cell list as described in Heckbert[2] */ X X { X register C_cell **ptr ; X register int n = C_LEN*C_LEN*C_LEN ; X X ptr = ColorCells = X (C_cell **) malloc(C_LEN*C_LEN*C_LEN * sizeof(C_cell *)); X X while( n-- > 0 ) X *ptr++ = NULL ; X } X X X X X /* 6b: create mapping from truncated pixel space to color X table entries */ X X map_colortable() ; X X X X/* X * PART II - scan image and map rgb values to color table, dithering X * if requested. X */ X X X /* X * STEP 7: scan image, match input values to table entries X */ X X pr_load_header(stdin, &rh) ; X pr_load_colormap(stdin, &rh, &colormap) ; X pr_read_init(&rh) ; X X olinebytes = rh.ras_width ; X olinebytes += olinebytes%2 ; X X outheader.ras_magic = RAS_MAGIC ; X outheader.ras_width = rh.ras_width ; X outheader.ras_height = rh.ras_height ; X outheader.ras_depth = COLOR_DEPTH ; X outheader.ras_length = olinebytes * outheader.ras_height ; X outheader.ras_type = RT_STANDARD ; X outheader.ras_maptype = RMT_EQUAL_RGB ; X outheader.ras_maplength = num_colors*3 ; X X ocmap.type = RMT_EQUAL_RGB ; X ocmap.length = num_colors ; X ocmap.map[0] = rm ; X ocmap.map[1] = gm ; X ocmap.map[2] = bm ; X X pr_dump_header(stdout, &outheader, &ocmap) ; X X if(dither) X quant_fsdither() ; X else X quant() ; X X fclose(stdout) ; X} X X X X X X/* X * This function reads the input, truncates the three colors to X * "B_DEPTH" bits of precision, updates the limits of the colorbox it X * is filling, and calculates a histogram X */ X X Xstatic Xget_histogram(box) Xregister Colorbox *box ; X{ X unsigned char *inline ; Xregister unsigned char *inptr ; X int i ; Xregister int j ; X X X pr_read_init(&rh) ; X X inline = (unsigned char *) malloc( linebytes ) ; X X box->rmin = box->gmin = box->bmin = 999 ; X box->rmax = box->gmax = box->bmax = -1 ; X box->total = rh.ras_height*rh.ras_width ; X X bzero( histogram, sizeof(histogram) ) ; X X X for(i=rh.ras_height; --i >= 0;) X { X pr_get_bytes(stdin, &rh, linebytes, inline) ; X inptr = inline ; X for(j=rh.ras_width; --j >= 0;) X { X register int red,green,blue ; X X switch( rh.ras_depth ) X { X case 8: blue = green = red = *inptr++ ; break ; X case 32: ++inptr ; X case 24: blue = *inptr++ ; green = *inptr++ ; red = *inptr++ ; X } X X if (rh.ras_maplength > 0) X { X red = colormap.map[0][red] ; X green = colormap.map[1][green] ; X blue = colormap.map[2][blue] ; X } X X red >>= (COLOR_DEPTH-B_DEPTH) ; X green >>= (COLOR_DEPTH-B_DEPTH) ; X blue >>= (COLOR_DEPTH-B_DEPTH) ; X X if(red < box->rmin) box->rmin = red ; X if(red > box->rmax) box->rmax = red ; X if(green < box->gmin) box->gmin = green ; X if(green > box->gmax) box->gmax = green ; X if(blue < box->bmin) box->bmin = blue ; X if(blue > box->bmax) box->bmax = blue ; X X ++histogram[red][green][blue] ; X } X } X free(inline) ; X} X X X X X X/* X * This function searches all of the color boxes in the list and returns X * the largest one, where "largest" is defined as the box with the most X * pixels. X * X * It is possible that defining "largest" as the box enclosing X * the most color space might provide better results. I'll have to X * try that sometime. X */ X Xstatic Colorbox * Xlargest_box() X{ Xregister Colorbox *tmp = usedboxes, *ptr = NULL ; Xregister int size = -1 ; X X while(tmp != NULL) X { X if( (tmp->rmax > tmp->rmin || X tmp->gmax > tmp->gmin || X tmp->bmax > tmp->bmin) && tmp->total > size ) X { X ptr = tmp ; X size = tmp->total ; X } X tmp = tmp->next ; X } X return(ptr) ; X} X X X X X/* This function takes a color box and splits it down the middle of its X * longest (r/g/b) axis. "longest" is defined as the axis with the X * largest domain. "middle" is defined as the median (point with X * the same number of pixels on each side). X * X * Both sub-boxes are then compressed until they just barely enclose X * their points. X * X * It is possible that defining "middle" in some other way might X * provide better results. I'll have to try that sometime. X */ X Xstatic Xsplitbox(ptr) Xregister Colorbox *ptr ; X{ X int hist2[B_LEN] ; X int first, last ; Xregister Colorbox *new ; Xregister int *iptr, *histp ; Xregister int i, j ; X enum {RED,GREEN,BLUE} which ; X X /* X * see which axis is the largest, do a histogram along that X * axis. Split at median point. Contract both new boxes to X * fit points and return X */ X X if( (i = ptr->rmax - ptr->rmin) >= (ptr->gmax - ptr->gmin) && X i >= (ptr->bmax - ptr->bmin) ) X which = RED ; X else if( (ptr->gmax - ptr->gmin) >= (ptr->bmax - ptr->bmin) ) X which = GREEN ; X else X which = BLUE ; X X X X /* get histogram along longest axis */ X { X register int ir,ig,ib ; X switch(which) X { X case RED: X histp = &hist2[ptr->rmin] ; X for(ir = ptr->rmin; ir <= ptr->rmax; ++ir) X { X *histp = 0 ; X for(ig = ptr->gmin; ig <= ptr->gmax; ++ig) X { X iptr = &histogram[ir][ig][ptr->bmin] ; X for(ib = ptr->bmin; ib <= ptr->bmax; ++ib) X { X *histp += *iptr ; X ++iptr ; X } X } X ++histp ; X } X first = ptr->rmin; last = ptr->rmax ; X break ; X X case GREEN: X histp = &hist2[ptr->gmin] ; X for(ig = ptr->gmin; ig <= ptr->gmax; ++ig) X { X *histp = 0 ; X for(ir = ptr->rmin; ir <= ptr->rmax; ++ir) X { X iptr = &histogram[ir][ig][ptr->bmin] ; X for(ib = ptr->bmin; ib <= ptr->bmax; ++ib) X { X *histp += *iptr ; X ++iptr ; X } X } X ++histp ; X } X first = ptr->gmin; last = ptr->gmax ; X break ; X X case BLUE: X histp = &hist2[ptr->bmin] ; X for(ib = ptr->bmin; ib <= ptr->bmax; ++ib) X { X *histp = 0 ; X for(ir = ptr->rmin; ir <= ptr->rmax; ++ir) X { X iptr = &histogram[ir][ptr->gmin][ib] ; X for(ig = ptr->gmin; ig <= ptr->gmax; ++ig) X { X *histp += *iptr ; X iptr += B_LEN ; X } X } X ++histp ; X } X first = ptr->bmin; last = ptr->bmax ; X break ; X } X } X X /* find median point */ X { X register int sum, sum2 ; X histp = &hist2[first] ; X X sum2 = ptr->total/2 ; X histp = &hist2[first] ; X sum = 0 ; X for( i=first; i<=last && (sum += *histp++) < sum2; ++i) ; X if( i == first ) ++i ; X } X X /* Create new box, re-allocate points */ X X new = freeboxes ; X freeboxes = new->next ; X if(freeboxes) freeboxes->prev = NULL ; X X if(usedboxes) usedboxes->prev = new ; X new->next = usedboxes ; X usedboxes = new ; X X { X register int sum1,sum2,j ; X int total ; X total = ptr->total ; X histp = &hist2[first] ; X sum1 = 0 ; X for( j = first; j < i; ++j) X sum1 += *histp++ ; X sum2 = 0 ; X for( j = i; j <= last; ++j) X sum2 += *histp++ ; X#ifdef DEBUG X if( sum1+sum2 != total || sum1 == 0 || sum2 == 0 ) X fprintf(stderr, "??? splitbox: sum1=%d, sum2=%d, total=%d\n", X sum1,sum2,total) ; X#endif DEBUG X new->total = sum1 ; X ptr->total = sum2 ; X } X X X new->rmin = ptr->rmin ; X new->rmax = ptr->rmax ; X new->gmin = ptr->gmin ; X new->gmax = ptr->gmax ; X new->bmin = ptr->bmin ; X new->bmax = ptr->bmax ; X switch(which) X { X case RED: X new->rmax = i-1 ; X ptr->rmin = i ; X break ; X X case GREEN: X new->gmax = i-1 ; X ptr->gmin = i ; X break ; X X case BLUE: X new->bmax = i-1 ; X ptr->bmin = i ; X break ; X } X shrinkbox(new) ; X shrinkbox(ptr) ; X} X X X X Xstatic Xshrinkbox(box) Xregister Colorbox *box ; X{ Xregister int *histp ; Xregister int ir,ig,ib ; X X X if(box->rmax > box->rmin) X { X for(ir = box->rmin; ir <= box->rmax; ++ir) X for(ig = box->gmin; ig <= box->gmax; ++ig) X { X histp = &histogram[ir][ig][box->bmin] ; X for(ib = box->bmin; ib <= box->bmax; ++ib) X if( *histp++ != 0 ) X { X box->rmin = ir ; X goto have_rmin ; X } X } Xhave_rmin: X X if(box->rmax > box->rmin) X for(ir = box->rmax; ir >= box->rmin; --ir) X for(ig = box->gmin; ig <= box->gmax; ++ig) X { X histp = &histogram[ir][ig][box->bmin] ; X for(ib = box->bmin; ib <= box->bmax; ++ib) X if( *histp++ != 0 ) X { X box->rmax = ir ; X goto have_rmax ; X } X } X } Xhave_rmax: X X if( box->gmax > box->gmin ) X { X for(ig = box->gmin; ig <= box->gmax; ++ig) X for(ir = box->rmin; ir <= box->rmax; ++ir) X { X histp = &histogram[ir][ig][box->bmin] ; X for(ib = box->bmin; ib <= box->bmax; ++ib) X if( *histp++ != 0 ) X { X box->gmin = ig ; X goto have_gmin ; X } X } Xhave_gmin: X X if( box->gmax > box->gmin ) X for(ig = box->gmax; ig >= box->gmin; --ig) X for(ir = box->rmin; ir <= box->rmax; ++ir) X { X histp = &histogram[ir][ig][box->bmin] ; X for(ib = box->bmin; ib <= box->bmax; ++ib) X if( *histp++ != 0 ) X { X box->gmax = ig ; X goto have_gmax ; X } X } X } Xhave_gmax: X X if( box->bmax > box->bmin ) X { X for(ib = box->bmin; ib <= box->bmax; ++ib) X for(ir = box->rmin; ir <= box->rmax; ++ir) X { X histp = &histogram[ir][box->gmin][ib] ; X for(ig = box->gmin; ig <= box->gmax; ++ig) X { X if( *histp != 0 ) X { X box->bmin = ib ; X goto have_bmin ; X } X histp += B_LEN ; X } X } Xhave_bmin: X X if( box->bmax > box->bmin ) X for(ib = box->bmax; ib >= box->bmin; --ib) X for(ir = box->rmin; ir <= box->rmax; ++ir) X { X histp = &histogram[ir][box->gmin][ib] ; X for(ig = box->gmin; ig <= box->gmax; ++ig) X { X if( *histp != 0 ) X { X box->bmax = ib ; X goto have_bmax ; X } X histp += B_LEN ; X } X } X } Xhave_bmax: return ; X} X X X X X/* X * This function assigns a color to a color box. Currently, the resulting X * color is the center of the box. X * X * It is possible that a histogram-weighted center would provide better X * results, but I seem to have tried that and not liked the results. X */ X X Xstatic Xassign_color(ptr,rp,gp,bp) Xregister Colorbox *ptr ; X unsigned char *rp,*gp,*bp ; X{ Xregister int *histp ; Xregister int ir,ig,ib ; Xregister long red = 0, green = 0, blue = 0 ; X X *rp = ((ptr->rmin + ptr->rmax) << (COLOR_DEPTH - B_DEPTH)) / 2 ; X *gp = ((ptr->gmin + ptr->gmax) << (COLOR_DEPTH - B_DEPTH)) / 2 ; X *bp = ((ptr->bmin + ptr->bmax) << (COLOR_DEPTH - B_DEPTH)) / 2 ; X X#ifdef COMMENT X#ifdef DEBUG X if( ptr->total <= 0 ) X { X fprintf(stderr,"??? assign_color: total = %d\n",ptr->total) ; X return ; X } X#endif DEBUG X X for( ir = ptr->rmin; ir <= ptr->rmax; ++ir) X for( ig = ptr->gmin; ig <= ptr->gmax; ++ig) X { X histp = &histogram[ir][ig][ptr->bmin] ; X for( ib = ptr->bmin; ib <= ptr->bmax; ++ib) X { X if( *histp != 0 ) X { X red += ir * *histp ; X green += ig * *histp ; X blue += ib * *histp ; X } X ++histp ; X } X } X X *rp = (red << (COLOR_DEPTH - B_DEPTH)) / ptr->total ; X *gp = (green << (COLOR_DEPTH - B_DEPTH)) / ptr->total ; X *bp = (blue << (COLOR_DEPTH - B_DEPTH)) / ptr->total ; X#endif COMMENT X} X X X Xstatic C_cell * Xcreate_colorcell(red,green,blue) X int red,green,blue ; X{ Xregister int ir,ig,ib, i ; X int mindist ; Xregister C_cell *ptr ; X X ir = red >> (COLOR_DEPTH-C_DEPTH) ; X ig = green >> (COLOR_DEPTH-C_DEPTH) ; X ib = blue >> (COLOR_DEPTH-C_DEPTH) ; X X#ifdef COMMENT X red &= ~0 << (COLOR_DEPTH-C_DEPTH) ; X green &= ~0 << (COLOR_DEPTH-C_DEPTH) ; X blue &= ~0 << (COLOR_DEPTH-C_DEPTH) ; X#endif COMMENT X X ptr = (C_cell *) malloc( sizeof(C_cell) ) ; X *( ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib ) = ptr ; X X ptr->num_ents = 0 ; X X X /* step 1: find all colors inside this cell, while we're at X it, find distance of centermost point to furthest X corner */ X X mindist = 99999999 ; X for(i=0; i<num_colors; ++i) X if( rm[i]>>(COLOR_DEPTH-C_DEPTH) == ir && X gm[i]>>(COLOR_DEPTH-C_DEPTH) == ig && X bm[i]>>(COLOR_DEPTH-C_DEPTH) == ib) X { X register int tmp, dist ; X X ptr->entries[ptr->num_ents][0] = i ; X ptr->entries[ptr->num_ents][1] = 0 ; X ++ptr->num_ents ; X X tmp = rm[i] - red ; X if( tmp < (MAX_COLOR/C_LEN/2) ) X tmp = MAX_COLOR/C_LEN-1 - tmp ; X dist = tmp*tmp ; X X tmp = gm[i] - green ; X if( tmp < (MAX_COLOR/C_LEN/2) ) X tmp = MAX_COLOR/C_LEN-1 - tmp ; X dist += tmp*tmp ; X X tmp = bm[i] - blue ; X if( tmp < (MAX_COLOR/C_LEN/2) ) X tmp = MAX_COLOR/C_LEN-1 - tmp ; X dist += tmp*tmp ; X X if( dist < mindist ) X mindist = dist ; X } X X X /* step 3: find all points within that distance to cell */ X X for( i=0; i<num_colors; ++i ) X { X register int dist, tmp ; X X if( rm[i] >> (COLOR_DEPTH-C_DEPTH) != ir || X gm[i] >> (COLOR_DEPTH-C_DEPTH) != ig || X bm[i] >> (COLOR_DEPTH-C_DEPTH) != ib) X { X dist = 0 ; X X if( (tmp = red - rm[i]) > 0 || X (tmp = rm[i] - (red + MAX_COLOR/C_LEN-1)) > 0 ) X dist += tmp*tmp ; X X if( (tmp = green - gm[i]) > 0 || X (tmp = gm[i] - (green + MAX_COLOR/C_LEN-1)) > 0 ) X dist += tmp*tmp ; X X if( (tmp = blue - bm[i]) > 0 || X (tmp = bm[i] - (blue + MAX_COLOR/C_LEN-1)) > 0 ) X dist += tmp*tmp ; X X if( dist < mindist ) X { X ptr->entries[ptr->num_ents][0] = i ; X ptr->entries[ptr->num_ents][1] = dist ; X ++ptr->num_ents ; X } X } X } X X /* sort color cells by distance, use cheap exchange sort */ X { X register int n, tmp, i ; X int next_n ; X X n = ptr->num_ents - 1 ; X while( n > 0 ) X { X next_n = 0 ; X for( i=0; i<n; ++i) X { X if( ptr->entries[i][1] > ptr->entries[i+1][1] ) X { X tmp = ptr->entries[i][0] ; X ptr->entries[i][0] = ptr->entries[i+1][0] ; X ptr->entries[i+1][0] = tmp ; X tmp = ptr->entries[i][1] ; X ptr->entries[i][1] = ptr->entries[i+1][1] ; X ptr->entries[i+1][1] = tmp ; X next_n = i ; X } X } X n = next_n ; X } X } X return( ptr ) ; X} X X X X Xstatic Xmap_colortable() X{ X int ir,ig,ib ; Xregister int *histp = &histogram[0][0][0] ; Xregister C_cell *cell ; X X for(ir = 0; ir < B_LEN; ++ir) X for(ig = 0; ig < B_LEN; ++ig) X for(ib = 0; ib < B_LEN; ++ib) X { X if( *histp == 0 ) X *histp = -1 ; X else X { X int i ; X register int j, tmp, d2, dist ; X X cell = *( ColorCells + ( ((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) X + ((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH ) X + (ib>>(B_DEPTH-C_DEPTH)) ) ) ; X X if(cell == NULL ) X cell = create_colorcell( ir<<(COLOR_DEPTH-B_DEPTH), X ig<<(COLOR_DEPTH-B_DEPTH), X ib<<(COLOR_DEPTH-B_DEPTH) ) ; X X dist = 9999999 ; X for(i = 0; X i < cell->num_ents && dist > cell->entries[i][1] ; X ++i) X { X j = cell->entries[i][0] ; X d2 = rm[j] - (ir << (COLOR_DEPTH-B_DEPTH)) ; X d2 *= d2 ; X tmp = gm[j] - (ig << (COLOR_DEPTH-B_DEPTH)) ; X d2 += tmp*tmp ; X tmp = bm[j] - (ib << (COLOR_DEPTH-B_DEPTH)) ; X d2 += tmp*tmp ; X if( d2 < dist ) X { X dist = d2 ; X *histp = j ; X } X } X#ifdef DEBUG X if( dist == 9999999 ) X fprintf(stderr,"??? map_colortable: dist=9999999\n") ; X#endif DEBUG X } X ++histp ; X } X} X X X X X X X X X X X/* X * straight quantization. Each pixel is mapped to the colors X * closest to it. Color values are rounded to the nearest color X * table entry. X */ X Xstatic Xquant() X{ X unsigned char *outline ; X unsigned char *inline ; Xregister unsigned char *outptr ; Xregister unsigned char *inptr ; Xregister int i, j ; X X X X X inline = (unsigned char *) malloc( linebytes ) ; X X outline = (unsigned char *) malloc( olinebytes ) ; X X for(i=0; i < rh.ras_height; ++i) X { X pr_get_bytes(stdin, &rh, linebytes, inline) ; X inptr = inline ; X outptr = outline; X for(j=0; j < rh.ras_width; ++j) X { X register int tmp,red,green,blue ; X X switch( rh.ras_depth ) X { X case 8: blue = green = red = *inptr++ ; break ; X case 32: ++inptr ; X case 24: blue = *inptr++ ; green = *inptr++ ; red = *inptr++ ; X } X X if (rh.ras_maplength > 0) X { X red = colormap.map[0][red] ; X green = colormap.map[1][green] ; X blue = colormap.map[2][blue] ; X } X X red >>= (COLOR_DEPTH-B_DEPTH) ; X green >>= (COLOR_DEPTH-B_DEPTH) ; X blue >>= (COLOR_DEPTH-B_DEPTH) ; X X *outptr++ = histogram[red][green][blue] ; X } X fwrite(outline, 1, olinebytes, stdout) ; X } X free(inline) ; X free(outline) ; X} X X X X X Xstatic Xquant_fsdither() X{ X unsigned char *outline, *inline ; X short *thisline, *nextline, *tmpptr ; X unsigned char *inptr ; Xregister unsigned char *outptr ; Xregister short *thisptr, *nextptr ; Xregister int i, j ; X int imax, jmax ; X int lastline, lastpixel ; X X X imax = rh.ras_height - 1 ; X jmax = rh.ras_width - 1 ; X X inline = (unsigned char *) malloc( linebytes ) ; X thisline = (short *) malloc( rh.ras_width * 3 * sizeof(short)) ; X nextline = (short *) malloc( rh.ras_width * 3 * sizeof(short)) ; X X outline = (unsigned char *) malloc( olinebytes ) ; X X /* X * get first line X */ X pr_get_bytes(stdin, &rh, linebytes, inline) ; X { X inptr = inline ; X nextptr = nextline ; X for(j=0; j < rh.ras_width; ++j) X { X register int red,green,blue ; X X switch( rh.ras_depth ) X { X case 8: blue = green = red = *inptr++ ; break ; X case 32: ++inptr ; X case 24: blue = *inptr++ ; green = *inptr++ ; red = *inptr++ ; X } X X if (rh.ras_maplength > 0) X { X red = colormap.map[0][red] ; X green = colormap.map[1][green] ; X blue = colormap.map[2][blue] ; X } X *nextptr++ = blue ; X *nextptr++ = green ; X *nextptr++ = red ; X } X } X X for(i=0; i < rh.ras_height; ++i) X { X tmpptr = thisline ; X thisline = nextline ; X nextline = tmpptr ; X lastline = (i == imax) ; X pr_get_bytes(stdin, &rh, linebytes, inline) ; X { X register int red,green,blue ; X X inptr = inline ; X nextptr = nextline ; X for(j=0; j < rh.ras_width; ++j) X { X switch( rh.ras_depth ) X { X case 8: blue = green = red = *inptr++ ; break ; X case 32: ++inptr ; X case 24: blue = *inptr++ ; green = *inptr++ ; red = *inptr++ ; X } X X if (rh.ras_maplength > 0) X { X red = colormap.map[0][red] ; X green = colormap.map[1][green] ; X blue = colormap.map[2][blue] ; X } X *nextptr++ = blue ; X *nextptr++ = green ; X *nextptr++ = red ; X } X } X X thisptr = thisline ; X nextptr = nextline ; X outptr = outline; X X for(j=0; j < rh.ras_width ; ++j) X { X int red,green,blue ; X register int oval, r2,g2,b2 ; X X lastpixel = (j == jmax) ; X X if( (b2 = *thisptr++) < 0 ) b2 = 0 ; X else if( b2 >= MAX_COLOR ) b2 = MAX_COLOR-1 ; X if( (g2 = *thisptr++) < 0 ) g2 = 0 ; X else if( g2 >= MAX_COLOR ) g2 = MAX_COLOR-1 ; X if( (r2 = *thisptr++) < 0 ) r2 = 0 ; X else if( r2 >= MAX_COLOR ) r2 = MAX_COLOR-1 ; X X red = r2 ; X green = g2 ; X blue = b2 ; X X r2 >>= (COLOR_DEPTH-B_DEPTH) ; X g2 >>= (COLOR_DEPTH-B_DEPTH) ; X b2 >>= (COLOR_DEPTH-B_DEPTH) ; X X if( (oval = histogram[r2][g2][b2]) == -1) X { X int ci ; X register int cj, tmp, d2, dist ; X register C_cell *cell ; X X cell = *( ColorCells + ( ((r2>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) X + ((g2>>(B_DEPTH-C_DEPTH)) << C_DEPTH ) X + (b2>>(B_DEPTH-C_DEPTH)) ) ) ; X X if(cell == NULL ) X cell = create_colorcell( red, green, blue ) ; X X X dist = 9999999 ; X for(ci = 0; X ci < cell->num_ents && dist > cell->entries[ci][1] ; X ++ci) X { X cj = cell->entries[ci][0] ; X d2 = (rm[cj] >> (COLOR_DEPTH-B_DEPTH)) - r2 ; X d2 *= d2 ; X tmp = (gm[cj] >> (COLOR_DEPTH-B_DEPTH)) - g2 ; X d2 += tmp*tmp ; X tmp = (bm[cj] >> (COLOR_DEPTH-B_DEPTH)) - b2 ; X d2 += tmp*tmp ; X if( d2 < dist ) X { X dist = d2 ; X oval = cj ; X } X } X histogram[r2][g2][b2] = oval ; X#ifdef DEBUG X if( dist == 9999999 ) X fprintf(stderr,"??? quant: dist=9999999\n") ; X#endif DEBUG X } X X *outptr++ = oval ; X X r2 = (red -= rm[oval]) ; X g2 = (green -= gm[oval]) ; X b2 = (blue -= bm[oval]) ; X X X if( !lastline ) X { X if( j != 0 ) X { X nextptr[-3] += b2 * 3 / 16 ; X nextptr[-2] += g2 * 3 / 16 ; X nextptr[-1] += r2 * 3 / 16 ; X } X nextptr[0] += b2 * 5 / 16 ; X nextptr[1] += g2 * 5 / 16 ; X nextptr[2] += r2 * 5 / 16 ; X if( !lastpixel ) X { X nextptr[3] += b2 / 16 ; X nextptr[4] += g2 / 16 ; X nextptr[5] += r2 / 16 ; X } X nextptr += 3 ; X } X if( !lastpixel ) X { X red -= r2 * 3 / 16 ; X red -= r2 * 5 / 16 ; X red -= r2 / 16 ; X green -= g2 * 3 / 16 ; X green -= g2 * 5 / 16 ; X green -= g2 / 16 ; X blue -= b2 * 3 / 16 ; X blue -= b2 * 5 / 16 ; X blue -= b2 / 16 ; X thisptr[0] += blue ; X thisptr[1] += green ; X thisptr[2] += red ; X } X } X fwrite(outline, 1, olinebytes, stdout) ; X } X free(inline) ; X free(thisline) ; X free(nextline) ; X free(outline) ; X} X X X X X#ifdef DEBUG Xshowboxes() X{ X Colorbox *ptr ; X X printf("boxes:\n") ; X ptr = usedboxes ; X while(ptr != NULL) X { X printf(" %d<r<%d, %d<g<%d, %d<b<%d\n", ptr->rmin,ptr->rmax, X ptr->gmin,ptr->gmax, ptr->bmin,ptr->bmax) ; X ptr = ptr->next ; X } X} X X X Xshowcell(ptr) Xregister C_cell *ptr ; X{ X int i ; X int j ; X X fprintf(stderr, "n=%d\n", ptr->num_ents) ; X for(i=0; i<ptr->num_ents; ++i) X { X j = ptr->entries[i][0] ; X fprintf(stderr, "(%d,%d): (%d,%d,%d)\n", X j, ptr->entries[i][1], rm[j],gm[j],bm[j]) ; X } X} X X X Xint Xtestbox(box) Xregister Colorbox *box ; X{ Xregister int ir,ig,ib, total ; X X total = 0 ; X for(ir=box->rmin; ir<=box->rmax; ++ir) X for(ig=box->gmin; ig<=box->gmax; ++ig) X for(ib=box->bmin; ib<=box->bmax; ++ib) X total += histogram[ir][ig][ib] ; X X return total ; X} X#endif DEBUG SHAR_EOF len=`wc -c < median.c` if test $len != 27988 ; then echo error: median.c was $len bytes long, should have been 27988 fi fi # end of overwriting check if test -f pr_stream.c then echo shar: will not over-write existing file pr_stream.c else echo shar: extracting 'pr_stream.c', 3512 characters sed 's/^X//' > pr_stream.c <<'SHAR_EOF' X/* pr_stream routines: allow images to be read in stream X * fashion rather than loading them into memory. X * X * These routines are used in conjunction with the pr_io routines. It X * is the application's responsibility to read the header and X * colormaps X * X * X * routines: X * X * pr_read_init(header) X * struct rasterfile *header ; X * X * sets up to read an image X * X * X * pr_get_bytes(file, header, len, buffer) X * FILE *file ; X * struct rasterfile *header ; X * int len ; X * char *buffer ; X * X * read data from input. len should be a multiple of 3 for 24-bit X * images and a multiple of 4 for 32-bit images. X * X * X * int X * pr_get_byte(file, header) X * FILE *file ; X * struct rasterfile *header ; X * X * read and return one byte from input X * X */ X X#include <stdio.h> X#include <sys/types.h> X#include <pixrect/pixrect.h> X#include <pixrect/memvar.h> X#include <pixrect/pr_io.h> X#include <rasterfile.h> X X#define ESCAPE 128 X X X Xstatic unsigned char icvalue ; Xstatic int icount ; Xstatic unsigned char icalpha, icblue, icgreen, icred ; X X X Xint Xpr_read_init(header) X struct rasterfile *header ; X{ X icount = 0 ; X} X X X Xint Xpr_get_bytes(file, header, len, buffer) Xregister FILE *file ; Xregister struct rasterfile *header ; Xregister int len ; Xregister unsigned char *buffer ; X{ X if(header->ras_type != RT_BYTE_ENCODED) X return( fread(buffer, 1, len, file) ) ; X X else X switch( header->ras_depth ) X { X case 1: X case 8: X while( --len >= 0) X { X if(icount > 0) X { X --icount ; X *buffer++ = icvalue ; X } X else X { X if( (icvalue = getc(file)) != ESCAPE ) X *buffer++ = icvalue ; X else X { X if( (icount = getc(file)) == 0 ) X *buffer++ = ESCAPE ; X else X { X *buffer++ = icvalue = getc(file) ; X } X } X } X } X break ; X X case 24: X len /= 3 ; X while( len-- > 0 ) X { X if(icount > 0) X { X --icount ; X *buffer++ = icblue ; X *buffer++ = icgreen ; X *buffer++ = icred ; X } X else X { X if( (icvalue = getc(file)) != ESCAPE ) X { X *buffer++ = icvalue ; X *buffer++ = getc(file) ; X *buffer++ = getc(file) ; X } X else X { X if( (icount = getc(file)) == 0 ) X { X *buffer++ = ESCAPE ; X *buffer++ = getc(file) ; X *buffer++ = getc(file) ; X } X else X { X *buffer++ = icblue = getc(file) ; X *buffer++ = icgreen = getc(file) ; X *buffer++ = icred = getc(file) ; X } X } X } X } X break ; X X case 32: X len /= 4 ; X while( len-- > 0 ) X { X if(icount > 0) X { X --icount ; X *buffer++ = icalpha ; X *buffer++ = icblue ; X *buffer++ = icgreen ; X *buffer++ = icred ; X } X else X { X if( (icvalue = getc(file)) != ESCAPE ) X { X *buffer++ = icvalue ; X *buffer++ = getc(file) ; X *buffer++ = getc(file) ; X *buffer++ = getc(file) ; X } X else X { X if( (icount = getc(file)) == 0 ) X { X *buffer++ = ESCAPE ; X *buffer++ = getc(file) ; X *buffer++ = getc(file) ; X *buffer++ = getc(file) ; X } X else X { X *buffer++ = icalpha = getc(file) ; X *buffer++ = icblue = getc(file) ; X *buffer++ = icgreen = getc(file) ; X *buffer++ = icred = getc(file) ; X } X } X } X } X break ; X } X X X X return 0 ; X} X X X Xunsigned char Xpr_get_byte(file, header) X FILE *file ; X struct rasterfile *header ; X{ X unsigned char rval ; X X pr_get_bytes(file, header, 1, &rval) ; X return( rval ) ; X} SHAR_EOF len=`wc -c < pr_stream.c` if test $len != 3512 ; then echo error: pr_stream.c was $len bytes long, should have been 3512 fi fi # end of overwriting check exit 0 -- -ed falk, sun microsystems sun!falk, falk@sun.com card-carrying ACLU member.
falk@sun.uucp (Ed Falk) (02/03/89)
OOOPS. I forgot a header file, ntsc.h. Here it is: static unsigned int ntscr[] = { 0, 77, 153, 230, 306, 383, 459, 536, 612, 689, 765, 842, 919, 995, 1072, 1148, 1225, 1301, 1378, 1454, 1531, 1607, 1684, 1761, 1837, 1914, 1990, 2067, 2143, 2220, 2296, 2373, 2449, 2526, 2602, 2679, 2756, 2832, 2909, 2985, 3062, 3138, 3215, 3291, 3368, 3444, 3521, 3598, 3674, 3751, 3827, 3904, 3980, 4057, 4133, 4210, 4286, 4363, 4440, 4516, 4593, 4669, 4746, 4822, 4899, 4975, 5052, 5128, 5205, 5282, 5358, 5435, 5511, 5588, 5664, 5741, 5817, 5894, 5970, 6047, 6124, 6200, 6277, 6353, 6430, 6506, 6583, 6659, 6736, 6812, 6889, 6966, 7042, 7119, 7195, 7272, 7348, 7425, 7501, 7578, 7654, 7731, 7807, 7884, 7961, 8037, 8114, 8190, 8267, 8343, 8420, 8496, 8573, 8649, 8726, 8803, 8879, 8956, 9032, 9109, 9185, 9262, 9338, 9415, 9491, 9568, 9645, 9721, 9798, 9874, 9951,10027,10104,10180,10257,10333, 10410,10487,10563,10640,10716,10793,10869,10946, 11022,11099,11175,11252,11329,11405,11482,11558, 11635,11711,11788,11864,11941,12017,12094,12170, 12247,12324,12400,12477,12553,12630,12706,12783, 12859,12936,13012,13089,13166,13242,13319,13395, 13472,13548,13625,13701,13778,13854,13931,14008, 14084,14161,14237,14314,14390,14467,14543,14620, 14696,14773,14850,14926,15003,15079,15156,15232, 15309,15385,15462,15538,15615,15692,15768,15845, 15921,15998,16074,16151,16227,16304,16380,16457, 16534,16610,16687,16763,16840,16916,16993,17069, 17146,17222,17299,17375,17452,17529,17605,17682, 17758,17835,17911,17988,18064,18141,18217,18294, 18371,18447,18524,18600,18677,18753,18830,18906, 18983,19059,19136,19213,19289,19366,19442,19519,} ; static unsigned int ntscg[] = { 0, 150, 301, 451, 601, 751, 902, 1052, 1202, 1352, 1503, 1653, 1803, 1954, 2104, 2254, 2404, 2555, 2705, 2855, 3005, 3156, 3306, 3456, 3607, 3757, 3907, 4057, 4208, 4358, 4508, 4658, 4809, 4959, 5109, 5260, 5410, 5560, 5710, 5861, 6011, 6161, 6311, 6462, 6612, 6762, 6913, 7063, 7213, 7363, 7514, 7664, 7814, 7964, 8115, 8265, 8415, 8566, 8716, 8866, 9016, 9167, 9317, 9467, 9617, 9768, 9918,10068,10218,10369,10519,10669, 10820,10970,11120,11270,11421,11571,11721,11871, 12022,12172,12322,12473,12623,12773,12923,13074, 13224,13374,13524,13675,13825,13975,14126,14276, 14426,14576,14727,14877,15027,15177,15328,15478, 15628,15779,15929,16079,16229,16380,16530,16680, 16830,16981,17131,17281,17432,17582,17732,17882, 18033,18183,18333,18483,18634,18784,18934,19085, 19235,19385,19535,19686,19836,19986,20136,20287, 20437,20587,20738,20888,21038,21188,21339,21489, 21639,21789,21940,22090,22240,22391,22541,22691, 22841,22992,23142,23292,23442,23593,23743,23893, 24044,24194,24344,24494,24645,24795,24945,25095, 25246,25396,25546,25697,25847,25997,26147,26298, 26448,26598,26748,26899,27049,27199,27350,27500, 27650,27800,27951,28101,28251,28401,28552,28702, 28852,29002,29153,29303,29453,29604,29754,29904, 30054,30205,30355,30505,30655,30806,30956,31106, 31257,31407,31557,31707,31858,32008,32158,32308, 32459,32609,32759,32910,33060,33210,33360,33511, 33661,33811,33961,34112,34262,34412,34563,34713, 34863,35013,35164,35314,35464,35614,35765,35915, 36065,36216,36366,36516,36666,36817,36967,37117, 37267,37418,37568,37718,37869,38019,38169,38319,} ; static unsigned int ntscb[] = { 0, 29, 58, 88, 117, 146, 175, 204, 233, 263, 292, 321, 350, 379, 409, 438, 467, 496, 525, 554, 584, 613, 642, 671, 700, 730, 759, 788, 817, 846, 876, 905, 934, 963, 992, 1021, 1051, 1080, 1109, 1138, 1167, 1197, 1226, 1255, 1284, 1313, 1342, 1372, 1401, 1430, 1459, 1488, 1518, 1547, 1576, 1605, 1634, 1663, 1693, 1722, 1751, 1780, 1809, 1839, 1868, 1897, 1926, 1955, 1985, 2014, 2043, 2072, 2101, 2130, 2160, 2189, 2218, 2247, 2276, 2306, 2335, 2364, 2393, 2422, 2451, 2481, 2510, 2539, 2568, 2597, 2627, 2656, 2685, 2714, 2743, 2772, 2802, 2831, 2860, 2889, 2918, 2948, 2977, 3006, 3035, 3064, 3094, 3123, 3152, 3181, 3210, 3239, 3269, 3298, 3327, 3356, 3385, 3415, 3444, 3473, 3502, 3531, 3560, 3590, 3619, 3648, 3677, 3706, 3736, 3765, 3794, 3823, 3852, 3881, 3911, 3940, 3969, 3998, 4027, 4057, 4086, 4115, 4144, 4173, 4202, 4232, 4261, 4290, 4319, 4348, 4378, 4407, 4436, 4465, 4494, 4524, 4553, 4582, 4611, 4640, 4669, 4699, 4728, 4757, 4786, 4815, 4845, 4874, 4903, 4932, 4961, 4990, 5020, 5049, 5078, 5107, 5136, 5166, 5195, 5224, 5253, 5282, 5311, 5341, 5370, 5399, 5428, 5457, 5487, 5516, 5545, 5574, 5603, 5633, 5662, 5691, 5720, 5749, 5778, 5808, 5837, 5866, 5895, 5924, 5954, 5983, 6012, 6041, 6070, 6099, 6129, 6158, 6187, 6216, 6245, 6275, 6304, 6333, 6362, 6391, 6420, 6450, 6479, 6508, 6537, 6566, 6596, 6625, 6654, 6683, 6712, 6742, 6771, 6800, 6829, 6858, 6887, 6917, 6946, 6975, 7004, 7033, 7063, 7092, 7121, 7150, 7179, 7208, 7238, 7267, 7296, 7325, 7354, 7384, 7413, 7442,} ; -- -ed falk, sun microsystems sun!falk, falk@sun.com card-carrying ACLU member.
mpksla%ritcv@cs.rit.edu (Michael Kirby) (02/08/89)
We have compiled the code posted earlier for optimizing a 24 bit image to an 8 bit image (Dither24to8 and Median, posted by Ed Falk). We are aware that the program should take a 24 bit rasterfile, but dont know the format for one. We are aware of how to use rasterfiles but dont wish to trudge through all the code to find what the exact format is. Any clues? -Michael Kirby & Eric S. Law mpk9172%ucss@cs.rit.edu rochester!ritcv!mpk9172 mpk9172@ritvax.bitnet esl0422%ucss@cs.rit.edu rochester!ritcv!esl0422 esl0422@ritvax.bitnet "Who else ray-traces out there?"