summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2011-07-28 18:39:29 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2011-07-28 18:39:46 -0400
commitdcc2856b6e8ee30ffbcc33e8305d3ea3e96fe7f7 (patch)
tree83068f2ad8ae11e6c20c5b0bf74c9d3f82989dcc
parent6235d222a29739152df9f1fa0f07ef3ad78cc3eb (diff)
Add pngtrans.c
-rw-r--r--fft.c14
-rw-r--r--fft.h19
-rw-r--r--pngtrans.c295
3 files changed, 327 insertions, 1 deletions
diff --git a/fft.c b/fft.c
index 46215cb..96dbdaa 100644
--- a/fft.c
+++ b/fft.c
@@ -166,3 +166,17 @@ shift_2d (complex_t *buffer, int n)
}
}
}
+
+void
+fft_shift_2d (complex_t *buffer, int n)
+{
+ fft_2d (buffer, n);
+ shift_2d (buffer, n);
+}
+
+void
+ifft_shift_2d (complex_t *buffer, int n)
+{
+ shift_2d (buffer, n);
+ ifft_2d (buffer, n);
+}
diff --git a/fft.h b/fft.h
index 31d7667..61d4ba9 100644
--- a/fft.h
+++ b/fft.h
@@ -55,7 +55,18 @@ complex_mag (complex_t a)
static inline double
complex_arg (complex_t a)
{
- return atan2 (a.im, a.re) + M_PI;
+ return fmod (atan2 (a.im, a.re) + 2 * M_PI, 2 * M_PI);
+}
+
+static inline complex_t
+complex_from_mag_arg (double mag, double arg)
+{
+ complex_t r;
+
+ r.re = mag * cos (arg);
+ r.im = mag * sin (arg);
+
+ return r;
}
static inline double
@@ -85,4 +96,10 @@ void
shift_2d (complex_t *buffer, int n);
void
+fft_shift_2d (complex_t *buffer, int n);
+
+void
+ifft_shift_2d (complex_t *buffer, int n);
+
+void
show_image (const char *name, complex_t *image, int n);
diff --git a/pngtrans.c b/pngtrans.c
new file mode 100644
index 0000000..37cb1c8
--- /dev/null
+++ b/pngtrans.c
@@ -0,0 +1,295 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkpixbuf.h>
+#include "fft.h"
+
+typedef struct complex_image_t complex_image_t;
+struct complex_image_t
+{
+ int width;
+ int height;
+ complex_t *red;
+ complex_t *green;
+ complex_t *blue;
+};
+
+static complex_image_t *
+complex_image_new (int width, int height)
+{
+ complex_image_t *image = g_new0 (complex_image_t, 1);
+
+ image->width = width;
+ image->height = height;
+ image->red = g_new0 (complex_t, width * height);
+ image->green = g_new0 (complex_t, width * height);
+ image->blue = g_new0 (complex_t, width * height);
+
+ return image;
+}
+
+static complex_image_t *
+complex_image_from_pixbuf (GdkPixbuf *pixbuf)
+{
+ complex_image_t *result;
+ uint8_t *pdata;
+ int w, h, s;
+ int i, j;
+ gboolean has_alpha;
+ int n_channels;
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+ s = gdk_pixbuf_get_rowstride (pixbuf);
+ pdata = gdk_pixbuf_get_pixels (pixbuf);
+ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+ n_channels = 3 + has_alpha;
+
+ printf ("has alpha: %d\n", has_alpha);
+
+ result = complex_image_new (w, h);
+
+ for (i = 0; i < h; ++i)
+ {
+ for (j = 0; j < w; ++j)
+ {
+ uint8_t *p = &pdata[i * s + j * n_channels];
+ int idx = i * w + j;
+
+ result->red[idx].re = p[0] / 255.0;
+ result->green[idx].re = p[1] / 255.0;
+ result->blue[idx].re = p[2] / 255.0;
+ }
+ }
+
+ return result;
+}
+
+typedef uint8_t (* convert_t) (complex_t c);
+
+static GdkPixbuf *
+pixbuf_from_complex_image (complex_image_t *image, convert_t convert)
+{
+ int w = image->width;
+ int h = image->height;
+ GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
+ uint8_t *p_bits = (uint8_t *)gdk_pixbuf_get_pixels (pixbuf);
+ int s = gdk_pixbuf_get_rowstride (pixbuf);
+ int i, j;
+
+ for (i = 0; i < h; ++i)
+ {
+ for (j = 0; j < w; ++j)
+ {
+ uint8_t *p = &(p_bits[i * s + j * 4]);
+ int idx = i * w + j;
+
+ p[0] = convert (image->red[idx]);
+ p[1] = convert (image->green[idx]);
+ p[2] = convert (image->blue[idx]);
+ p[3] = 0xff; // convert (image->alpha[idx]);
+ }
+ }
+
+ return pixbuf;
+}
+
+#define SIZE 1024
+#define SIZE 1024
+
+static gboolean
+on_expose (GtkWidget *widget, GdkEventExpose *expose, gpointer data)
+{
+ GdkPixbuf *pixbuf = data;
+ int i, j;
+ int pwidth = gdk_pixbuf_get_width (pixbuf);
+ int pheight = gdk_pixbuf_get_height (pixbuf);
+ int dwidth, dheight;
+
+ gdk_drawable_get_size (widget->window, &dwidth, &dheight);
+
+ for (i = 0; i < dheight; i += pheight)
+ {
+ for (j = 0; j < dwidth; j += pwidth)
+ {
+ gdk_draw_pixbuf (widget->window, NULL,
+ pixbuf, 0, 0, j, i, pwidth, pheight,
+ GDK_RGB_DITHER_NONE,
+ 0, 0);
+ }
+ }
+ return TRUE;
+}
+
+typedef enum
+{
+ DISPLAY_MAG,
+ DISPLAY_RE
+} display_type_t;
+
+static uint8_t
+convert_mag (complex_t d)
+{
+ double m = complex_mag (d);
+
+ m = log (m) / 10.0;
+
+ if (m > 1.0)
+ {
+ printf ("%f\n", m);
+ m = 1.0;
+ }
+
+ if (m < 0)
+ m = 0;
+
+ return (uint8_t) (m * 255.0 + 0.5);
+}
+
+static uint8_t
+convert_re (complex_t c)
+{
+ if (c.re > 1.0)
+ c.re = 1.0;
+ if (c.re < 0)
+ c.re = 0;
+
+ return c.re * 255.0 + 0.5;
+}
+
+static void
+display (const char *name, complex_image_t *image, display_type_t type)
+{
+ GtkWidget *window, *da;
+ GdkPixbuf *pixbuf;
+ int argc;
+ char **argv;
+ char *arg0 = g_strdup (name);
+ convert_t convert;
+
+ argc = 1;
+ argv = (char **)&arg0;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ da = gtk_drawing_area_new ();
+
+ gtk_container_add (GTK_CONTAINER (window), da);
+
+ gtk_window_set_default_size (GTK_WINDOW (window), SIZE, SIZE);
+
+ switch (type)
+ {
+ case DISPLAY_MAG: convert = convert_mag; break;
+ case DISPLAY_RE: convert = convert_re; break;
+ default:
+ g_assert_not_reached();
+ }
+
+ pixbuf = pixbuf_from_complex_image (image, convert);
+
+ g_signal_connect (da, "expose_event", G_CALLBACK (on_expose), pixbuf);
+ g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+}
+
+static void
+image_fft (complex_image_t *image)
+{
+ fft_shift_2d (image->red, image->width);
+ fft_shift_2d (image->green, image->width);
+ fft_shift_2d (image->blue, image->width);
+}
+
+static void
+image_ifft (complex_image_t *image)
+{
+ ifft_shift_2d (image->red, image->width);
+ ifft_shift_2d (image->green, image->width);
+ ifft_shift_2d (image->blue, image->width);
+}
+
+static complex_t
+filter (complex_t c, double dist)
+{
+ double m = complex_mag (c);
+ double arg = complex_arg (c);
+
+ return complex_from_mag_arg (m * (1/(pow (sqrt (dist) / 16.0, 4) + 1)) , arg);
+}
+
+static void
+low_pass (complex_image_t *image, double d)
+{
+ int w = image->width;
+ int h = image->height;
+ int i, j;
+ double d2 = d * d;
+ int c = h / 2;
+
+ for (i = 0; i < h; ++i)
+ {
+ for (j = 0; j < w; ++j)
+ {
+ int idx = i * w + j;
+ double dist = (c - i) * (c - i) + (c - j) * (c -j);
+ double t;
+
+ image->red[idx] = filter (image->red[idx], dist);
+ image->green[idx] = filter (image->green[idx], dist);
+ image->blue[idx] = filter (image->blue[idx], dist);
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ char *input, *output;
+ GdkPixbuf *pb;
+ complex_image_t *image;
+
+ g_type_init ();
+
+ if (argc < 3)
+ {
+ printf ("Usage: %s <input name> <output name>\n\n", argv[0]);
+ return 1;
+ }
+
+ input = argv[1];
+ output = argv[2];
+
+ if (!(pb = gdk_pixbuf_new_from_file (input, NULL)))
+ {
+ printf ("Could not open %s\n", input);
+ return -1;
+ }
+
+ image = complex_image_from_pixbuf (pb);
+
+ g_print ("width, height %d %d\n", image->width, image->height);
+
+ image_fft (image);
+
+
+ low_pass (image, 2 * image->width);
+
+#if 0
+ display ("test", image, DISPLAY_MAG);
+#endif
+#if 0
+#endif
+
+ image_ifft (image);
+
+ display ("test", image, DISPLAY_RE);
+
+ return 0;
+}