#include #include #include #include #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" #include "effects.h" void rgb_to_hsv (double red, double green, double blue, double *hue, double *saturation, double *value) { double h, s, v; double min, max; double delta; h = 0.0; /* Shut up -Wall */ if (red > green) { if (red > blue) max = red; else max = blue; if (green < blue) min = green; else min = blue; } else { if (green > blue) max = green; else max = blue; if (red < blue) min = red; else min = blue; } v = max; if (max != 0.0) s = (max - min) / max; else s = 0.0; if (s == 0.0) { h = 0.0; } else { delta = max - min; if (red == max) h = (green - blue) / delta; else if (green == max) h = 2 + (blue - red) / delta; else if (blue == max) h = 4 + (red - green) / delta; h /= 6.0; if (h < 0.0) h += 1.0; else if (h >= 1.0) h -= 1.0; } *hue = h; *saturation = s; *value = v; } void hsv_to_rgb (double hue, double saturation, double value, double *red, double *green, double *blue) { double f, p, q, t; if (saturation == 0.0) { *red = value; *green = value; *blue = value; } else { hue *= 6.0; if (hue == 6.0) hue = 0.0; f = hue - (int) hue; p = value * (1.0 - saturation); q = value * (1.0 - saturation * f); t = value * (1.0 - saturation * (1.0 - f)); switch ((int) hue) { case 0: *red = value; *green = t; *blue = p; break; case 1: *red = q; *green = value; *blue = p; break; case 2: *red = p; *green = value; *blue = t; break; case 3: *red = p; *green = q; *blue = value; break; case 4: *red = t; *green = p; *blue = value; break; case 5: *red = value; *green = p; *blue = q; break; } } } double spread(double x) { return cos(x * M_PI) * -0.5 + 0.5; } void rainbow(gdouble *parameters, int width, int height, int bpp, guchar *srcpix, guchar *dstpix) { int pixsize = height * width * bpp; int i; for (i = 0; i < pixsize; i += bpp) { guchar r,g,b; double red, green, blue; double hue, saturation, value; r = srcpix[i]; g = srcpix[i+1]; b = srcpix[i+2]; red = r / 255.0; green = g / 255.0; blue = b / 255.0; rgb_to_hsv(red, green, blue, &hue, &saturation, &value); hue = value * (parameters[1] + 1.0) + parameters[0]; hue = hue - (int) hue; //value = 1.0; //saturation = 1.0; hsv_to_rgb(hue, saturation, value, &red, &green, &blue); r = red * 255; g = green * 255; b = blue * 255; dstpix[i] = r; dstpix[i+1] = g; dstpix[i+2] = b; } } void rubbing(gdouble *parameters, int width, int height, int bpp, guchar *srcpix, guchar *dstpix) /* the code herein is vastly inefficient. sue me. */ #define XY(X,Y) (((X) + (Y) * width) * bpp) { guchar *origpix; int pixsize = height * width * bpp; int x,y; int delta; if (parameters[0] != 0) delta = parameters[0]; else delta = 5; for (x = 0; x < width; x++) for (y = 0; y < height; y++) { int x2, y2; int count, total, average, orig; int color; total = 0; count = 0; for (x2 = -delta; x2 <= delta; x2++) for (y2 = -delta; y2 <= delta; y2++) { if (((x + x2) >= 0) && ((x + x2) < width) && ((y + y2) >= 0) && ((y + y2) < height)) { total += srcpix[XY(x + x2, y + y2)] + /* red */ srcpix[XY(x + x2, y + y2) + 1] + /* green */ srcpix[XY(x + x2, y + y2) + 2]; /* blue */ count++; } } average = total / count; orig = srcpix[XY(x,y)] + srcpix[XY(x,y)+1] + srcpix[XY(x,y)+2]; if (average > orig) color = 0; else color = 255; dstpix[XY(x,y)] = color; dstpix[XY(x,y)+1] = color; dstpix[XY(x,y)+2] = color; } } typedef struct _rect { int left; int top; int right; int bottom; } rect; typedef struct _rgb24 { unsigned char r; unsigned char g; unsigned char b; } rgb24; typedef struct _surface { int width; int height; int bpp; guchar *pix; } surface; void average_rgn(surface *surf, rect *rgn, rgb24 *c) { double r = 0; double g = 0; double b = 0; int i; int x, y; double blocksize = (rgn->right - rgn->left) * (rgn->bottom - rgn->top); /* printf("rgn: (%d, %d) x (%d, %d)\n\r", rgn->left, rgn->top, rgn->right, rgn->bottom); */ for (y = rgn->top; y < rgn->bottom; y++) { i = (y * surf->width * surf->bpp) + rgn->left * surf->bpp; for (x = rgn->left; x < rgn->right; x++) { r += surf->pix[i++]; g += surf->pix[i++]; b += surf->pix[i++]; } } /* printf("average_rgn: (%f, %f, %f)\n\r", r, g, b); */ c->r = (int)(r / blocksize); c->g = (int)(g / blocksize); c->b = (int)(b / blocksize); } void average_rgn_circle(surface *surf, rect *rgn, rgb24 *c) { double r = 0; double g = 0; double b = 0; int i; int x, y; int cx, cy; int radius; int rsquared; int dist; double blocksize = (rgn->right - rgn->left) * (rgn->bottom - rgn->top); radius = rgn->right - rgn->left; rsquared = radius * radius; cx = rgn->left + radius; cy = rgn->top + radius; for (y = rgn->top; y < rgn->bottom; y++) { i = (y * surf->width * surf->bpp) + rgn->left * surf->bpp; for (x = rgn->left; x < rgn->right; x++) { r += surf->pix[i++]; g += surf->pix[i++]; b += surf->pix[i++]; } } /* printf("average_rgn: (%f, %f, %f)\n\r", r, g, b); */ c->r = (int)(r / blocksize); c->g = (int)(g / blocksize); c->b = (int)(b / blocksize); } void mosaic(gdouble *parameters, int width, int height, int bpp, guchar *srcpix, guchar *dstpix) { surface surf = { width, height, bpp, srcpix }; int pixsize = height * width * bpp; int step; int x, y; int x2, y2; int i; int avgred, avgblue, avggreen; rect rgn; rgb24 c; /* First parameter determines the mosaic size */ if (parameters[0] != 0) step = parameters[0]; else step = 5; i = 0; printf("Gadget: dim (%d, %d) bpp=%d\n\r", width, height, bpp); for (y = 0; y < height; y += step) { for (x = 0; x < width; x += step) { rgn.left = x; rgn.top = y; rgn.right = x + step; rgn.bottom = y + step; if (rgn.right >= width) rgn.right = width - 1; if (rgn.bottom >= height) rgn.bottom = height - 1; average_rgn(&surf, &rgn, &c); for (y2 = y; y2 < y + step; y2++) { if (y2 >= height) break; i = y2 * width * bpp + x * bpp; for (x2 = 0; x2 < step; x2++) { if (x2 >= width) break; dstpix[i++] = c.r; dstpix[i++] = c.g; dstpix[i++] = c.b; } } } } #if 0 /* This flips the image vertically */ i = 0; for (y = height - 1; y >= 0; y--) { j = y * width * bpp; for (x = 0; x < width; x++) { dstpix[i++] = srcpix[j++]; dstpix[i++] = srcpix[j++]; dstpix[i++] = srcpix[j++]; } } #endif } void draw_circle(int x, int y, int radius, rgb24 *c, surface *src, surface *dst) { int width = src->width; int bpp = src->bpp; unsigned char r, g, b; int i, j; int cx, cy; int dist; int rsquared; int idx; double scale; cx = x + radius; cy = y + radius; rsquared = radius * radius; for (j = y; j < y + radius; j++) { for (i = x; i < x + radius; i++) { dist = (cx - i) * (cx - i) + (cy - j) * (cy - j); /* Inside circle? */ if (dist < rsquared) { scale = (double)((double)sqrt(dist) / (double)sqrt(rsquared)); scale = 1; r = c->r * scale; g = c->g * scale; b = c->b * scale; /* Quadrant II */ idx = XY(i, j); dst->pix[idx] = r; dst->pix[idx+1] = g; dst->pix[idx+2] = b; /* Quadrant I */ idx = XY(2 * cx - i - 1, j); dst->pix[idx] = r; dst->pix[idx+1] = g; dst->pix[idx+2] = b; /* Quadrant III */ idx = XY(i, 2 * cy - j - 1); dst->pix[idx] = r; dst->pix[idx+1] = g; dst->pix[idx+2] = b; /* Quadrant IV */ idx = XY(2 * cx - i - 1, 2 * cy - j - 1); dst->pix[idx] = r; dst->pix[idx+1] = g; dst->pix[idx+2] = b; } /* else { dst->pix[idx] = src->pix[idx]; dst->pix[idx+1] = src->pix[idx+1]; dst->pix[idx+2] = src->pix[idx+2]; } */ } } } void sniper(gdouble *parameters, int width, int height, int bpp, guchar *srcpix, guchar *dstpix) { surface src = { width, height, bpp, srcpix }; surface dst = { width, height, bpp, dstpix }; rgb24 reddish = { 200, 50, 50 }; rect rgn; rgb24 c; int radius; int diameter; int b_copy = 0; int i; int pixsize = height * width * bpp; int x, y; /* First parameter determines the radius */ if (parameters[0] != 0) radius = parameters[0]; else radius = 5; diameter = 2 * radius; /* Second parameter is a flag - copy original surface? */ b_copy = parameters[1]; /* Copy surface */ if (b_copy) { for (i = 0; i < pixsize; i++) { dstpix[i] = srcpix[i]; } } for (y = 0; y < height - diameter; y += diameter - 1) { for (x = 0; x < width - diameter; x += diameter - 1) { rgn.left = x; rgn.top = y; rgn.right = x + diameter; rgn.bottom = y + diameter; average_rgn(&src, &rgn, &c); draw_circle(x, y, radius, &c, &src, &dst); } } }