jevans@.ucalgary.ca (David Jevans) (09/28/88)
I have received so many requests for the source for my program which will display a 24bit color image on an 8bit color sun that I have decided to post it to the net. A few things have changed since last week however: 1) I am posting the source for a version that was hacked over by another researcher here. This code has been optimised a little but there have been two major changes: a) it supports a color sun or an 8bitplane iris b) it supports my simple format and our run-length-encoded format. 2) It seems there may be a bug somewhere in the octree reduction code. 3) The code will attempt to read a file with the 8bit colortable entries etc. If it cannot find this file it will read the 24bit image and create this file and then display it. This means that once you have displayed a picture once, the 256 elem colortable does not need to be re-calculated. Due to these mods the code has grown (almost doubled) in length. There are #ifdefs throughout, so if you only want a sun version or only an iris version you can spend a few minutes in emacs... Also, someone told me that the program bombed when it got halfway through displaying his file. It seems it thought it couldn't reduce the octree any further. This of course means that there could be a bug in the octree reduction code but I am sorry, I have no time to look into it. Use the code at your own risk. If anyone finds and fixes it why not post it to the net? The paper which describes the algorithm is in the proceedings of Computer Graphics International 1988, published by Springer-Verlag. BTW it should only take a few minutes for anyone to change the program to use their image format... the files are read in in main() at the bottom of the program. ----- makefile ----- cut here ----- makefile ----- cut here ----- makefile -- DEBUG = -g all: irisb_8_ras irisb: irisb_8_cd irisb_8_ras sun3: sun3_8_cd sun3_8_ras sun4: sun4_8_cd sun4_8_ras irisb_8_cd: 8_bit.c cc $(DEBUG) -DCDISP -DIRIS -o irisb_8_cd 8_bit.c -lgl irisb_8_ras: 8_bit.c cc $(DEBUG) -DRAS -DIRIS -o irisb_8_ras 8_bit.c -lgl sun3_8_cd: 8_bit.c cc $(DEBUG) -DCDISP -DSUN3 -o sun3_8_cd 8_bit.c -lpixrect sun3_8_ras: 8_bit.c cc $(DEBUG) -DRAS -DSUN3 -o sun3_8_ras 8_bit.c -lpixrect sun4_8_cd: 8_bit.c cc $(DEBUG) -DCDISP -DSUN4 -o sun4_8_cd 8_bit.c sun4_8_ras: 8_bit.c cc $(DEBUG) -DRAS -DSUN4 -o sun4_8_ras 8_bit.c ----- 8_bit.c ----- cut here ----- 8_bit.c ----- cut here ----- 8_bit.c -- /*************************************************************************/ /* Used to cdisp & .ras format files to an 8 bitplane device such as a /* colour sun or Iris B (also make intermediate files on sun4 for wails) /* Original algorithm implemented by Dave Jevans /* Hacked for 8bit iris etc. by Chris Bone /*************************************************************************/ /* clever includes */ #include <stdio.h> #ifdef IRIS #include <gl.h> #include <device.h> #endif #ifdef SUN3 #include <pixrect/pixrect_hs.h> #endif /* wiggy types */ #ifdef SUN4 typedef unsigned char RGBvalue; typedef unsigned short Colorindex; #endif #ifdef SUN3 typedef unsigned char RGBvalue; typedef unsigned short Colorindex; #endif /* fancy extensions */ #ifdef CDISP #define EXTENSION ".8_bit_cdisp" #endif #ifdef RAS #define EXTENSION ".8_bit_ras" #endif #define MAXCOLORS 256 /* pixrect for screen */ #ifdef SUN3 struct pixrect *screen; #endif struct node { RGBvalue leaf; RGBvalue rgb[3]; int numtimes; int index; struct node *octrees[8]; struct node *next; }; static struct node *reducible[8], root; static int numcolors = 0, numcolormap = 0; RGBvalue lutr[256],lutg[256],lutb[256]; int do_gfx_stuff; /* former functions... now macros for wails */ #define whichoctree(rgb, depth) (((rgb[0] & (1 << 7-depth)) >> 7-depth) << 1 | ((rgb[1] & (1 << 7-depth)) >> 7-depth)) << 1 | ((rgb[2] & (1 << 7-depth)) >> 7-depth) #define makereducible(o,d) {o->next=reducible[d]; reducible[d]=o;} #define findcolor(rgb) find(rgb,&root,0) /* reduce the deepest octree nodes */ reduce() { register depth; struct node *octree; register a, numoctrees, numtimes; int rgb[3],nt; for(depth = 7; depth >= 0; depth--) if(reducible[depth]) break; if(depth < 0){ fprintf(stderr, "reduce: nothing to reduce, %d colors\n", numcolors); exit(-1); } octree = reducible[depth]; reducible[depth] = octree->next; octree->next = NULL; /* just to be safe */ rgb[0] = rgb[1] = rgb[2] = 0; for(a = numoctrees = numtimes = 0; a < 8; a++) if(octree->octrees[a]){ numoctrees++; numtimes += octree->octrees[a]->numtimes; nt=octree->octrees[a]->numtimes; rgb[0] += octree->octrees[a]->rgb[0] * nt; rgb[1] += octree->octrees[a]->rgb[1] * nt; rgb[2] += octree->octrees[a]->rgb[2] * nt; numcolors--; free(octree->octrees[a]); octree->octrees[a] = NULL; /* just to be safe */ } if(numoctrees == 0){ fprintf(stderr, "reduce: only %d to reduce! need >= 2.\n", numoctrees); exit(-1); } if(numtimes == 0){ fprintf(stderr, "reduce: colors occured 0 times!?!\n"); exit(-1); } octree->rgb[0] = rgb[0] / numtimes; octree->rgb[1] = rgb[1] / numtimes; octree->rgb[2] = rgb[2] / numtimes; octree->numtimes = numtimes; octree->leaf = 1; numcolors++; } /* insert a new color into the octree. this may involve deepening the octree. */ struct node *insert(rgb, octree, depth,count) RGBvalue rgb[3]; struct node *octree; int depth; int count; { struct node *o; register a,wo; if(!octree){ if(!(o = (struct node *)malloc(sizeof(struct node)))){ fprintf(stderr, "insert: out of mems\n"); exit(-1); } o->leaf = 1; o->rgb[0] = rgb[0]; o->rgb[1] = rgb[1]; o->rgb[2] = rgb[2]; o->numtimes = count; numcolors++; return(o); }else if(octree->leaf){ if(rgb[0] == octree->rgb[0] && rgb[1] == octree->rgb[1] && rgb[2] == octree->rgb[2]){ octree->numtimes+=count; return(octree); } if(!(o = (struct node *)malloc(sizeof(struct node)))){ fprintf(stderr, "insert: out of mems\n"); exit(-1); } o->leaf = 0; for(a = 0; a < 8; a++) o->octrees[a] = NULL; wo=whichoctree(octree->rgb,depth); o->octrees[wo]=insert(octree->rgb,o->octrees[wo],depth+1,octree->numtimes); numcolors--; free(octree); wo=whichoctree(rgb,depth); o->octrees[wo]=insert(rgb,o->octrees[wo],depth+1,count); makereducible(o,depth); return(o); } else{ wo=whichoctree(rgb,depth); octree->octrees[wo]=insert(rgb,octree->octrees[wo],depth+1,count); return(octree); } } /* search the octree for the nearest color to rgb[] */ int find(rgb, octree, depth) RGBvalue rgb[3]; struct node *octree; int depth; { if(octree->leaf) return(octree->index); else { register wo; wo=whichoctree(rgb,depth); if(octree->octrees[wo] == NULL){ if(octree->octrees[0]) return(find(rgb, octree->octrees[0], depth+1)); if(octree->octrees[1]) return(find(rgb, octree->octrees[1], depth+1)); if(octree->octrees[2]) return(find(rgb, octree->octrees[2], depth+1)); if(octree->octrees[3]) return(find(rgb, octree->octrees[3], depth+1)); if(octree->octrees[4]) return(find(rgb, octree->octrees[4], depth+1)); if(octree->octrees[5]) return(find(rgb, octree->octrees[5], depth+1)); if(octree->octrees[6]) return(find(rgb, octree->octrees[6], depth+1)); if(octree->octrees[7]) return(find(rgb, octree->octrees[7], depth+1)); fprintf(stderr, "ERROR: find cannot find anything near %d %d %d\n",rgb[0], rgb[1], rgb[2]); exit(-1); } return(find(rgb, octree->octrees[wo], depth+1)); } } setcolortable(octree) struct node *octree; { register a; if(octree->leaf){ #ifdef IRIS mapcolor(numcolormap,(short)octree->rgb[0],(short)octree->rgb[1],(short)octree->rgb[2]); #endif #ifdef SUN3 pr_putcolormap(screen,numcolormap,1, &octree->rgb[0], &octree->rgb[1], &octree->rgb[2]); #endif lutr[numcolormap]=(RGBvalue)octree->rgb[0]; lutg[numcolormap]=(RGBvalue)octree->rgb[1]; lutb[numcolormap]=(RGBvalue)octree->rgb[2]; octree->index = numcolormap; numcolormap++; } else for(a = 0; a < 8; a++) if(octree->octrees[a]) setcolortable(octree->octrees[a]); } clearscreen() { #ifdef SUN3 pr_rop(screen,0,0,screen->pr_size.x,screen->pr_size.y,PIX_SRC,NULL,0,0); #endif #ifdef IRIS ginit(); clear(); onemap(); gconfig(); qdevice(QKEY); qreset(); #endif } main(argc, argv) int argc; char **argv; { FILE *fp,*sbits; register x, y; register a, b, c; int xsize, ysize,crap,nread,count; RGBvalue col[3]; RGBvalue colour,tmp_name[80]; Colorindex *row; RGBvalue *rrow; #ifdef SUN4 do_gfx_stuff=0; #else do_gfx_stuff=1; #endif if(argc != 2 && argc !=3){ fprintf(stderr, "usage: %s <filename> [-d]\n", argv[0]); exit(-1); } /* this is gross but I am to lazy to do it better */ if(argc==3 && argv[2][0]=='-' && argv[2][1]=='d') do_gfx_stuff=0; strcpy(tmp_name,argv[1]); if(fp=fopen(strcat(tmp_name,EXTENSION),"r")) { #ifdef SUN4 fprintf(stderr,"Can't do gfx on sun4\n"); fclose(fp); exit(-1); #endif fread(&xsize,sizeof(int),1,fp); fread(&ysize,sizeof(int),1,fp); row=(Colorindex *)malloc(xsize*sizeof(Colorindex)); rrow=(RGBvalue *)malloc(xsize*sizeof(RGBvalue)); fread(lutr,sizeof(RGBvalue),256,fp); fread(lutg,sizeof(RGBvalue),256,fp); fread(lutb,sizeof(RGBvalue),256,fp); #ifdef SUN3 screen=pr_open("/dev/fb"); #endif clearscreen(); #ifdef SUN3 pr_putcolormap(screen,0,256,lutr,lutg,lutb); #endif #ifdef IRIS for(x=0;x<256;x++) mapcolor(x,lutr[x],lutg[x],lutb[x]); #endif #ifdef RAS x=y=0; crap=1; nread=0; do { nread=fread(tmp_name,sizeof(RGBvalue),80,fp); for(crap=0;crap<nread;crap+=2) { colour=tmp_name[crap]; count=1+(int)tmp_name[crap+1]; a=x+count; if(a>xsize) a=xsize; for(b=x;b<=a;b++) { row[b]=colour; } x+=count; while(x>xsize) { #ifdef SUN3 for(a=0;a<xsize;a++) pr_put(screen,a,y,row[a]); #endif #ifdef IRIS cmov2i(0,767-y); writepixels(xsize,row); #endif x-=xsize; a=x; if(a>xsize) a=xsize; for(b=0;b<=a;b++) row[b]=colour; y++; } } } while(nread==80); #endif #ifdef CDISP for(y = 0; y < ysize; y++) { fread(rrow,sizeof(RGBvalue),xsize,fp); for(x=0;x<xsize;x++) { row[x]=(Colorindex)rrow[x]; #ifdef SUN3 pr_put(screen,x,y,row[x]); #endif } if(do_gfx_stuff) { #ifdef IRIS cmov2i(0,767-y); writepixels((short)xsize,row); #endif } } #endif fclose(fp); goto skip_stuff; } if(!(fp = fopen(argv[1], "r"))){ fprintf(stderr, "could not open file %s\n", argv[1]); exit(-1); } #ifdef CDISP if(fread(&xsize, sizeof(int), 1, fp) != 1) exit(-1); if(fread(&ysize, sizeof(int), 1, fp) != 1) exit(-1); for(y = 0; y < ysize; y++) { for(x = 0; x < xsize; x++) { if(fread(col, sizeof(RGBvalue), 3, fp) != 3){ ysize = y; break; } while(numcolors > MAXCOLORS-1) reduce(); insert(col, &root, 0,1); } printf("%d\n",ysize-y); } #endif #ifdef RAS if(fread(tmp_name,sizeof(RGBvalue),80,fp)!=80) exit(-1); if(strncmp(tmp_name,"gl RASF",8) && strncmp(tmp_name,"gl RASf",8) && strncmp(tmp_name,"gl SHRT",8)) { fprintf(stderr,"<%s> Not in ras file format\n",argv[1]); exit(-1); } xsize= *(int *)(tmp_name+8); ysize= *(int *)(tmp_name+8+sizeof(int)); if(*(int *)(tmp_name+8+sizeof(int)+sizeof(int))!=24) { fprintf(stderr,"This is for 24 bit plane source images\n"); exit(-1); } x=y=0; crap=1; nread=0; do { nread=fread(tmp_name,sizeof(RGBvalue),80,fp); for(crap=0;crap<nread;crap+=4) { col[0]=tmp_name[crap]; col[1]=tmp_name[crap+1]; col[2]=tmp_name[crap+2]; count=1+(int)tmp_name[crap+3]; while(numcolors>MAXCOLORS-1) reduce(); insert(col,&root,0,count); x+=count; while(x>xsize) { x-=xsize; y++; printf("%d\n",ysize-y); } } } while(nread==80); #endif fclose(fp); if(do_gfx_stuff) { #ifdef SUN3 screen=pr_open("/dev/fb"); #endif clearscreen(); } setcolortable(&root); if(!(fp = fopen(argv[1], "r"))){ fprintf(stderr, "could not read file %s\n", argv[1]); exit(-1); } row=(Colorindex *)malloc(xsize*sizeof(Colorindex)); rrow=(RGBvalue *)malloc(xsize*sizeof(RGBvalue)); if(sbits=fopen(strcat(argv[1],EXTENSION),"w")) { fwrite(&xsize,sizeof(int),1,sbits); fwrite(&ysize,sizeof(int),1,sbits); fwrite(lutr,sizeof(RGBvalue),256,sbits); fwrite(lutg,sizeof(RGBvalue),256,sbits); fwrite(lutb,sizeof(RGBvalue),256,sbits); } #ifdef RAS fread(tmp_name,sizeof(RGBvalue),80,fp); xsize= *(int *)(tmp_name+8); ysize= *(int *)(tmp_name+8+sizeof(int)); x=y=0; crap=1; nread=0; do { nread=fread(tmp_name,sizeof(RGBvalue),80,fp); for(crap=0;crap<nread;crap+=4) { col[0]=tmp_name[crap]; col[1]=tmp_name[crap+1]; col[2]=tmp_name[crap+2]; count=1+(int)tmp_name[crap+3]; colour=(RGBvalue)findcolor(col); if(sbits) { tmp_name[crap+2]=(RGBvalue)colour; fwrite(&tmp_name[crap+2],sizeof(RGBvalue),2,sbits); } a=x+count; if(a>xsize) a=xsize; for(b=x;b<=a;b++) { row[b]=colour; } x+=count; while(x>xsize) { #ifdef SUN3 for(a=0;a<xsize;a++) pr_put(screen,a,y,row[a]); #endif #ifdef IRIS cmov2i(0,767-y); writepixels(xsize,row); #endif x-=xsize; a=x; if(a>xsize) a=xsize; for(b=0;b<=a;b++) row[b]=colour; y++; } } } while(nread==80); #endif #ifdef CDISP if(fread(&crap, sizeof(int), 1, fp) != 1) exit(-1); if(fread(&crap, sizeof(int), 1, fp) != 1) exit(-1); for(y = 0; y < ysize; y++) { for(x = 0; x < xsize; x++){ if(fread(col, sizeof(RGBvalue), 3, fp) != 3) exit(-1); colour=(RGBvalue)findcolor(col); row[x]=colour; #ifdef SUN3 pr_put(screen,x,y,colour); #endif } if (do_gfx_stuff) { #ifdef IRIS cmov2i(0,767-y); writepixels(xsize,row); #endif } if(sbits) { for(x=0;x<xsize;x++) rrow[x]=(RGBvalue)row[x]; fwrite(rrow,sizeof(RGBvalue),xsize,sbits); } } #endif if(sbits) fclose(sbits); fclose(fp); skip_stuff: if(do_gfx_stuff) { #ifdef IRIS while(!qtest()); unqdevice(QKEY); greset(); gexit(); #endif } exit(0); } ----- end ----- cut here ----- end ----- cut here ----- end ----- cut here -- What did you pay? Nuthin! What did you get? Sumthin! Don't grumble. David Jevans "New sensations barely interest me"