aboutsummaryrefslogtreecommitdiffstats
path: root/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'filter.c')
-rw-r--r--filter.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/filter.c b/filter.c
new file mode 100644
index 0000000..283a1fa
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,495 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "readers.h"
+#include "filter.h"
+
+int debug = 0;
+
+/* ----------------------------------------------------------------------- */
+
+static void
+op_grayscale(struct ida_image *src, struct ida_rect *rect,
+ unsigned char *dst, int line, void *data)
+{
+ unsigned char *scanline;
+ int i,g;
+
+ scanline = src->data + line * src->i.width * 3;
+ memcpy(dst,scanline,src->i.width * 3);
+ if (line < rect->y1 || line >= rect->y2)
+ return;
+ dst += 3*rect->x1;
+ scanline += 3*rect->x1;
+ for (i = rect->x1; i < rect->x2; i++) {
+ g = (scanline[0]*30 + scanline[1]*59+scanline[2]*11)/100;
+ dst[0] = g;
+ dst[1] = g;
+ dst[2] = g;
+ scanline += 3;
+ dst += 3;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct op_3x3_handle {
+ struct op_3x3_parm filter;
+ int *linebuf;
+};
+
+static void*
+op_3x3_init(struct ida_image *src, struct ida_rect *rect,
+ struct ida_image_info *i, void *parm)
+{
+ struct op_3x3_parm *args = parm;
+ struct op_3x3_handle *h;
+
+ h = malloc(sizeof(*h));
+ memcpy(&h->filter,args,sizeof(*args));
+ h->linebuf = malloc(sizeof(int)*3*(src->i.width));
+
+ *i = src->i;
+ return h;
+}
+
+static int inline
+op_3x3_calc_pixel(struct op_3x3_parm *p, unsigned char *s1,
+ unsigned char *s2, unsigned char *s3)
+{
+ int val = 0;
+
+ val += p->f1[0] * s1[0];
+ val += p->f1[1] * s1[3];
+ val += p->f1[2] * s1[6];
+ val += p->f2[0] * s2[0];
+ val += p->f2[1] * s2[3];
+ val += p->f2[2] * s2[6];
+ val += p->f3[0] * s3[0];
+ val += p->f3[1] * s3[3];
+ val += p->f3[2] * s3[6];
+ if (p->mul && p->div)
+ val = val * p->mul / p->div;
+ val += p->add;
+ return val;
+}
+
+static void
+op_3x3_calc_line(struct ida_image *src, struct ida_rect *rect,
+ int *dst, unsigned int line, struct op_3x3_parm *p)
+{
+ unsigned char b1[9],b2[9],b3[9];
+ unsigned char *s1,*s2,*s3;
+ unsigned int i,left,right;
+
+ s1 = src->data + (line-1) * src->i.width * 3;
+ s2 = src->data + line * src->i.width * 3;
+ s3 = src->data + (line+1) * src->i.width * 3;
+ if (0 == line)
+ s1 = src->data + line * src->i.width * 3;
+ if (src->i.height-1 == line)
+ s3 = src->data + line * src->i.width * 3;
+
+ left = rect->x1;
+ right = rect->x2;
+ if (0 == left) {
+ /* left border special case: dup first col */
+ memcpy(b1,s1,3);
+ memcpy(b2,s2,3);
+ memcpy(b3,s3,3);
+ memcpy(b1+3,s1,6);
+ memcpy(b2+3,s2,6);
+ memcpy(b3+3,s3,6);
+ dst[0] = op_3x3_calc_pixel(p,b1,b2,b3);
+ dst[1] = op_3x3_calc_pixel(p,b1+1,b2+1,b3+1);
+ dst[2] = op_3x3_calc_pixel(p,b1+2,b2+2,b3+2);
+ left++;
+ }
+ if (src->i.width == right) {
+ /* right border */
+ memcpy(b1,s1+src->i.width*3-6,6);
+ memcpy(b2,s2+src->i.width*3-6,6);
+ memcpy(b3,s3+src->i.width*3-6,6);
+ memcpy(b1+3,s1+src->i.width*3-3,3);
+ memcpy(b2+3,s2+src->i.width*3-3,3);
+ memcpy(b3+3,s3+src->i.width*3-3,3);
+ dst[src->i.width*3-3] = op_3x3_calc_pixel(p,b1,b2,b3);
+ dst[src->i.width*3-2] = op_3x3_calc_pixel(p,b1+1,b2+1,b3+1);
+ dst[src->i.width*3-1] = op_3x3_calc_pixel(p,b1+2,b2+2,b3+2);
+ right--;
+ }
+
+ dst += 3*left;
+ s1 += 3*(left-1);
+ s2 += 3*(left-1);
+ s3 += 3*(left-1);
+ for (i = left; i < right; i++) {
+ dst[0] = op_3x3_calc_pixel(p,s1++,s2++,s3++);
+ dst[1] = op_3x3_calc_pixel(p,s1++,s2++,s3++);
+ dst[2] = op_3x3_calc_pixel(p,s1++,s2++,s3++);
+ dst += 3;
+ }
+}
+
+static void
+op_3x3_clip_line(unsigned char *dst, int *src, int left, int right)
+{
+ int i,val;
+
+ src += left*3;
+ dst += left*3;
+ for (i = left*3; i < right*3; i++) {
+ val = *(src++);
+ if (val < 0)
+ val = 0;
+ if (val > 255)
+ val = 255;
+ *(dst++) = val;
+ }
+}
+
+static void
+op_3x3_work(struct ida_image *src, struct ida_rect *rect,
+ unsigned char *dst, int line, void *data)
+{
+ struct op_3x3_handle *h = data;
+ unsigned char *scanline;
+
+ scanline = src->data + line * src->i.width * 3;
+ memcpy(dst,scanline,src->i.width * 3);
+ if (line < rect->y1 || line >= rect->y2)
+ return;
+
+ op_3x3_calc_line(src,rect,h->linebuf,line,&h->filter);
+ op_3x3_clip_line(dst,h->linebuf,rect->x1,rect->x2);
+}
+
+static void
+op_3x3_free(void *data)
+{
+ struct op_3x3_handle *h = data;
+
+ free(h->linebuf);
+ free(h);
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct op_sharpe_handle {
+ int factor;
+ int *linebuf;
+};
+
+static void*
+op_sharpe_init(struct ida_image *src, struct ida_rect *rect,
+ struct ida_image_info *i, void *parm)
+{
+ struct op_sharpe_parm *args = parm;
+ struct op_sharpe_handle *h;
+
+ h = malloc(sizeof(*h));
+ h->factor = args->factor;
+ h->linebuf = malloc(sizeof(int)*3*(src->i.width));
+
+ *i = src->i;
+ return h;
+}
+
+static void
+op_sharpe_work(struct ida_image *src, struct ida_rect *rect,
+ unsigned char *dst, int line, void *data)
+{
+ static struct op_3x3_parm laplace = {
+ f1: { 1, 1, 1 },
+ f2: { 1, -8, 1 },
+ f3: { 1, 1, 1 },
+ };
+ struct op_sharpe_handle *h = data;
+ unsigned char *scanline;
+ int i;
+
+ scanline = src->data + line * src->i.width * 3;
+ memcpy(dst,scanline,src->i.width * 3);
+ if (line < rect->y1 || line >= rect->y2)
+ return;
+
+ op_3x3_calc_line(src,rect,h->linebuf,line,&laplace);
+ for (i = rect->x1*3; i < rect->x2*3; i++)
+ h->linebuf[i] = scanline[i] - h->linebuf[i] * h->factor / 256;
+ op_3x3_clip_line(dst,h->linebuf,rect->x1,rect->x2);
+}
+
+static void
+op_sharpe_free(void *data)
+{
+ struct op_sharpe_handle *h = data;
+
+ free(h->linebuf);
+ free(h);
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct op_resize_state {
+ float xscale,yscale,inleft;
+ float *rowbuf;
+ unsigned int width,height,srcrow;
+};
+
+static void*
+op_resize_init(struct ida_image *src, struct ida_rect *rect,
+ struct ida_image_info *i, void *parm)
+{
+ struct op_resize_parm *args = parm;
+ struct op_resize_state *h;
+
+ h = malloc(sizeof(*h));
+ h->width = args->width;
+ h->height = args->height;
+ h->xscale = (float)args->width/src->i.width;
+ h->yscale = (float)args->height/src->i.height;
+ h->rowbuf = malloc(src->i.width * 3 * sizeof(float));
+ h->srcrow = 0;
+ h->inleft = 1;
+
+ *i = src->i;
+ i->width = args->width;
+ i->height = args->height;
+ i->dpi = args->dpi;
+ return h;
+}
+
+static void
+op_resize_work(struct ida_image *src, struct ida_rect *rect,
+ unsigned char *dst, int line, void *data)
+{
+ struct op_resize_state *h = data;
+ float outleft,left,weight,d0,d1,d2;
+ unsigned char *csrcline;
+ float *fsrcline;
+ unsigned int i,sx,dx;
+
+ /* scale y */
+ memset(h->rowbuf, 0, src->i.width * 3 * sizeof(float));
+ outleft = 1/h->yscale;
+ while (outleft > 0 && h->srcrow < src->i.height) {
+ if (outleft < h->inleft) {
+ weight = outleft * h->yscale;
+ h->inleft -= outleft;
+ outleft = 0;
+ } else {
+ weight = h->inleft * h->yscale;
+ outleft -= h->inleft;
+ h->inleft = 0;
+ }
+#if 0
+ if (debug)
+ fprintf(stderr,"y: %6.2f%%: %d/%d => %d/%d\n",
+ weight*100,h->srcrow,src->height,line,h->height);
+#endif
+ csrcline = src->data + h->srcrow * src->i.width * 3;
+ for (i = 0; i < src->i.width * 3; i++)
+ h->rowbuf[i] += (float)csrcline[i] * weight;
+ if (0 == h->inleft) {
+ h->inleft = 1;
+ h->srcrow++;
+ }
+ }
+
+ /* scale x */
+ left = 1;
+ fsrcline = h->rowbuf;
+ for (sx = 0, dx = 0; dx < h->width; dx++) {
+ d0 = d1 = d2 = 0;
+ outleft = 1/h->xscale;
+ while (outleft > 0 && dx < h->width && sx < src->i.width) {
+ if (outleft < left) {
+ weight = outleft * h->xscale;
+ left -= outleft;
+ outleft = 0;
+ } else {
+ weight = left * h->xscale;
+ outleft -= left;
+ left = 0;
+ }
+#if 0
+ if (debug)
+ fprintf(stderr," x: %6.2f%%: %d/%d => %d/%d\n",
+ weight*100,sx,src->width,dx,h->width);
+#endif
+ d0 += fsrcline[3*sx+0] * weight;
+ d1 += fsrcline[3*sx+1] * weight;
+ d2 += fsrcline[3*sx+2] * weight;
+ if (0 == left) {
+ left = 1;
+ sx++;
+ }
+ }
+ dst[0] = d0;
+ dst[1] = d1;
+ dst[2] = d2;
+ dst += 3;
+ }
+}
+
+static void
+op_resize_done(void *data)
+{
+ struct op_resize_state *h = data;
+
+ free(h->rowbuf);
+ free(h);
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct op_rotate_state {
+ float angle,sina,cosa;
+ struct ida_rect calc;
+ int cx,cy;
+};
+
+static void*
+op_rotate_init(struct ida_image *src, struct ida_rect *rect,
+ struct ida_image_info *i, void *parm)
+{
+ struct op_rotate_parm *args = parm;
+ struct op_rotate_state *h;
+ float diag;
+
+ h = malloc(sizeof(*h));
+ h->angle = args->angle * 2 * M_PI / 360;
+ h->sina = sin(h->angle);
+ h->cosa = cos(h->angle);
+ h->cx = (rect->x2 - rect->x1) / 2 + rect->x1;
+ h->cy = (rect->y2 - rect->y1) / 2 + rect->y1;
+
+ /* the area we have to process (worst case: 45°) */
+ diag = sqrt((rect->x2 - rect->x1)*(rect->x2 - rect->x1) +
+ (rect->y2 - rect->y1)*(rect->y2 - rect->y1))/2;
+ h->calc.x1 = h->cx - diag;
+ h->calc.x2 = h->cx + diag;
+ h->calc.y1 = h->cy - diag;
+ h->calc.y2 = h->cy + diag;
+ if (h->calc.x1 < 0)
+ h->calc.x1 = 0;
+ if (h->calc.x2 > src->i.width)
+ h->calc.x2 = src->i.width;
+ if (h->calc.y1 < 0)
+ h->calc.y1 = 0;
+ if (h->calc.y2 > src->i.height)
+ h->calc.y2 = src->i.height;
+
+ *i = src->i;
+ return h;
+}
+
+static inline
+unsigned char* op_rotate_getpixel(struct ida_image *src, struct ida_rect *rect,
+ int sx, int sy, int dx, int dy)
+{
+ static unsigned char black[] = { 0, 0, 0};
+
+ if (sx < rect->x1 || sx >= rect->x2 ||
+ sy < rect->y1 || sy >= rect->y2) {
+ if (dx < rect->x1 || dx >= rect->x2 ||
+ dy < rect->y1 || dy >= rect->y2)
+ return src->data + dy * src->i.width * 3 + dx * 3;
+ return black;
+ }
+ return src->data + sy * src->i.width * 3 + sx * 3;
+}
+
+static void
+op_rotate_work(struct ida_image *src, struct ida_rect *rect,
+ unsigned char *dst, int y, void *data)
+{
+ struct op_rotate_state *h = data;
+ unsigned char *pix;
+ float fx,fy,w;
+ int x,sx,sy;
+
+ pix = src->data + y * src->i.width * 3;
+ memcpy(dst,pix,src->i.width * 3);
+ if (y < h->calc.y1 || y >= h->calc.y2)
+ return;
+
+ dst += 3*h->calc.x1;
+ memset(dst, 0, (h->calc.x2-h->calc.x1) * 3);
+ for (x = h->calc.x1; x < h->calc.x2; x++, dst+=3) {
+ fx = h->cosa * (x - h->cx) - h->sina * (y - h->cy) + h->cx;
+ fy = h->sina * (x - h->cx) + h->cosa * (y - h->cy) + h->cy;
+ sx = (int)fx;
+ sy = (int)fy;
+ if (fx < 0)
+ sx--;
+ if (fy < 0)
+ sy--;
+ fx -= sx;
+ fy -= sy;
+
+ pix = op_rotate_getpixel(src,rect,sx,sy,x,y);
+ w = (1-fx) * (1-fy);
+ dst[0] += pix[0] * w;
+ dst[1] += pix[1] * w;
+ dst[2] += pix[2] * w;
+ pix = op_rotate_getpixel(src,rect,sx+1,sy,x,y);
+ w = fx * (1-fy);
+ dst[0] += pix[0] * w;
+ dst[1] += pix[1] * w;
+ dst[2] += pix[2] * w;
+ pix = op_rotate_getpixel(src,rect,sx,sy+1,x,y);
+ w = (1-fx) * fy;
+ dst[0] += pix[0] * w;
+ dst[1] += pix[1] * w;
+ dst[2] += pix[2] * w;
+ pix = op_rotate_getpixel(src,rect,sx+1,sy+1,x,y);
+ w = fx * fy;
+ dst[0] += pix[0] * w;
+ dst[1] += pix[1] * w;
+ dst[2] += pix[2] * w;
+ }
+}
+
+static void
+op_rotate_done(void *data)
+{
+ struct op_rotate_state *h = data;
+
+ free(h);
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct ida_op desc_grayscale = {
+ name: "grayscale",
+ init: op_none_init,
+ work: op_grayscale,
+ done: op_none_done,
+};
+struct ida_op desc_3x3 = {
+ name: "3x3",
+ init: op_3x3_init,
+ work: op_3x3_work,
+ done: op_3x3_free,
+};
+struct ida_op desc_sharpe = {
+ name: "sharpe",
+ init: op_sharpe_init,
+ work: op_sharpe_work,
+ done: op_sharpe_free,
+};
+struct ida_op desc_resize = {
+ name: "resize",
+ init: op_resize_init,
+ work: op_resize_work,
+ done: op_resize_done,
+};
+struct ida_op desc_rotate = {
+ name: "rotate",
+ init: op_rotate_init,
+ work: op_rotate_work,
+ done: op_rotate_done,
+};