--- ray/src/common/color.c 1990/10/19 11:13:02 1.13 +++ ray/src/common/color.c 1991/08/23 12:33:49 1.14 @@ -1,4 +1,4 @@ -/* Copyright (c) 1986 Regents of the University of California */ +/* Copyright (c) 1991 Regents of the University of California */ #ifndef lint static char SCCSid[] = "$SunId$ LBL"; @@ -14,59 +14,121 @@ static char SCCSid[] = "$SunId$ LBL"; #include "color.h" +#define MINELEN 8 /* minimum scanline length for encoding */ +#define MINRUN 4 /* minimum run length */ + +char * +tempbuffer(len) /* get a temporary buffer */ +unsigned len; +{ + extern char *malloc(), *realloc(); + static char *tempbuf = NULL; + static int tempbuflen = 0; + + if (len > tempbuflen) { + if (tempbuflen > 0) + tempbuf = realloc(tempbuf, len); + else + tempbuf = malloc(len); + tempbuflen = tempbuf==NULL ? 0 : len; + } + return(tempbuf); +} + + fwritecolrs(scanline, len, fp) /* write out a colr scanline */ register COLR *scanline; int len; register FILE *fp; { - COLR lastcolr; - int rept; + register int i, j, beg, cnt; + int c2; - lastcolr[RED] = lastcolr[GRN] = lastcolr[BLU] = 1; - lastcolr[EXP] = 0; - rept = 0; - - while (len > 0) { - if (scanline[0][EXP] == lastcolr[EXP] && - scanline[0][RED] == lastcolr[RED] && - scanline[0][GRN] == lastcolr[GRN] && - scanline[0][BLU] == lastcolr[BLU]) - rept++; - else { - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - putc(scanline[0][RED], fp); /* new color */ - putc(scanline[0][GRN], fp); - putc(scanline[0][BLU], fp); - putc(scanline[0][EXP], fp); - copycolr(lastcolr, scanline[0]); - rept = 0; + if (len < MINELEN) /* too small to encode */ + return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len); + if (len > 32767) /* too big! */ + return(-1); + putc(2, fp); /* put magic header */ + putc(2, fp); + putc(len>>8, fp); + putc(len&255, fp); + /* put components seperately */ + for (i = 0; i < 4; i++) { + for (j = 0; j < len; j += cnt) { /* find next run */ + for (beg = j; beg < len; beg += cnt) { + for (cnt = 1; cnt < 127 && beg+cnt < len && + scanline[beg+cnt][i] == scanline[beg][i]; cnt++) + ; + if (cnt >= MINRUN) + break; /* long enough */ } - scanline++; - len--; + while (j < beg) { /* write out non-run(s) */ + if ((c2 = beg-j) > 128) c2 = 128; + putc(c2, fp); + while (c2--) + putc(scanline[j++][i], fp); + } + if (cnt >= MINRUN) { /* write out run */ + putc(128+cnt, fp); + putc(scanline[beg][i], fp); + } else + cnt = 0; + } } - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } return(ferror(fp) ? -1 : 0); } -freadcolrs(scanline, len, fp) /* read in a colr scanline */ +freadcolrs(scanline, len, fp) /* read in an encoded colr scanline */ register COLR *scanline; int len; register FILE *fp; { + register int i, j; + int code; + /* determine scanline type */ + if (len < MINELEN) + return(oldreadcolrs(scanline, len, fp)); + if ((i = getc(fp)) == EOF) + return(-1); + if (i != 2) { + ungetc(i, fp); + return(oldreadcolrs(scanline, len, fp)); + } + scanline[0][GRN] = getc(fp); + scanline[0][BLU] = getc(fp); + if ((i = getc(fp)) == EOF) + return(-1); + if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) { + scanline[0][RED] = 2; + scanline[0][EXP] = i; + return(oldreadcolrs(scanline+1, len-1, fp)); + } + if ((scanline[0][BLU]<<8 | i) != len) + return(-1); /* length mismatch! */ + /* read each component */ + for (i = 0; i < 4; i++) + for (j = 0; j < len; ) { + if ((code = getc(fp)) == EOF) + return(-1); + if (code > 128) { /* run */ + scanline[j++][i] = getc(fp); + for (code &= 127; --code; j++) + scanline[j][i] = scanline[j-1][i]; + } else /* non-run */ + while (code--) + scanline[j++][i] = getc(fp); + } + return(feof(fp) ? -1 : 0); +} + + +oldreadcolrs(scanline, len, fp) /* read in an old colr scanline */ +register COLR *scanline; +int len; +register FILE *fp; +{ int rshift; register int i; @@ -101,86 +163,50 @@ register FILE *fp; fwritescan(scanline, len, fp) /* write out a scanline */ register COLOR *scanline; int len; -register FILE *fp; +FILE *fp; { - COLR lastcolr, thiscolr; - int rept; - - lastcolr[RED] = lastcolr[GRN] = lastcolr[BLU] = 1; - lastcolr[EXP] = 0; - rept = 0; - - while (len > 0) { - setcolr(thiscolr, scanline[0][RED], + COLR *clrscan; + int n; + register COLR *sp; + /* get scanline buffer */ + if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) + return(-1); + clrscan = sp; + /* convert scanline */ + n = len; + while (n-- > 0) { + setcolr(sp[0], scanline[0][RED], scanline[0][GRN], scanline[0][BLU]); - if (thiscolr[EXP] == lastcolr[EXP] && - thiscolr[RED] == lastcolr[RED] && - thiscolr[GRN] == lastcolr[GRN] && - thiscolr[BLU] == lastcolr[BLU]) - rept++; - else { - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - putc(thiscolr[RED], fp); /* new color */ - putc(thiscolr[GRN], fp); - putc(thiscolr[BLU], fp); - putc(thiscolr[EXP], fp); - copycolr(lastcolr, thiscolr); - rept = 0; - } scanline++; - len--; + sp++; } - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - return(ferror(fp) ? -1 : 0); + return(fwritecolrs(clrscan, len, fp)); } freadscan(scanline, len, fp) /* read in a scanline */ register COLOR *scanline; int len; -register FILE *fp; +FILE *fp; { - COLR thiscolr; - int rshift; - register int i; - - rshift = 0; - - while (len > 0) { - thiscolr[RED] = getc(fp); - thiscolr[GRN] = getc(fp); - thiscolr[BLU] = getc(fp); - thiscolr[EXP] = getc(fp); - if (feof(fp) || ferror(fp)) - return(-1); - if (thiscolr[RED] == 1 && - thiscolr[GRN] == 1 && - thiscolr[BLU] == 1) { - for (i = thiscolr[EXP] << rshift; i > 0; i--) { - copycolor(scanline[0], scanline[-1]); - scanline++; - len--; - } - rshift += 8; - } else { - colr_color(scanline[0], thiscolr); - scanline++; - len--; - rshift = 0; - } + register COLR *clrscan; + + if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) + return(-1); + if (freadcolrs(clrscan, len, fp) < 0) + return(-1); + /* convert scanline */ + colr_color(scanline[0], clrscan[0]); + while (--len > 0) { + scanline++; clrscan++; + if (clrscan[0][RED] == clrscan[-1][RED] && + clrscan[0][GRN] == clrscan[-1][GRN] && + clrscan[0][BLU] == clrscan[-1][BLU] && + clrscan[0][EXP] == clrscan[-1][EXP]) + copycolor(scanline[0], scanline[-1]); + else + colr_color(scanline[0], clrscan[0]); } return(0); }