[gtk+/wip/blur: 2/7] Add code for blurring (original code from Unico, copyright fine for Gtk+)



commit 285474332294653cc685de9c131fd244811ac70b
Author: Andrea Cimitan <andrea cimitan canonical com>
Date:   Fri Apr 13 11:59:26 2012 +0200

    Add code for blurring (original code from Unico, copyright fine for Gtk+)

 gtk/Makefile.am    |    2 +
 gtk/gtkcairoblur.c |  267 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkcairoblur.h |   37 +++++++
 3 files changed, 306 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index e31feb2..798a76a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -415,6 +415,7 @@ gtk_private_h_sources =		\
 	gtkboxprivate.h         \
 	gtkbuilderprivate.h	\
 	gtkbuttonprivate.h	\
+	gtkcairoblurprivate.h	\
 	gtkcellareaboxcontextprivate.h	\
 	gtkcolorswatchprivate.h	\
 	gtkcoloreditorprivate.h	\
@@ -607,6 +608,7 @@ gtk_base_c_sources = 		\
 	gtkbuilderparser.c	\
 	gtkbuilder-menus.c	\
 	gtkbutton.c		\
+	gtkcairoblur.c		\
 	gtkcalendar.c		\
 	gtkcellarea.c		\
 	gtkcellareabox.c	\
diff --git a/gtk/gtkcairoblur.c b/gtk/gtkcairoblur.c
new file mode 100644
index 0000000..ce90175
--- /dev/null
+++ b/gtk/gtkcairoblur.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2012 Canonical Ltd
+ *
+ * This  library is free  software; you can  redistribute it and/or
+ * modify it  under  the terms  of the  GNU Lesser  General  Public
+ * License  as published  by the Free  Software  Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed  in the hope that it will be useful,
+ * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License  along  with  this library;  if not,  write to  the Free
+ * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <andrea cimitan canonical com>
+ * Original code from Mirco Mueller <mirco mueller canonical com>
+ *
+ */
+
+#include "gtkcairoblur.h"
+
+#include <math.h>
+
+/*
+ * Notes:
+ *   based on exponential-blur algorithm by Jani Huhtanen
+ */
+static inline void
+_blurinner (guchar* pixel,
+            gint   *zR,
+            gint   *zG,
+            gint   *zB,
+            gint   *zA,
+            gint    alpha,
+            gint    aprec,
+            gint    zprec)
+{
+  gint R;
+  gint G;
+  gint B;
+  guchar A;
+
+  R = *pixel;
+  G = *(pixel + 1);
+  B = *(pixel + 2);
+  A = *(pixel + 3);
+
+  *zR += (alpha * ((R << zprec) - *zR)) >> aprec;
+  *zG += (alpha * ((G << zprec) - *zG)) >> aprec;
+  *zB += (alpha * ((B << zprec) - *zB)) >> aprec;
+  *zA += (alpha * ((A << zprec) - *zA)) >> aprec;
+
+  *pixel       = *zR >> zprec;
+  *(pixel + 1) = *zG >> zprec;
+  *(pixel + 2) = *zB >> zprec;
+  *(pixel + 3) = *zA >> zprec;
+} 
+
+static inline void
+_blurrow (guchar* pixels,
+          gint    width,
+          gint    height,
+          gint    channels,
+          gint    line,
+          gint    alpha,
+          gint    aprec,
+          gint    zprec)
+{
+  gint    zR;
+  gint    zG;
+  gint    zB;
+  gint    zA;
+  gint    index;
+  guchar* scanline;
+
+  scanline = &(pixels[line * width * channels]);
+
+  zR = *scanline << zprec;
+  zG = *(scanline + 1) << zprec;
+  zB = *(scanline + 2) << zprec;
+  zA = *(scanline + 3) << zprec;
+
+  for (index = 0; index < width; index ++)
+    _blurinner (&scanline[index * channels],
+                &zR,
+                &zG,
+                &zB,
+                &zA,
+                alpha,
+                aprec,
+                zprec);
+
+  for (index = width - 2; index >= 0; index--)
+    _blurinner (&scanline[index * channels],
+                &zR,
+                &zG,
+                &zB,
+                &zA,
+                alpha,
+                aprec,
+                zprec);
+}
+
+static inline void
+_blurcol (guchar* pixels,
+          gint    width,
+          gint    height,
+          gint    channels,
+          gint    x,
+          gint    alpha,
+          gint    aprec,
+          gint    zprec)
+{
+  gint zR;
+  gint zG;
+  gint zB;
+  gint zA;
+  gint index;
+  guchar* ptr;
+
+  ptr = pixels;
+  
+  ptr += x * channels;
+
+  zR = *((guchar*) ptr    ) << zprec;
+  zG = *((guchar*) ptr + 1) << zprec;
+  zB = *((guchar*) ptr + 2) << zprec;
+  zA = *((guchar*) ptr + 3) << zprec;
+
+  for (index = width; index < (height - 1) * width; index += width)
+    _blurinner ((guchar*) &ptr[index * channels],
+                &zR,
+                &zG,
+                &zB,
+                &zA,
+                alpha,
+                aprec,
+                zprec);
+
+  for (index = (height - 2) * width; index >= 0; index -= width)
+    _blurinner ((guchar*) &ptr[index * channels],
+                &zR,
+                &zG,
+                &zB,
+                &zA,
+                alpha,
+                aprec,
+                zprec);
+}
+
+/*
+ * _expblur:
+ * @pixels: image data
+ * @width: image width
+ * @height: image height
+ * @channels: image channels
+ * @radius: kernel radius
+ * @aprec: precision of alpha parameter in fixed-point format 0.aprec
+ * @zprec: precision of state parameters zR,zG,zB and zA in fp format 8.zprec
+ *
+ * Performs an in-place blur of image data 'pixels'
+ * with kernel of approximate radius 'radius'.
+ *
+ * Blurs with two sided exponential impulse response.
+ *
+ */
+static void
+_expblur (guchar* pixels,
+          gint    width,
+          gint    height,
+          gint    channels,
+          gint    radius,
+          gint    aprec,
+          gint    zprec)
+{
+  gint alpha;
+  gint row = 0;
+  gint col = 0;
+
+  if (radius < 1)
+    return;
+
+  /* Calculate the alpha such that 90% of 
+   * the kernel is within the radius.
+   * (Kernel extends to infinity) */
+  alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
+
+  for (; row < height; row++)
+    _blurrow (pixels,
+              width,
+              height,
+              channels,
+              row,
+              alpha,
+              aprec,
+              zprec);
+
+  for(; col < width; col++)
+    _blurcol (pixels,
+              width,
+              height,
+              channels,
+              col,
+              alpha,
+              aprec,
+              zprec);
+}
+
+
+/*
+ * _gtk_cairo_blur_surface:
+ * @surface: a cairo image surface.
+ * @radius: the blur radius.
+ *
+ * Blurs the cairo image surface at the given radius.
+ *
+ */
+void
+_gtk_cairo_blur_surface (cairo_surface_t* surface,
+                         guint            radius)
+{
+  cairo_format_t format;
+  guchar*        pixels;
+  guint          width;
+  guint          height;
+
+  g_return_if_fail (surface != NULL);
+  g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+  format = cairo_image_surface_get_format (surface);
+  g_return_if_fail (format == CAIRO_FORMAT_A8 ||
+                    format == CAIRO_FORMAT_RGB24 ||
+                    format == CAIRO_FORMAT_ARGB32);
+
+  if (radius == 0)
+    return;
+
+  /* Before we mess with the surface execute any pending drawing. */
+  cairo_surface_flush (surface);
+
+  pixels = cairo_image_surface_get_data (surface);
+  width  = cairo_image_surface_get_width (surface);
+  height = cairo_image_surface_get_height (surface);
+  format = cairo_image_surface_get_format (surface);
+
+  switch (format)
+  {
+    case CAIRO_FORMAT_ARGB32:
+      _expblur (pixels, width, height, 4, radius, 16, 7);
+      break;
+    case CAIRO_FORMAT_RGB24:
+      _expblur (pixels, width, height, 3, radius, 16, 7);
+      break;
+    case CAIRO_FORMAT_A8:
+      _expblur (pixels, width, height, 1, radius, 16, 7);
+      break;
+    default:
+      break;
+  }
+
+  /* Inform cairo we altered the surfaces contents. */
+  cairo_surface_mark_dirty (surface);
+}
diff --git a/gtk/gtkcairoblur.h b/gtk/gtkcairoblur.h
new file mode 100644
index 0000000..0b93bb5
--- /dev/null
+++ b/gtk/gtkcairoblur.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Canonical Ltd
+ *
+ * This  library is free  software; you can  redistribute it and/or
+ * modify it  under  the terms  of the  GNU Lesser  General  Public
+ * License  as published  by the Free  Software  Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed  in the hope that it will be useful,
+ * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License  along  with  this library;  if not,  write to  the Free
+ * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <andrea cimitan canonical com>
+ * Original code from Mirco Mueller <mirco mueller canonical com>
+ *
+ */
+
+#ifndef _GTK_CAIRO_BLUR_H
+#define _GTK_CAIRO_BLUR_H
+
+#include <glib.h>
+#include <cairo.h>
+
+G_BEGIN_DECLS
+
+void            _gtk_cairo_blur_surface (cairo_surface_t* surface,
+                                         guint            radius);
+
+G_END_DECLS
+
+#endif /* _GTK_CAIRO_BLUR_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]