ref: c3ba64f6935322f09b6de5c2285544fd471c605d
dir: /sys/src/cmd/jpg/totruecolor.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <draw.h> #include "imagefile.h" enum { c1 = 2871, /* 1.402 * 2048 */ c2 = 705, /* 0.34414 * 2048 */ c3 = 1463, /* 0.71414 * 2048 */ c4 = 3629, /* 1.772 * 2048 */ }; Rawimage* totruecolor(Rawimage *i, int chandesc) { int j, k; Rawimage *im; char err[ERRMAX]; uchar *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[4*256]; int r, g, b, Y, Cr, Cb, psize; if(chandesc!=CY && chandesc!=CRGB24) return _remaperror("remap: can't convert to chandesc %d", chandesc); err[0] = '\0'; errstr(err, sizeof err); /* throw it away */ im = malloc(sizeof(Rawimage)); if(im == nil) return nil; memset(im, 0, sizeof(Rawimage)); if(chandesc == CY) im->chanlen = i->chanlen; else im->chanlen = 3*i->chanlen; im->chandesc = chandesc; im->chans[0] = malloc(im->chanlen); if(im->chans[0] == nil){ free(im); return nil; } im->r = i->r; im->nchans = 1; cmap = i->cmap; outp = im->chans[0]; switch(i->chandesc){ default: return _remaperror("remap: can't recognize channel type %d", i->chandesc); case CY: if(i->nchans != 1) return _remaperror("remap: Y image has %d chans", i->nchans); if(chandesc == CY){ memmove(im->chans[0], i->chans[0], i->chanlen); break; } /* convert to three color */ inp = i->chans[0]; for(j=0; j<i->chanlen; j++){ k = *inp++; *outp++ = k; *outp++ = k; *outp++ = k; } break; case CRGB1: case CRGBV: psize = (i->chandesc == CRGB1) ? 3 : 4; 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); if(i->cmaplen > psize*256) return _remaperror("remap: can't do colormap size %d*%d", psize, i->cmaplen/psize); if(i->cmaplen != psize*256){ /* to avoid a range check in loop below, make a full-size cmap */ memmove(cmap1, cmap, i->cmaplen); cmap = cmap1; } inp = i->chans[0]; if(chandesc == CY){ for(j=0; j<i->chanlen; j++){ k = psize*(*inp++); r = cmap[k+2]; g = cmap[k+1]; b = cmap[k+0]; r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */ *outp++ = r; } }else{ for(j=0; j<i->chanlen; j++){ k = psize*(*inp++); *outp++ = cmap[k+2]; *outp++ = cmap[k+1]; *outp++ = cmap[k+0]; } } break; case CRGB: if(i->nchans != 3) return _remaperror("remap: can't handle nchans %d", i->nchans); rp = i->chans[0]; gp = i->chans[1]; bp = i->chans[2]; if(chandesc == CY){ for(j=0; j<i->chanlen; j++){ r = *bp++; g = *gp++; b = *rp++; r = (2125*r + 7154*g + 721*b)/10000; /* Poynton page 84 */ *outp++ = r; } }else for(j=0; j<i->chanlen; j++){ *outp++ = *bp++; *outp++ = *gp++; *outp++ = *rp++; } break; case CYCbCr: if(i->nchans != 3) return _remaperror("remap: can't handle nchans %d", i->nchans); rp = i->chans[0]; gp = i->chans[1]; bp = i->chans[2]; for(j=0; j<i->chanlen; j++){ Y = *rp++ << 11; Cb = *gp++ - 128; Cr = *bp++ - 128; r = (Y+c1*Cr) >> 11; g = (Y-c2*Cb-c3*Cr) >> 11; b = (Y+c4*Cb) >> 11; if(r < 0) r = 0; if(r > 255) r = 255; if(g < 0) g = 0; if(g > 255) g = 255; if(b < 0) b = 0; if(b > 255) b = 255; if(chandesc == CY){ r = (2125*r + 7154*g + 721*b)/10000; *outp++ = r; }else{ *outp++ = b; *outp++ = g; *outp++ = r; } } break; } return im; }