#include #include #include #include #include "imagefile.h" #include "rgbv.h" #include "ycbcr.h" #define CLAMPOFF 128 static int clamp[CLAMPOFF+256+CLAMPOFF]; static int inited; void* _remaperror(char *fmt, ...) { va_list arg; char buf[256]; va_start(arg, fmt); vseprint(buf, buf+sizeof buf, fmt, arg); va_end(arg); werrstr(buf); return nil; } Rawimage* torgbv(Rawimage *i, int errdiff) { int j, k, rgb, x, y, er, eg, eb, col, t; int r, g, b, r1, g1, b1; int *ered, *egrn, *eblu, *rp, *gp, *bp; int bpc; uint *map3; uchar *closest; Rawimage *im; int dx, dy; char err[ERRMAX]; uchar *cmap, *cm, *in, *out, *inp, *outp, cmap1[3*256], map[256], *rpic, *bpic, *gpic; err[0] = '\0'; errstr(err, sizeof err); /* throw it away */ im = malloc(sizeof(Rawimage)); if(im == nil) return nil; memset(im, 0, sizeof(Rawimage)); im->chans[0] = malloc(i->chanlen); if(im->chans[0] == nil){ free(im); return nil; } im->r = i->r; im->nchans = 1; im->chandesc = CRGBV; im->chanlen = i->chanlen; dx = i->r.max.x-i->r.min.x; dy = i->r.max.y-i->r.min.y; cmap = i->cmap; if(inited == 0){ inited = 1; for(j=0; j>4); for(j=0; j>4); } in = i->chans[0]; inp = in; out = im->chans[0]; outp = out; ered = malloc((dx+1)*sizeof(int)); egrn = malloc((dx+1)*sizeof(int)); eblu = malloc((dx+1)*sizeof(int)); if(ered==nil || egrn==nil || eblu==nil){ free(im->chans[0]); free(im); free(ered); free(egrn); free(eblu); return _remaperror("remap: malloc failed: %r"); } memset(ered, 0, (dx+1)*sizeof(int)); memset(egrn, 0, (dx+1)*sizeof(int)); memset(eblu, 0, (dx+1)*sizeof(int)); switch(i->chandesc){ default: return _remaperror("remap: can't recognize channel type %d", i->chandesc); case CRGB1: if(cmap == nil) return _remaperror("remap: image has no color map"); if(i->nchans != 1) return _remaperror("remap: can't handle nchans %d", i->nchans); for(j=1; j<=8; j++) if(i->cmaplen == 3*(1< 8) return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3); if(i->cmaplen != 3*256){ /* to avoid a range check in inner loop below, make a full-size cmap */ memmove(cmap1, cmap, i->cmaplen); cmap = cmap1; } if(errdiff == 0){ k = 0; for(j=0; j<256; j++){ r = cmap[k]>>4; g = cmap[k+1]>>4; b = cmap[k+2]>>4; k += 3; map[j] = closestrgb[b+16*(g+16*r)]; } for(j=0; jchanlen; j++) out[j] = map[in[j]]; }else{ /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */ for(y=0; y= 256+CLAMPOFF) r = 0; if(g >= 256+CLAMPOFF) g = 0; if(b >= 256+CLAMPOFF) b = 0; r1 = clamp[r+CLAMPOFF]; g1 = clamp[g+CLAMPOFF]; b1 = clamp[b+CLAMPOFF]; if(r1 >= 16 || g1 >= 16 || b1 >= 16) col = 0; else col = closestrgb[b1+16*(g1+16*r1)]; *outp++ = col; rgb = rgbmap[col]; r -= (rgb>>16) & 0xFF; t = (3*r)>>4; *rp++ = t+er; *rp += t; er = r-3*t; g -= (rgb>>8) & 0xFF; t = (3*g)>>4; *gp++ = t+eg; *gp += t; eg = g-3*t; b -= rgb & 0xFF; t = (3*b)>>4; *bp++ = t+eb; *bp += t; eb = b-3*t; } } } break; case CYCbCr: bpc = 1; rpic = i->chans[0]; gpic = i->chans[1]; bpic = i->chans[2]; closest = closestycbcr; map3 = ycbcrmap; if(i->nchans != 3) return _remaperror("remap: RGB image has %d channels", i->nchans); goto Threecolor; case CRGB: bpc = 1; rpic = i->chans[0]; gpic = i->chans[1]; bpic = i->chans[2]; if(i->nchans != 3) return _remaperror("remap: RGB image has %d channels", i->nchans); goto rgbgen; case CRGB24: bpc = 3; bpic = i->chans[0]; gpic = i->chans[0] + 1; rpic = i->chans[0] + 2; goto rgbgen; case CRGBA32: bpc = 4; /* i->chans[0]+0 is alpha */ bpic = i->chans[0] + 1; gpic = i->chans[0] + 2; rpic = i->chans[0] + 3; rgbgen: closest = closestrgb; map3 = rgbmap; Threecolor: if(errdiff == 0){ outp = out; for(j=0; jchanlen; j+=bpc){ r = rpic[j]>>4; g = gpic[j]>>4; b = bpic[j]>>4; *outp++ = closest[b+16*(g+16*r)]; } }else{ /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */ for(y=0; y 255) r = 255; if(g < 0) g = 0; else if(g > 255) g = 255; if(b < 0) b = 0; else if(b > 255) b = 255; r1 = r>>4; g1 = g>>4; b1 = b>>4; col = closest[b1+16*(g1+16*r1)]; *outp++ = col; rgb = map3[col]; r -= (rgb>>16) & 0xFF; t = (3*r)>>4; *rp++ = t+er; *rp += t; er = r-3*t; g -= (rgb>>8) & 0xFF; t = (3*g)>>4; *gp++ = t+eg; *gp += t; eg = g-3*t; b -= rgb & 0xFF; t = (3*b)>>4; *bp++ = t+eb; *bp += t; eb = b-3*t; } } } break; case CYA16: bpc = 2; /* i->chans[0] + 0 is alpha */ rpic = i->chans[0] + 1; goto greygen; case CY: bpc = 1; rpic = i->chans[0]; if(i->nchans != 1) return _remaperror("remap: Y image has %d chans", i->nchans); greygen: if(errdiff == 0){ for(j=0; jchanlen; j+=bpc){ r = rpic[j]>>4; *outp++ = closestrgb[r+16*(r+16*r)]; } }else{ /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */ for(y=0; y>16) & 0xFF; t = (3*r)>>4; *rp++ = t+er; *rp += t; er = r-3*t; } } } break; } free(ered); free(egrn); free(eblu); return im; }