URI:
       ttorgbv.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       ttorgbv.c (6443B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <draw.h>
            5 #include "imagefile.h"
            6 
            7 #include "rgbv.h"
            8 #include "ycbcr.h"
            9 
           10 #define        CLAMPOFF 128
           11 
           12 static        int        clamp[CLAMPOFF+256+CLAMPOFF];
           13 static        int        inited;
           14 
           15 void*
           16 _remaperror(char *fmt, ...)
           17 {
           18         va_list arg;
           19         char buf[256];
           20 
           21         va_start(arg, fmt);
           22         vseprint(buf, buf+sizeof buf, fmt, arg);
           23         va_end(arg);
           24 
           25         werrstr(buf);
           26         return nil;
           27 }
           28 
           29 Rawimage*
           30 torgbv(Rawimage *i, int errdiff)
           31 {
           32         int j, k, rgb, x, y, er, eg, eb, col, t;
           33         int r, g, b, r1, g1, b1;
           34         int *ered, *egrn, *eblu, *rp, *gp, *bp;
           35         uint *map3;
           36         uchar *closest;
           37         Rawimage *im;
           38         int dx, dy;
           39         char err[ERRMAX];
           40         uchar *cmap, *cm, *in, *out, *inp, *outp, cmap1[3*256], map[256], *rpic, *bpic, *gpic;
           41 
           42         err[0] = '\0';
           43         errstr(err, sizeof err);        /* throw it away */
           44         im = malloc(sizeof(Rawimage));
           45         if(im == nil)
           46                 return nil;
           47         memset(im, 0, sizeof(Rawimage));
           48         im->chans[0] = malloc(i->chanlen);
           49         if(im->chans[0] == nil){
           50                 free(im);
           51                 return nil;
           52         }
           53         im->r = i->r;
           54         im->nchans = 1;
           55         im->chandesc = CRGBV;
           56         im->chanlen = i->chanlen;
           57 
           58         dx = i->r.max.x-i->r.min.x;
           59         dy = i->r.max.y-i->r.min.y;
           60         cmap = i->cmap;
           61 
           62         if(inited == 0){
           63                 inited = 1;
           64                 for(j=0; j<CLAMPOFF; j++)
           65                         clamp[j] = 0;
           66                 for(j=0; j<256; j++)
           67                         clamp[CLAMPOFF+j] = (j>>4);
           68                 for(j=0; j<CLAMPOFF; j++)
           69                         clamp[CLAMPOFF+256+j] = (255>>4);
           70         }
           71 
           72         in = i->chans[0];
           73         inp = in;
           74         out = im->chans[0];
           75         outp = out;
           76 
           77         ered = malloc((dx+1)*sizeof(int));
           78         egrn = malloc((dx+1)*sizeof(int));
           79         eblu = malloc((dx+1)*sizeof(int));
           80         if(ered==nil || egrn==nil || eblu==nil){
           81                 free(im->chans[0]);
           82                 free(im);
           83                 free(ered);
           84                 free(egrn);
           85                 free(eblu);
           86                 return _remaperror("remap: malloc failed: %r");
           87         }
           88         memset(ered, 0, (dx+1)*sizeof(int));
           89         memset(egrn, 0, (dx+1)*sizeof(int));
           90         memset(eblu, 0, (dx+1)*sizeof(int));
           91 
           92         switch(i->chandesc){
           93         default:
           94                 return _remaperror("remap: can't recognize channel type %d", i->chandesc);
           95         case CRGB1:
           96                 if(cmap == nil)
           97                         return _remaperror("remap: image has no color map");
           98                 if(i->nchans != 1)
           99                         return _remaperror("remap: can't handle nchans %d", i->nchans);
          100                 for(j=1; j<=8; j++)
          101                         if(i->cmaplen == 3*(1<<j))
          102                                 break;
          103                 if(j > 8)
          104                         return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3);
          105                 if(i->cmaplen != 3*256){
          106                         /* to avoid a range check in inner loop below, make a full-size cmap */
          107                         memmove(cmap1, cmap, i->cmaplen);
          108                         cmap = cmap1;
          109                 }
          110                 if(errdiff == 0){
          111                         k = 0;
          112                         for(j=0; j<256; j++){
          113                                 r = cmap[k]>>4;
          114                                 g = cmap[k+1]>>4;
          115                                 b = cmap[k+2]>>4;
          116                                 k += 3;
          117                                 map[j] = closestrgb[b+16*(g+16*r)];
          118                         }
          119                         for(j=0; j<i->chanlen; j++)
          120                                 out[j] = map[in[j]];
          121                 }else{
          122                         /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
          123                         for(y=0; y<dy; y++){
          124                                 er = 0;
          125                                 eg = 0;
          126                                 eb = 0;
          127                                 rp = ered;
          128                                 gp = egrn;
          129                                 bp = eblu;
          130                                 for(x=0; x<dx; x++){
          131                                         cm = &cmap[3 * *inp++];
          132                                         r = cm[0] +*rp;
          133                                         g = cm[1] +*gp;
          134                                         b = cm[2] +*bp;
          135 
          136                                         /* sanity checks are new */
          137                                         if(r >= 256+CLAMPOFF)
          138                                                 r = 0;
          139                                         if(g >= 256+CLAMPOFF)
          140                                                 g = 0;
          141                                         if(b >= 256+CLAMPOFF)
          142                                                 b = 0;
          143                                         r1 = clamp[r+CLAMPOFF];
          144                                         g1 = clamp[g+CLAMPOFF];
          145                                         b1 = clamp[b+CLAMPOFF];
          146                                         if(r1 >= 16 || g1 >= 16 || b1 >= 16)
          147                                                 col = 0;
          148                                         else
          149                                                 col = closestrgb[b1+16*(g1+16*r1)];
          150                                         *outp++ = col;
          151 
          152                                         rgb = rgbmap[col];
          153                                         r -= (rgb>>16) & 0xFF;
          154                                         t = (3*r)>>4;
          155                                         *rp++ = t+er;
          156                                         *rp += t;
          157                                         er = r-3*t;
          158 
          159                                         g -= (rgb>>8) & 0xFF;
          160                                         t = (3*g)>>4;
          161                                         *gp++ = t+eg;
          162                                         *gp += t;
          163                                         eg = g-3*t;
          164 
          165                                         b -= rgb & 0xFF;
          166                                         t = (3*b)>>4;
          167                                         *bp++ = t+eb;
          168                                         *bp += t;
          169                                         eb = b-3*t;
          170                                 }
          171                         }
          172                 }
          173                 break;
          174 
          175         case CYCbCr:
          176                 closest = closestycbcr;
          177                 map3 = ycbcrmap;
          178                 goto Threecolor;
          179 
          180         case CRGB:
          181                 closest = closestrgb;
          182                 map3 = rgbmap;
          183 
          184         Threecolor:
          185                 if(i->nchans != 3)
          186                         return _remaperror("remap: RGB image has %d channels", i->nchans);
          187                 rpic = i->chans[0];
          188                 gpic = i->chans[1];
          189                 bpic = i->chans[2];
          190                 if(errdiff == 0){
          191                         for(j=0; j<i->chanlen; j++){
          192                                 r = rpic[j]>>4;
          193                                 g = gpic[j]>>4;
          194                                 b = bpic[j]>>4;
          195                                 out[j] = closest[b+16*(g+16*r)];
          196                         }
          197                 }else{
          198                         /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
          199                         for(y=0; y<dy; y++){
          200                                 er = 0;
          201                                 eg = 0;
          202                                 eb = 0;
          203                                 rp = ered;
          204                                 gp = egrn;
          205                                 bp = eblu;
          206                                 for(x=0; x<dx; x++){
          207                                         r = *rpic++ + *rp;
          208                                         g = *gpic++ + *gp;
          209                                         b = *bpic++ + *bp;
          210                                         /*
          211                                          * Errors can be uncorrectable if converting from YCbCr,
          212                                          * since we can't guarantee that an extremal value of one of
          213                                          * the components selects a color with an extremal value.
          214                                          * If we don't, the errors accumulate without bound.  This
          215                                          * doesn't happen in RGB because the closest table can guarantee
          216                                          * a color on the edge of the gamut, producing a zero error in
          217                                          * that component.  For the rotation YCbCr space, there may be
          218                                          * no color that can guarantee zero error at the edge.
          219                                          * Therefore we must clamp explicitly rather than by assuming
          220                                          * an upper error bound of CLAMPOFF.  The performance difference
          221                                          * is miniscule anyway.
          222                                          */
          223                                         if(r < 0)
          224                                                 r = 0;
          225                                         else if(r > 255)
          226                                                 r = 255;
          227                                         if(g < 0)
          228                                                 g = 0;
          229                                         else if(g > 255)
          230                                                 g = 255;
          231                                         if(b < 0)
          232                                                 b = 0;
          233                                         else if(b > 255)
          234                                                 b = 255;
          235                                         r1 = r>>4;
          236                                         g1 = g>>4;
          237                                         b1 = b>>4;
          238                                         col = closest[b1+16*(g1+16*r1)];
          239                                         *outp++ = col;
          240 
          241                                         rgb = map3[col];
          242                                         r -= (rgb>>16) & 0xFF;
          243                                         t = (3*r)>>4;
          244                                         *rp++ = t+er;
          245                                         *rp += t;
          246                                         er = r-3*t;
          247 
          248                                         g -= (rgb>>8) & 0xFF;
          249                                         t = (3*g)>>4;
          250                                         *gp++ = t+eg;
          251                                         *gp += t;
          252                                         eg = g-3*t;
          253 
          254                                         b -= rgb & 0xFF;
          255                                         t = (3*b)>>4;
          256                                         *bp++ = t+eb;
          257                                         *bp += t;
          258                                         eb = b-3*t;
          259                                 }
          260                         }
          261                 }
          262                 break;
          263 
          264         case CY:
          265                 if(i->nchans != 1)
          266                         return _remaperror("remap: Y image has %d chans", i->nchans);
          267                 rpic = i->chans[0];
          268                 if(errdiff == 0){
          269                         for(j=0; j<i->chanlen; j++){
          270                                 r = rpic[j]>>4;
          271                                 *outp++ = closestrgb[r+16*(r+16*r)];
          272                         }
          273                 }else{
          274                         /* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */
          275                         for(y=0; y<dy; y++){
          276                                 er = 0;
          277                                 rp = ered;
          278                                 for(x=0; x<dx; x++){
          279                                         r = *inp++ + *rp;
          280                                         r1 = clamp[r+CLAMPOFF];
          281                                         col = closestrgb[r1+16*(r1+16*r1)];
          282                                         *outp++ = col;
          283 
          284                                         rgb = rgbmap[col];
          285                                         r -= (rgb>>16) & 0xFF;
          286                                         t = (3*r)>>4;
          287                                         *rp++ = t+er;
          288                                         *rp += t;
          289                                         er = r-3*t;
          290                                 }
          291                         }
          292                 }
          293                 break;
          294         }
          295         free(ered);
          296         free(egrn);
          297         free(eblu);
          298         return im;
          299 }