Example #1
0
/*Adds triangle-shaped dither to an RGB pixel, but aligned with the Y'CbCr axes
   and scaled with the quantizer in that space.
  The dither has to be added in Y'CbCr space because that's where we're
   quantizing, but projecting it back allows us to measure error in the RGB
   space, which is especially useful for handling things like subsampling.*/
static void get_dithered_pixel(int32_t *_r,int32_t *_g,int32_t *_b,
 const png_byte *_rgb,int64_t _yd,int64_t _cbd,int64_t _crd){
  int32_t r;
  int32_t g;
  int32_t b;
  r=_rgb[0]*256+_rgb[1];
  g=_rgb[2]*256+_rgb[3];
  b=_rgb[4]*256+_rgb[5];
  r+=(int32_t)OD_DIV_ROUND(2*_yd+3*_crd,8176000);
  g+=(int32_t)OD_DIV_ROUND(2384*_yd+361*_cbd+1063*_crd,9745792000LL);
  b+=(int32_t)OD_DIV_ROUND(2*_yd+3*_cbd,8176000);
  *_r=r;
  *_g=g;
  *_b=b;
}
Example #2
0
static int calc_y(int32_t _r,int32_t _g,int32_t _b,int _cb,int _cr){
  int64_t chroma_r;
  int64_t chroma_g;
  int64_t chroma_b;
  int64_t r_res;
  int64_t g_res;
  int64_t b_res;
  int64_t yn;
  int64_t err0;
  int64_t err1;
  int32_t r;
  int32_t g;
  int32_t b;
  int     y0;
  _cb-=128;
  _cr-=128;
  chroma_r=4490222169144LL*_cr;
  chroma_g=-534117096223LL*_cb-1334761232047LL*_cr;
  chroma_b=5290866304968LL*_cb;
  r_res=_r*9745792000LL-chroma_r+4096>>13;
  g_res=_g*9745792000LL-chroma_g+4096>>13;
  b_res=_b*9745792000LL-chroma_b+4096>>13;
  /*Take the floor here instead of rounding; we'll consider both possible
     values.*/
  yn=1063*r_res+3576*g_res+361*b_res;
  y0=(int)((yn-(1780026171874LL&OD_SIGNMASK(yn)))/1780026171875LL);
  /*Clamp before adding the offset.
    We clamp to 238 instead of 239 to ensure we can always add one and stay in
     range.*/
  y0=OD_CLAMPI(-16,y0,238);
  /*Check the reconstruction error with y0 after rounding and clamping.*/
  r=OD_CLAMPI(0,
   (int32_t)OD_DIV_ROUND(2916394880000LL*y0+chroma_r,9745792000LL),65535);
  g=OD_CLAMPI(0,
   (int32_t)OD_DIV_ROUND(2916394880000LL*y0+chroma_g,9745792000LL),65535);
  b=OD_CLAMPI(0,
   (int32_t)OD_DIV_ROUND(2916394880000LL*y0+chroma_b,9745792000LL),65535);
  err0=(_r-r)*(_r-r)+(_g-g)*(_g-g)+(_b-b)*(_b-b);
  /*Check the reconstruction error with y0+1 after rounding and clamping.*/
  r=OD_CLAMPI(0,
   (int32_t)OD_DIV_ROUND(2916394880000LL*(y0+1)+chroma_r,9745792000LL),65535);
  g=OD_CLAMPI(0,
   (int32_t)OD_DIV_ROUND(2916394880000LL*(y0+1)+chroma_g,9745792000LL),65535);
  b=OD_CLAMPI(0,
   (int32_t)OD_DIV_ROUND(2916394880000LL*(y0+1)+chroma_b,9745792000LL),65535);
  err1=(_r-r)*(_r-r)+(_g-g)*(_g-g)+(_b-b)*(_b-b);
  if(err1<err0)y0++;
  /*In the unlikely event there's a tie, round to even.*/
  else if(err1==err0)y0+=y0&1;
  return y0+16;
}
Example #3
0
static void rgb_to_ycbcr(img_plane _ycbcr[3],png_bytep *_png){
  kiss99_ctx     kiss;
  unsigned char *ydata;
  unsigned char *cbdata;
  unsigned char *crdata;
  int            ystride;
  int            cbstride;
  int            crstride;
  int            hstep;
  int            vstep;
  int            w;
  int            h;
  int            i;
  int            j;
  w=_ycbcr[0].width;
  h=_ycbcr[0].height;
  ystride=_ycbcr[0].stride;
  ydata=_ycbcr[0].data;
  cbstride=_ycbcr[1].stride;
  cbdata=_ycbcr[1].data;
  crstride=_ycbcr[2].stride;
  crdata=_ycbcr[2].data;
  hstep=pixel_format&1;
  vstep=pixel_format&2;
  kiss99_srand(&kiss,NULL,0);
  for(j=0;j<h;j+=2){
    for(i=0;i<w;i+=2){
      int32_t yd[4];
      int32_t cbd[4];
      int32_t crd[4];
      int32_t r0;
      int32_t g0;
      int32_t b0;
      int32_t r1;
      int32_t g1;
      int32_t b1;
      int32_t r2;
      int32_t g2;
      int32_t b2;
      int32_t r3;
      int32_t g3;
      int32_t b3;
      int64_t rsum;
      int64_t gsum;
      int64_t bsum;
      int     k;
      int     cb;
      int     cr;
      /*This often generates more dither values than we use, but keeps them in
         sync for the luma plane across the different pixel formats.*/
      for(k=0;k<4;k++){
        /*The size of the dither here is chosen to be the largest divisor of
           all the corresponding coefficients in the transform that still fits
           in 31 bits.*/
        if (dither) {
          yd[k]=triangle_rand(&kiss,1223320000);
          cbd[k]=triangle_rand(&kiss,1479548743);
          crd[k]=triangle_rand(&kiss,1255654969);
        } else {
          yd[k] = 0;
          cbd[k] = 0;
          crd[k] = 0;
        }
      }
      get_dithered_pixel(&r0,&g0,&b0,_png[j]+6*i,yd[0],cbd[0],crd[0]);
      if(i+1<w){
        get_dithered_pixel(&r1,&g1,&b1,_png[j]+6*(i+1),
         yd[1],cbd[hstep],crd[hstep]);
      }
      else{
        r1=r0;
        g1=g0;
        b1=b0;
      }
      if(j+1<h){
        get_dithered_pixel(&r2,&g2,&b2,_png[j+1]+6*i,
         yd[2],cbd[vstep],crd[vstep]);
        if(i+1<w){
          get_dithered_pixel(&r3,&g3,&b3,_png[j+1]+6*(i+1),
           yd[3],cbd[vstep+hstep],crd[vstep+hstep]);
        }
        else{
          r3=r2;
          g3=g2;
          b3=b2;
        }
      }
      else{
        r2=r0;
        g2=g0;
        b2=b0;
        r3=r1;
        g3=g1;
        b3=b1;
      }
      if(pixel_format==PIXEL_FMT_420){
        rsum=r0+r1+r2+r3;
        gsum=g0+g1+g2+g3;
        bsum=b0+b1+b2+b3;
        cb=OD_CLAMP255(
         OD_DIV_ROUND(-29764*rsum-100128*gsum+129892*bsum,304016865)+128);
        cr=OD_CLAMP255(
         OD_DIV_ROUND(110236*rsum-100128*gsum-10108*bsum,258011295)+128);
        cbdata[(j>>1)*cbstride+(i>>1)]=(unsigned char)cb;
        crdata[(j>>1)*crstride+(i>>1)]=(unsigned char)cr;
        ydata[j*ystride+i]=calc_y(r0,g0,b0,cb,cr);
        if(i+1<w)ydata[j*ystride+i+1]=calc_y(r1,g1,b1,cb,cr);
        if(j+1<h){
          ydata[(j+1)*ystride+i]=calc_y(r2,g2,b2,cb,cr);
          if(i+1<w)ydata[(j+1)*ystride+i+1]=calc_y(r3,g3,b3,cb,cr);
        }
      }
      else if(pixel_format==PIXEL_FMT_422){
        rsum=r0+r1;
        gsum=g0+g1;
        bsum=b0+b1;
        cb=OD_CLAMP255(
         OD_DIV_ROUND(-59528*rsum-200256*gsum+259784*bsum,304016865)+128);
        cr=OD_CLAMP255(
         OD_DIV_ROUND(220472*rsum-200256*gsum-20216*bsum,258011295)+128);
        cbdata[j*cbstride+(i>>1)]=(unsigned char)cb;
        crdata[j*crstride+(i>>1)]=(unsigned char)cr;
        ydata[j*ystride+i]=calc_y(r0,g0,b0,cb,cr);
        if(i+1<w)ydata[j*ystride+i+1]=calc_y(r1,g1,b1,cb,cr);
        if(j+1<h){
          rsum=r2+r3;
          gsum=g2+g3;
          bsum=b2+b3;
          cb=OD_CLAMP255(
           OD_DIV_ROUND(-59528*rsum-200256*gsum+259784*bsum,304016865)+128);
          cr=OD_CLAMP255(
           OD_DIV_ROUND(220472*rsum-200256*gsum-20216*bsum,258011295)+128);
          cbdata[(j+1)*cbstride+(i>>1)]=(unsigned char)cb;
          crdata[(j+1)*crstride+(i>>1)]=(unsigned char)cr;
          ydata[(j+1)*ystride+i]=calc_y(r2,g2,b2,cb,cr);
          if(i+1<w)ydata[(j+1)*ystride+i+1]=calc_y(r3,g3,b3,cb,cr);
        }
Example #4
0
void img_to_rgb(SDL_Surface *surf, const od_img *img) {
  unsigned char *y_row;
  unsigned char *cb_row;
  unsigned char *cr_row;
  unsigned char *y;
  unsigned char *cb;
  unsigned char *cr;
  int y_stride;
  int cb_stride;
  int cr_stride;
  int width;
  int height;
  int xdec;
  int ydec;
  int i;
  int j;
  unsigned char *pixels;
  int pitch;
  pixels = (unsigned char *)surf->pixels;
  pitch = surf->pitch;
  width = img->width;
  height = img->height;
  /*Assume both C planes are decimated.*/
  xdec = img->planes[1].xdec;
  ydec = img->planes[1].ydec;
  y_stride = img->planes[0].ystride;
  cb_stride = img->planes[1].ystride;
  cr_stride = img->planes[2].ystride;
  y_row = img->planes[0].data;
  cb_row = img->planes[1].data;
  cr_row = img->planes[2].data;
  /*Chroma up-sampling is just done with a box filter.
    This is very likely what will actually be used in practice on a real
     display, and also removes one more layer to search in for the source of
     artifacts.
    As an added bonus, it's dead simple.*/
  for (j = 0; j < height; j++) {
    int dc;
    y = y_row;
    cb = cb_row;
    cr = cr_row;
    for (i = 0; i < 3 * width;) {
      int64_t yval;
      int64_t cbval;
      int64_t crval;
      unsigned rval;
      unsigned gval;
      unsigned bval;
      yval = *y - 16;
      cbval = *cb - 128;
      crval = *cr - 128;
      /*This is intentionally slow and very accurate.*/
      rval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
       2916394880000LL*yval + 4490222169144LL*crval, 9745792000LL), 65535);
      gval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
       2916394880000LL*yval - 534117096223LL*cbval - 1334761232047LL*crval,
       9745792000LL), 65535);
      bval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
       2916394880000LL*yval + 5290866304968LL*cbval, 9745792000LL), 65535);
      *(pixels + pitch*j + i++) = (unsigned char)(bval >> 8);
      *(pixels + pitch*j + i++) = (unsigned char)(gval >> 8);
      *(pixels + pitch*j + i++) = (unsigned char)(rval >> 8);
      dc = ((y - y_row) & 1) | (1 - xdec);
      y++;
      cb += dc;
      cr += dc;
    }
    y_row += y_stride;
    dc = -((j & 1) | (1 - ydec));
    cb_row += dc & cb_stride;
    cr_row += dc & cr_stride;
  }
}