Blame simple/x11/lib/img.c

Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
#include "img.h"
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
#pragma pack(push,1)
Ivan Mahonin 7d8000
typedef struct {
Ivan Mahonin 7d8000
  unsigned char  idLength;
Ivan Mahonin 7d8000
  unsigned char  colormapType;
Ivan Mahonin 7d8000
  unsigned char  imageType;
Ivan Mahonin 7d8000
  unsigned char  colormapIndex[2];
Ivan Mahonin 7d8000
  unsigned char  colormapLength[2];
Ivan Mahonin 7d8000
  unsigned char  colormapSize;
Ivan Mahonin 7d8000
  unsigned char  xOrigin[2];
Ivan Mahonin 7d8000
  unsigned char  yOrigin[2];
Ivan Mahonin 7d8000
  unsigned char  width[2];
Ivan Mahonin 7d8000
  unsigned char  height[2];
Ivan Mahonin 7d8000
  unsigned char  pixelSize;
Ivan Mahonin 7d8000
  unsigned char  attributes;
Ivan Mahonin 7d8000
} TgaHeader;
Ivan Mahonin 7d8000
#pragma pack(pop)
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgCreate(int w, int h) {
Ivan Mahonin 7d8000
  if (w <= 0 || h <= 0)
Ivan Mahonin 7d8000
    return (Image){};
Ivan Mahonin 7d8000
  Color *pixels = malloc(sizeof(Color)*w*h);
Ivan Mahonin 7d8000
  if (!pixels)
Ivan Mahonin 7d8000
    return LOGERR("imgCreate: cannot alocate memory for pixels (%dx%d)", w, h), (Image){};
Ivan Mahonin 7d8000
  return (Image){ .w = w, .h = h, .data = pixels };
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
void imgFree(Image *img) {
Ivan Mahonin 7d8000
  if (!img) return;
Ivan Mahonin 7d8000
  LOGDBG("imgFree");
Ivan Mahonin 7d8000
  free(img->data);
Ivan Mahonin 7d8000
  *img = (Image){};
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgCopy(Image img) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return (Image){};
Ivan Mahonin 7d8000
  Image res = imgCreate(img.w, img.h);
Ivan Mahonin 7d8000
  if (!imgValid(res)) return (Image){};
Ivan Mahonin 7d8000
  memcpy(res.data, img.data, sizeof(Color)*img.w*img.h);
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgSub(Image img, int x, int y, int w, int h) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return (Image){};
Ivan Mahonin 7d8000
  if (x < 0) w += x, x = 0;
Ivan Mahonin 7d8000
  if (y < 0) h += y, y = 0;
Ivan Mahonin 7d8000
  if (x + w > img.w) w = img.w - x;
Ivan Mahonin 7d8000
  if (y + h > img.h) h = img.h - y;
Ivan Mahonin 7d8000
  if (w <= 0 || h <= 0) return (Image){};
Ivan Mahonin 7d8000
  Image res = imgCreate(w, h);
Ivan Mahonin 7d8000
  if (!imgValid(res)) return (Image){};
Ivan Mahonin 7d8000
  for(int i = 0; i < h; ++i)
Ivan Mahonin 7d8000
    memcpy(res.data + i*w, img.data + (y+i)*img.w + x, sizeof(Color)*w);
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
void imgClear(Image img) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return;
Ivan Mahonin 7d8000
  memset(img.data, 0, sizeof(Color)*img.w*img.h);
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
void imgMultA(Image img) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return;
Ivan Mahonin 7d8000
  for(Color *p = img.data, *e = p + img.w*img.h; p < e; ++p) {
Ivan Mahonin 7d8000
    unsigned int a = p->a;
Ivan Mahonin 7d8000
    p->r = (p->r*a + 0xff) >> 8;
Ivan Mahonin 7d8000
    p->g = (p->g*a + 0xff) >> 8;
Ivan Mahonin 7d8000
    p->b = (p->b*a + 0xff) >> 8;
Ivan Mahonin 7d8000
  }
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
void imgDivA(Image img) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return;
Ivan Mahonin 7d8000
  for(Color *p = img.data, *e = p + img.w*img.h; p < e; ++p) {
Ivan Mahonin 7d8000
    unsigned int a = p->a;
Ivan Mahonin 7d8000
    if (!a) continue;
Ivan Mahonin 7d8000
    p->r = (((unsigned int)p->r << 8) - 1)/a;
Ivan Mahonin 7d8000
    p->g = (((unsigned int)p->g << 8) - 1)/a;
Ivan Mahonin 7d8000
    p->b = (((unsigned int)p->b << 8) - 1)/a;
Ivan Mahonin 7d8000
  }
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
int imgVisible(Image img) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return 0;
Ivan Mahonin 7d8000
  for(Color *p = img.data, *e = p + img.w*img.h; p < e; ++p)
Ivan Mahonin 7d8000
    if (p->a) return 1;
Ivan Mahonin 7d8000
  return 0;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
int imgHasPicture(Image img) {
Ivan Mahonin 7d8000
  if (!imgValid(img)) return 0;
Ivan Mahonin 7d8000
  Color c = {};
Ivan Mahonin 7d8000
  for(Color *p = img.data, *e = p + img.w*img.h; p < e; ++p)
Ivan Mahonin 7d8000
    if (p->a) { c = *p; break; }
Ivan Mahonin 7d8000
  if (!c.a) return 0;
Ivan Mahonin 7d8000
  for(Color *p = img.data, *e = p + img.w*img.h; p < e; ++p)
Ivan Mahonin 7d8000
    for(int i = 0; i < 4; ++i)
Ivan Mahonin 7d8000
      if (p->c[i] != c.c[i]) return 1;
Ivan Mahonin 7d8000
  return 0;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
static void rowResample(
Ivan Mahonin 7d8000
  Color *dst, unsigned int dcnt, unsigned int dstep,
Ivan Mahonin 7d8000
  Color *src, unsigned int scnt, unsigned int sstep
Ivan Mahonin 7d8000
) {
Ivan Mahonin 7d8000
  if (dcnt < scnt) {
Ivan Mahonin 7d8000
    // downscale
Ivan Mahonin 7d8000
    unsigned int sistep = dcnt << 8, si = sistep, di1 = 0x100, w = 0, sum[4];
Ivan Mahonin 7d8000
    for(Color *e = src + scnt*sstep; src != e; src += sstep, si += sistep) {
Ivan Mahonin 7d8000
      unsigned int di = si/scnt;
Ivan Mahonin 7d8000
      if (di < di1) {
Ivan Mahonin 7d8000
        w += 0xff;
Ivan Mahonin 7d8000
        for(int i = 0; i < 4; ++i)
Ivan Mahonin 7d8000
          sum[i] += src->c[i];
Ivan Mahonin 7d8000
      } else {
Ivan Mahonin 7d8000
        unsigned int k1 = (di - di1)*scnt/dcnt;
Ivan Mahonin 7d8000
        unsigned int k0 = 0xff - k1;
Ivan Mahonin 7d8000
        w += k0;
Ivan Mahonin 7d8000
        for(int i = 0; i < 4; ++i) {
Ivan Mahonin 7d8000
          unsigned int c = src->c[i];
Ivan Mahonin 7d8000
          unsigned int cc = (c*k0 + 0xff) >> 8;
Ivan Mahonin 7d8000
          dst->c[i] = (sum[i] + cc)*255/w;
Ivan Mahonin 7d8000
          sum[i] = (c*k1 + 0xff) >> 8;
Ivan Mahonin 7d8000
        }
Ivan Mahonin 7d8000
        w = k1;
Ivan Mahonin 7d8000
        di1 += 0x100;
Ivan Mahonin 7d8000
        dst += dstep;
Ivan Mahonin 7d8000
      }
Ivan Mahonin 7d8000
    }
Ivan Mahonin 7d8000
  } else {
Ivan Mahonin 7d8000
    // upscale
Ivan Mahonin 7d8000
    if (!--dcnt) dcnt = 1;
Ivan Mahonin 7d8000
    if (!--scnt) sstep = 0;
Ivan Mahonin 7d8000
    unsigned int di = 0, distep = (scnt << 8) - 1;
Ivan Mahonin 7d8000
    for(Color *e = dst + dcnt*dstep + dstep; dst != e; dst += dstep, di += distep) {
Ivan Mahonin 7d8000
      unsigned int si = di/dcnt;
Ivan Mahonin 7d8000
      unsigned int k1 = si & 0xff;
Ivan Mahonin 7d8000
      unsigned int k0 = 0xff - k1;
Ivan Mahonin 7d8000
      si >>= 8;
Ivan Mahonin 7d8000
      Color *s0 = src + si*sstep;
Ivan Mahonin 7d8000
      Color *s1 = s0 + sstep;
Ivan Mahonin 7d8000
      for(int i = 0; i < 4; ++i)
Ivan Mahonin 7d8000
        dst->c[i] = (s0->c[i]*k0 + s1->c[i]*k1 + 0xff) >> 8;
Ivan Mahonin 7d8000
    }
Ivan Mahonin 7d8000
  }
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgResampleX(Image img, int w) {
Ivan Mahonin 7d8000
  if (!imgValid(img) || w <= 0)
Ivan Mahonin 7d8000
    return (Image){};
Ivan Mahonin 7d8000
  if (img.w == w)
Ivan Mahonin 7d8000
    return imgCopy(img);
Ivan Mahonin 7d8000
  Image res = imgCreate(w, img.h);
Ivan Mahonin 7d8000
  for(int i = 0; i < res.h; ++i)
Ivan Mahonin 7d8000
    rowResample(res.data + i*w, w, 1, img.data + i*img.w, img.w, 1);
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgResampleY(Image img, int h) {
Ivan Mahonin 7d8000
  if (!imgValid(img) || h <= 0)
Ivan Mahonin 7d8000
    return (Image){};
Ivan Mahonin 7d8000
  if (img.h == h)
Ivan Mahonin 7d8000
    return imgCopy(img);
Ivan Mahonin 7d8000
  Image res = imgCreate(img.w, h);
Ivan Mahonin 7d8000
  for(int i = 0; i < res.w; ++i)
Ivan Mahonin 7d8000
    rowResample(res.data + i, h, img.w, img.data + i, img.h, img.w);
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgResample(Image img, int w, int h) {
Ivan Mahonin 7d8000
  if (!imgValid(img) || w <= 0 || h <= 0)
Ivan Mahonin 7d8000
    return (Image){};
Ivan Mahonin 7d8000
  if (img.w == w && img.h == h)
Ivan Mahonin 7d8000
    return imgCopy(img);
Ivan Mahonin 7d8000
  if (img.h == h)
Ivan Mahonin 7d8000
    return imgResampleX(img, w);
Ivan Mahonin 7d8000
  if (img.w == w)
Ivan Mahonin 7d8000
    return imgResampleY(img, h);
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  //clock_t start = clock();
Ivan Mahonin 7d8000
  Image tmp = imgResampleX(img, w);
Ivan Mahonin 7d8000
  Image res = imgResampleY(tmp, h);
Ivan Mahonin 7d8000
  imgFree(&tmp);
Ivan Mahonin 7d8000
  //LOGDBG("imgResample: %f sec", (clock() - start)/(double)CLOCKS_PER_SEC);
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
XImage* imgToX(Image *img) {
Ivan Mahonin 7d8000
  LOGDBG("imgToX: create XImage");
Ivan Mahonin 7d8000
  if (!img)
Ivan Mahonin 7d8000
    return LOGERR("imgToX: bad args"), NULL;
Ivan Mahonin 7d8000
  XImage *res = XCreateImage(dpy, visual, 24, ZPixmap, 0, (char*)img->data, img->w, img->h, 32, img->w*sizeof(Color));
Ivan Mahonin 7d8000
  if (!res)
Ivan Mahonin 7d8000
    return LOGERR("imgToX: cannot create XImage (%dx%d)", img->w, img->h), imgFree(img), NULL;
Ivan Mahonin 7d8000
  *img = (Image){};
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
Image imgLoadTga(const char *filename) {
Ivan Mahonin 7d8000
  LOGDBG("imgLoadTga: open: %s", filename);
Ivan Mahonin 7d8000
  FILE *f = fopen(filename, "rb");
Ivan Mahonin 7d8000
  if (!f)
Ivan Mahonin 7d8000
    return LOGERR("imgLoadTga: cannot open file for read: %s", filename), (Image){};
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  LOGDBG("imgLoadTga: read header");
Ivan Mahonin 7d8000
  TgaHeader header = {};
Ivan Mahonin 7d8000
  fread(&header, sizeof(header), 1, f);
Ivan Mahonin 7d8000
  if ( header.imageType != 2
Ivan Mahonin 7d8000
    || (!header.width[0] && !header.width[1])
Ivan Mahonin 7d8000
    || (!header.height[0] && !header.height[1])
Ivan Mahonin 7d8000
    || header.colormapType
Ivan Mahonin 7d8000
    || (header.pixelSize != 24 && header.pixelSize != 32) )
Ivan Mahonin 7d8000
    return LOGERR("imgLoadTga: unsupported format, only uncompressed 24 or 32 bits TGA are supported: %s", filename), fclose(f), (Image){};
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  int w = header.width[1]*256 + header.width[0];
Ivan Mahonin 7d8000
  int h = header.height[1]*256 + header.height[0];
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  LOGDBG("imgLoadTga: create image (%d x %d)", w, h);
Ivan Mahonin 7d8000
  Image res = imgCreate(w, h);
Ivan Mahonin 7d8000
  if (!imgValid(res))
Ivan Mahonin 7d8000
    return LOGERR("imgLoadTga: cannot create image (%d x %d): %s", w, h, filename), fclose(f), (Image){};
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  LOGDBG("imgLoadTga: read data");
Ivan Mahonin 7d8000
  fseek(f, header.idLength, SEEK_CUR);
Ivan Mahonin 7d8000
  Color *row = res.data + w*h;
Ivan Mahonin 7d8000
  for(unsigned short r = h; r; --r, row -= w) {
Ivan Mahonin 7d8000
    for(Color *c = row - w; c < row; ++c) {
Ivan Mahonin 7d8000
      c->r = fgetc(f);
Ivan Mahonin 7d8000
      c->g = fgetc(f);
Ivan Mahonin 7d8000
      c->b = fgetc(f);
Ivan Mahonin 7d8000
      c->a = header.pixelSize == 32 ? fgetc(f) : 255;
Ivan Mahonin 7d8000
    }
Ivan Mahonin 7d8000
  }
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000
  LOGDBG("imgLoadTga: done");
Ivan Mahonin 7d8000
  fclose(f);
Ivan Mahonin 7d8000
  return res;
Ivan Mahonin 7d8000
}
Ivan Mahonin 7d8000
Ivan Mahonin 7d8000