Blame img.inc.c

ea5919
ea5919
ea5919
#define IMG_PRECISION (1e-8)
ea5919
ea5919
ea5919
typedef struct {
ea5919
  int w, h;
ea5919
  double *data;
ea5919
} Img;
ea5919
ea5919
ea5919
void setRgb(double *rgb, double r, double g, double b)
ea5919
  { rgb[0] = r; rgb[1] = g; rgb[2] = b; }
ea5919
ea5919
int colorMin(const double *rgb)
ea5919
  { return rgb[0] < rgb[1] ? (rgb[0] < rgb[2] ? 0 : 2) : (rgb[1] < rgb[2] ? 1 : 2); }
ea5919
int colorMax(const double *rgb)
ea5919
  { return rgb[0] < rgb[1] ? (rgb[1] < rgb[2] ? 2 : 1) : (rgb[0] < rgb[2] ? 2 : 0); }
ea5919
ea5919
void rgbToHsv(double *hsv, const double *rgb) {
ea5919
  int cmin = colorMin(rgb);
ea5919
  int cmax = colorMax(rgb);
ea5919
  double d = rgb[cmax] - rgb[cmin];
ea5919
ea5919
  double h = 0;
ea5919
  if (d > IMG_PRECISION) {
ea5919
    double k = 1.0/d;
ea5919
    switch(cmax){
ea5919
    case 0: h = (rgb[1] - rgb[2])*k + 0; break;
ea5919
    case 1: h = (rgb[2] - rgb[0])*k + 2; break;
ea5919
    case 2: h = (rgb[0] - rgb[1])*k + 4; break;
ea5919
    }
ea5919
    h /= 6; h -= floor(h); h *= 360;
ea5919
  }
ea5919
  double s = rgb[cmax] > IMG_PRECISION ? d/rgb[cmax] : 0;
ea5919
  double v = rgb[cmax];
ea5919
  setRgb(hsv, h, s, v);
ea5919
}
ea5919
ea5919
ea5919
void hsvToRgb(double *rgb, const double *hsv) {
ea5919
  double h = hsv[0], s = hsv[1], v = hsv[2];
ea5919
  h -= floor(h/360)*360;
ea5919
  h /= 60.0;
ea5919
  int i = (int)h;
ea5919
  double f = h - i;
ea5919
  double p = v*(1 - s);
ea5919
  double q = v*(1 - s*f);
ea5919
  double t = v*(1 - s*(1 - f));
ea5919
  switch(i) {
ea5919
  case 0: setRgb(rgb, v, t, p); return;
ea5919
  case 1: setRgb(rgb, q, v, p); return;
ea5919
  case 2: setRgb(rgb, p, v, t); return;
ea5919
  case 3: setRgb(rgb, p, q, v); return;
ea5919
  case 4: setRgb(rgb, t, p, v); return;
ea5919
  case 5: setRgb(rgb, v, p, q); return;
ea5919
  }
ea5919
  return setRgb(rgb, v, t, p);
ea5919
}
ea5919
ea5919
ea5919
double cubicInterpolation(double p0, double p1, double p2, double p3, double l) {
ea5919
  double ll = l*l;
ea5919
  double lll = ll*l;
ea5919
  return 0.5*( p0*(  -lll + 2*ll - l)
ea5919
             + p1*( 3*lll - 5*ll + 2)
ea5919
             + p2*(-3*lll + 4*ll + l)
ea5919
             + p3*(   lll -   ll    ) );
ea5919
}
ea5919
ea5919
double cubicRow(double *row, int count, double x) {
ea5919
  if (count < 0) return 0;
ea5919
  if (!(x > 0)) x = 0;
ea5919
  if (!(x < count)) x = count;
ea5919
  double xi = floor(x);
ea5919
  double l = x - xi;
ea5919
ea5919
  int i = (int)x - 1;
ea5919
  double p0 = i < 0 ? row[0] : i >= count ? row[count-1] : row[i]; ++i;
ea5919
  double p1 = i < 0 ? row[0] : i >= count ? row[count-1] : row[i]; ++i;
ea5919
  double p2 = i < 0 ? row[0] : i >= count ? row[count-1] : row[i]; ++i;
ea5919
  double p3 = i < 0 ? row[0] : i >= count ? row[count-1] : row[i]; ++i;
ea5919
ea5919
  return cubicInterpolation(p0, p1, p2, p3, l);
ea5919
}
ea5919
ea5919
ea5919
ea5919
void imgDestroy(Img *img) {
ea5919
  free(img->data);
ea5919
  img->data = NULL;
ea5919
  img->w = img->h = 0;
ea5919
}
ea5919
ea5919
ea5919
void imgSwap(Img *imgA, Img *imgB) {
ea5919
  Img imgC;
ea5919
  memcpy(&imgC, imgA, sizeof(imgC));
ea5919
  memcpy(imgA, imgB, sizeof(imgC));
ea5919
  memcpy(imgB, &imgC, sizeof(imgC));
ea5919
}
ea5919
ea5919
ea5919
int imgInit(Img *img, int w, int h) {
ea5919
  imgDestroy(img);
ea5919
  if (w < 0 || h < 0) return FALSE;
ea5919
  img->data = calloc(1, sizeof(double)*4*w*h);
ea5919
  if (!img->data) return FALSE;
ea5919
  img->w = w;
ea5919
  img->h = h;
ea5919
  return TRUE;
ea5919
}
ea5919
ea5919
ea5919
double* imgPixel(const Img *img, int x, int y) {
ea5919
  if (!img->data) return NULL;
ea5919
  if (x >= img->w) x = img->w - 1;
ea5919
  if (y >= img->h) y = img->h - 1;
ea5919
  if (x < 0) x = 0;
ea5919
  if (y < 0) y = 0;
ea5919
  return img->data + (img->w*y + x)*4;
ea5919
}
ea5919
ea5919
ea5919
double* imgNearest(const Img *img, double x, double y)
ea5919
  { return imgPixel(img, (int)round(x), (int)round(y)); }
ea5919
ea5919
ea5919
double imgCubicHCh(const Img *img, int ch, double x, int y) {
ea5919
  if (!img->data) return 0;
ea5919
  if (!(x > 0)) x = 0;
ea5919
  if (!(x < img->w)) x = img->w;
ea5919
  double xi = floor(x);
ea5919
  int i = (int)xi - 1;
ea5919
  double p[] = {
ea5919
    imgPixel(img, i+0, y)[ch],
ea5919
    imgPixel(img, i+1, y)[ch],
ea5919
    imgPixel(img, i+2, y)[ch],
ea5919
    imgPixel(img, i+3, y)[ch] };
ea5919
  return cubicInterpolation(p[0], p[1], p[2], p[3], x - xi);
ea5919
}
ea5919
ea5919
ea5919
double imgCubicVCh(const Img *img, int ch, int x, double y) {
ea5919
  if (!img->data) return 0;
ea5919
  if (!(y > 0)) x = 0;
ea5919
  if (!(y < img->h)) y = img->h;
ea5919
  double yi = floor(y);
ea5919
  int i = (int)yi - 1;
ea5919
  double p[] = {
ea5919
    imgPixel(img, i+0, y)[ch],
ea5919
    imgPixel(img, i+1, y)[ch],
ea5919
    imgPixel(img, i+2, y)[ch],
ea5919
    imgPixel(img, i+3, y)[ch] };
ea5919
  return cubicInterpolation(p[0], p[1], p[2], p[3], y - yi);
ea5919
}
ea5919
ea5919
ea5919
void imgCubicH(const Img *img, double x, int y, double *pix) {
ea5919
  if (!img->data) { pix[0] = pix[1] = pix[2] = pix[3] = 0; return; }
ea5919
  if (!(x > 0)) x = 0;
ea5919
  if (!(x < img->w)) x = img->w;
ea5919
  double xi = floor(x);
ea5919
  double l = x - xi;
ea5919
ea5919
  int i = (int)xi - 1;
ea5919
  double *p[] = {
ea5919
    imgPixel(img, i+0, y),
ea5919
    imgPixel(img, i+1, y),
ea5919
    imgPixel(img, i+2, y),
ea5919
    imgPixel(img, i+3, y) };
ea5919
ea5919
  pix[0] = cubicInterpolation(p[0][0], p[1][0], p[2][0], p[3][0], l);
ea5919
  pix[1] = cubicInterpolation(p[0][1], p[1][1], p[2][1], p[3][1], l);
ea5919
  pix[2] = cubicInterpolation(p[0][2], p[1][2], p[2][2], p[3][2], l);
ea5919
  pix[3] = cubicInterpolation(p[0][3], p[1][3], p[2][3], p[3][3], l);
ea5919
}
ea5919
ea5919
ea5919
void imgCubicV(const Img *img, int x, double y, double *pix) {
ea5919
  if (!img->data) { pix[0] = pix[1] = pix[2] = pix[3] = 0; return; }
ea5919
  if (!(y > 0)) y = 0;
ea5919
  if (!(y < img->h)) y = img->h;
ea5919
  double yi = floor(y);
ea5919
  double l = y - yi;
ea5919
ea5919
  int i = (int)yi - 1;
ea5919
  double *p[] = {
ea5919
    imgPixel(img, x, i+0),
ea5919
    imgPixel(img, x, i+1),
ea5919
    imgPixel(img, x, i+2),
ea5919
    imgPixel(img, x, i+3) };
ea5919
ea5919
  pix[0] = cubicInterpolation(p[0][0], p[1][0], p[2][0], p[3][0], l);
ea5919
  pix[1] = cubicInterpolation(p[0][1], p[1][1], p[2][1], p[3][1], l);
ea5919
  pix[2] = cubicInterpolation(p[0][2], p[1][2], p[2][2], p[3][2], l);
ea5919
  pix[3] = cubicInterpolation(p[0][3], p[1][3], p[2][3], p[3][3], l);
ea5919
}
ea5919
ea5919
ea5919
double imgCubicCh(const Img *img, int ch, double x, double y) {
ea5919
  if (!img->data) return 0;
ea5919
  if (!(y > 0)) y = 0;
ea5919
  if (!(y < img->h)) y = img->h;
ea5919
  double yi = floor(y);
ea5919
  double l = y - yi;
ea5919
ea5919
  int i = (int)yi - 1;
ea5919
  double p[] = {
ea5919
    imgCubicHCh(img, ch, x, i+0),
ea5919
    imgCubicHCh(img, ch, x, i+1),
ea5919
    imgCubicHCh(img, ch, x, i+2),
ea5919
    imgCubicHCh(img, ch, x, i+3) };
ea5919
ea5919
  return cubicInterpolation(p[0], p[1], p[2], p[3], l);
ea5919
}
ea5919
ea5919
ea5919
void imgCubic(const Img *img, double x, double y, double *pix) {
ea5919
  if (!img->data) { pix[0] = pix[1] = pix[2] = pix[3] = 0; return; }
ea5919
  if (!(y > 0)) y = 0;
ea5919
  if (!(y < img->h)) y = img->h;
ea5919
  double yi = floor(y);
ea5919
  double l = y - yi;
ea5919
ea5919
  int i = (int)yi - 1;
ea5919
  double p[4][4];
ea5919
  imgCubicH(img, x, i+0, p[0]);
ea5919
  imgCubicH(img, x, i+1, p[1]);
ea5919
  imgCubicH(img, x, i+2, p[2]);
ea5919
  imgCubicH(img, x, i+3, p[3]);
ea5919
ea5919
  pix[0] = cubicInterpolation(p[0][0], p[1][0], p[2][0], p[3][0], l);
ea5919
  pix[1] = cubicInterpolation(p[0][1], p[1][1], p[2][1], p[3][1], l);
ea5919
  pix[2] = cubicInterpolation(p[0][2], p[1][2], p[2][2], p[3][2], l);
ea5919
  pix[3] = cubicInterpolation(p[0][3], p[1][3], p[2][3], p[3][3], l);
ea5919
}
ea5919
ea5919
ea5919
void imgFromInt(Img *img, int w, int h, const unsigned char *data) {
ea5919
  imgInit(img, w, h);
ea5919
  if (!img->data || !data) return;
ea5919
  for(double *p = img->data, *e = p + 4*img->w*img->h; p < e; ++p)
ea5919
    *p = (*data++)/255.0;
ea5919
}
ea5919
ea5919
ea5919
unsigned char* imgToInt(Img *img) {
ea5919
  if (!img->data) return NULL;
ea5919
  unsigned char *data = (unsigned char*)malloc(sizeof(unsigned char)*4*img->w*img->h), *dp = data;
ea5919
  for(double *p = img->data, *e = p + 4*img->w*img->h; p < e; ++p)
ea5919
    *dp++ = *p > 0 ? (*p < 1 ? (unsigned char)floor(*p*255.9999999) : 255) : 0;
ea5919
  return data;
ea5919
}
ea5919