[lasem] svg_morphology: import algorithm from librsvg



commit 7466f0b3b28001892441edf484b3fee5c6b9aca5
Author: Emmanuel Pacaud <emmanuel gnome org>
Date:   Sun Aug 2 12:19:31 2015 +0200

    svg_morphology: import algorithm from librsvg

 docs/reference/lasem/Makefile.am |    3 +
 src/Makefile.am                  |    4 +
 src/lsmsvgdocument.c             |    3 +
 src/lsmsvgfiltermorphology.c     |  116 ++++++++++++++++++++++++++++++++++++++
 src/lsmsvgfiltermorphology.h     |   58 +++++++++++++++++++
 src/lsmsvgfiltersurface.c        |   82 ++++++++++++++++++++++++++-
 src/lsmsvgfiltersurface.h        |    2 +
 src/lsmsvgtraits.h               |    1 +
 src/lsmsvgtypes.h                |    1 +
 src/lsmsvgview.c                 |   28 +++++++++
 src/lsmsvgview.h                 |    2 +
 11 files changed, 299 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/lasem/Makefile.am b/docs/reference/lasem/Makefile.am
index 75b668c..a88e1c3 100644
--- a/docs/reference/lasem/Makefile.am
+++ b/docs/reference/lasem/Makefile.am
@@ -153,11 +153,14 @@ IGNORE_HFILES=\
        lsmsvgfilterprimitive.h                 \
        lsmsvgfilterblend.h                     \
        lsmsvgfiltercomposite.h                 \
+       lsmsvgfiltercolormatrix.h               \
        lsmsvgfilterflood.h                     \
        lsmsvgfiltergaussianblur.h              \
+       lsmsvgfilterimage.h                     \
        lsmsvgfilteroffset.h                    \
        lsmsvgfiltermerge.h                     \
        lsmsvgfiltermergenode.h                 \
+       lsmsvgfiltermorphology.h                \
        lsmsvgfilterspecularlighting.h          \
        lsmsvgfiltertile.h                      \
        lsmsvgfiltersurface.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d78c57..98640b8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -142,6 +142,7 @@ LASEM_SVG_SRCS =                            \
        lsmsvgfilteroffset.c                    \
        lsmsvgfiltermerge.c                     \
        lsmsvgfiltermergenode.c                 \
+       lsmsvgfiltermorphology.c                \
        lsmsvgfilterspecularlighting.c          \
        lsmsvgfiltertile.c                      \
        lsmsvgfiltersurface.c
@@ -254,12 +255,15 @@ LASEM_SVG_HDRS =                          \
        lsmsvgfilterelement.h                   \
        lsmsvgfilterprimitive.h                 \
        lsmsvgfilterblend.h                     \
+       lsmsvgfiltercolormatrix.h               \
        lsmsvgfiltercomposite.h                 \
        lsmsvgfilterflood.h                     \
        lsmsvgfiltergaussianblur.h              \
+       lsmsvgfilterimage.h                     \
        lsmsvgfilteroffset.h                    \
        lsmsvgfiltermerge.h                     \
        lsmsvgfiltermergenode.h                 \
+       lsmsvgfiltermorphology.h                \
        lsmsvgfilterspecularlighting.h          \
        lsmsvgfiltertile.h                      \
        lsmsvgfiltersurface.h
diff --git a/src/lsmsvgdocument.c b/src/lsmsvgdocument.c
index 99ade04..c5e7b67 100644
--- a/src/lsmsvgdocument.c
+++ b/src/lsmsvgdocument.c
@@ -37,6 +37,7 @@
 #include <lsmsvgfilteroffset.h>
 #include <lsmsvgfiltermerge.h>
 #include <lsmsvgfiltermergenode.h>
+#include <lsmsvgfiltermorphology.h>
 #include <lsmsvgfilterspecularlighting.h>
 #include <lsmsvgfiltercolormatrix.h>
 #include <lsmsvgfiltertile.h>
@@ -172,6 +173,8 @@ _create_element (LsmDomDocument *document, const char *tag_name)
                node = lsm_svg_filter_color_matrix_new ();
        else if (strcmp (tag_name, "feImage") == 0)
                node = lsm_svg_filter_image_new ();
+       else if (strcmp (tag_name, "feMorphology") == 0)
+               node = lsm_svg_filter_morphology_new ();
        else if (strcmp (tag_name, "feTile") == 0)
                node = lsm_svg_filter_tile_new ();
 
diff --git a/src/lsmsvgfiltermorphology.c b/src/lsmsvgfiltermorphology.c
new file mode 100644
index 0000000..52dfded
--- /dev/null
+++ b/src/lsmsvgfiltermorphology.c
@@ -0,0 +1,116 @@
+/* Lasem
+ * 
+ * Copyright © 2015 Emmanuel Pacaud
+ *
+ * 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#include <lsmsvgfiltermorphology.h>
+#include <lsmsvgview.h>
+
+static GObjectClass *parent_class;
+
+/* GdomNode implementation */
+
+static const char *
+lsm_svg_filter_morphology_get_node_name (LsmDomNode *node)
+{
+       return "feMorphology";
+}
+
+/* LsmSvgElement implementation */
+
+static void
+lsm_svg_filter_morphology_apply  (LsmSvgFilterPrimitive *self, LsmSvgView *view,
+                            const char *input, const char *output, const LsmBox *subregion)
+{
+       double radius;
+
+       LsmSvgFilterMorphology *morphology = LSM_SVG_FILTER_MORPHOLOGY (self);
+
+       radius = lsm_svg_view_normalize_length (view, &morphology->radius.length, 
LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+
+       lsm_svg_view_apply_morphology (view, input, output, subregion, morphology->op.value, radius);
+}
+
+/* LsmSvgFilterMorphology implementation */
+
+LsmDomNode *
+lsm_svg_filter_morphology_new (void)
+{
+       return g_object_new (LSM_TYPE_SVG_FILTER_MORPHOLOGY, NULL);
+}
+
+static const LsmSvgLength radius_default = { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgMorphologyOperator operator_default = LSM_SVG_MORPHOLOGY_OPERATOR_ERODE;
+
+static void
+lsm_svg_filter_morphology_init (LsmSvgFilterMorphology *self)
+{
+       self->radius.length = radius_default;
+       self->op.value = operator_default;
+}
+
+static void
+lsm_svg_filter_morphology_finalize (GObject *object)
+{
+       parent_class->finalize (object);
+}
+
+/* LsmSvgFilterMorphology class */
+
+static const LsmAttributeInfos lsm_svg_filter_morphology_attribute_infos[] = {
+       {
+               .name = "radius",
+               .attribute_offset = offsetof (LsmSvgFilterMorphology, radius),
+               .trait_class = &lsm_svg_length_trait_class,
+               .trait_default = &radius_default
+       },
+       {
+               .name = "operator",
+               .attribute_offset = offsetof (LsmSvgFilterMorphology, op),
+               .trait_class = &lsm_svg_morphology_operator_trait_class,
+               .trait_default = &operator_default
+       }
+};
+
+static void
+lsm_svg_filter_morphology_class_init (LsmSvgFilterMorphologyClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       LsmDomNodeClass *d_node_class = LSM_DOM_NODE_CLASS (klass);
+       LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_CLASS (klass);
+       LsmSvgFilterPrimitiveClass *f_primitive_class = LSM_SVG_FILTER_PRIMITIVE_CLASS (klass);
+
+       parent_class = g_type_class_peek_parent (klass);
+
+       object_class->finalize = lsm_svg_filter_morphology_finalize;
+
+       d_node_class->get_node_name = lsm_svg_filter_morphology_get_node_name;
+
+       s_element_class->attribute_manager = lsm_attribute_manager_duplicate 
(s_element_class->attribute_manager);
+
+       lsm_attribute_manager_add_attributes (s_element_class->attribute_manager,
+                                             G_N_ELEMENTS (lsm_svg_filter_morphology_attribute_infos),
+                                             lsm_svg_filter_morphology_attribute_infos);
+
+       f_primitive_class->apply = lsm_svg_filter_morphology_apply;
+}
+
+G_DEFINE_TYPE (LsmSvgFilterMorphology, lsm_svg_filter_morphology, LSM_TYPE_SVG_FILTER_PRIMITIVE)
diff --git a/src/lsmsvgfiltermorphology.h b/src/lsmsvgfiltermorphology.h
new file mode 100644
index 0000000..8bcb1af
--- /dev/null
+++ b/src/lsmsvgfiltermorphology.h
@@ -0,0 +1,58 @@
+/* Lasem
+ *
+ * Copyright © 2015 Emmanuel Pacaud
+ *
+ * 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#ifndef LSM_SVG_FILTER_MORPHOLOGY_H
+#define LSM_SVG_FILTER_MORPHOLOGY_H
+
+#include <lsmsvgtypes.h>
+#include <lsmsvgfilterprimitive.h>
+
+G_BEGIN_DECLS
+
+#define LSM_TYPE_SVG_FILTER_MORPHOLOGY             (lsm_svg_filter_morphology_get_type ())
+#define LSM_SVG_FILTER_MORPHOLOGY(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
LSM_TYPE_SVG_FILTER_MORPHOLOGY, LsmSvgFilterMorphology))
+#define LSM_SVG_FILTER_MORPHOLOGY_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
LSM_TYPE_SVG_FILTER_MORPHOLOGY, LsmSvgFilterMorphologyClass))
+#define LSM_IS_SVG_FILTER_MORPHOLOGY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
LSM_TYPE_SVG_FILTER_MORPHOLOGY))
+#define LSM_IS_SVG_FILTER_MORPHOLOGY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
LSM_TYPE_SVG_FILTER_MORPHOLOGY))
+#define LSM_SVG_FILTER_MORPHOLOGY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), 
LSM_TYPE_SVG_FILTER_MORPHOLOGY, LsmSvgFilterMorphologyClass))
+
+typedef struct _LsmSvgFilterMorphologyClass LsmSvgFilterMorphologyClass;
+
+struct _LsmSvgFilterMorphology {
+       LsmSvgFilterPrimitive base;
+
+       LsmSvgMorphologyOperatorAttribute op;
+       LsmSvgLengthAttribute radius;
+};
+
+struct _LsmSvgFilterMorphologyClass {
+       LsmSvgFilterPrimitiveClass  element_class;
+};
+
+GType lsm_svg_filter_morphology_get_type (void);
+
+LsmDomNode *   lsm_svg_filter_morphology_new           (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/lsmsvgfiltersurface.c b/src/lsmsvgfiltersurface.c
index 5a8f171..c3dc4fd 100644
--- a/src/lsmsvgfiltersurface.c
+++ b/src/lsmsvgfiltersurface.c
@@ -32,6 +32,8 @@
 #include <math.h>
 #include <string.h>
 
+static const int channelmap[4] = {2, 1, 0, 3};
+
 struct _LsmSvgFilterSurface {
        char *name;
        cairo_surface_t *surface;
@@ -479,7 +481,6 @@ lsm_svg_filter_surface_color_matrix (LsmSvgFilterSurface *input, LsmSvgFilterSur
        gint sum;
        guchar *in_pixels;
        guchar *output_pixels;
-       int channelmap[4] = {2, 1, 0, 3};
        double setting;
 
        g_return_if_fail (input != NULL);
@@ -646,3 +647,82 @@ lsm_svg_filter_surface_image (LsmSvgFilterSurface *output, GdkPixbuf *pixbuf,
 
        cairo_destroy (cairo);
 }
+
+void
+lsm_svg_filter_surface_morphology (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
+                                  LsmSvgMorphologyOperator op, double rx, double ry)
+{
+       cairo_t *cairo;
+       int i, j;
+       int ch, extreme;
+       gint x, y, x1, x2, y1, y2;
+       gint width, height;
+       gint rowstride;
+       guchar *in_pixels;
+       guchar *output_pixels;
+       gint kx, ky;
+       guchar val;
+
+       g_return_if_fail (input != NULL);
+       g_return_if_fail (output != NULL);
+
+       width = cairo_image_surface_get_width (input->surface);
+       height = cairo_image_surface_get_height (input->surface);
+
+       if (width != cairo_image_surface_get_width (output->surface) ||
+           height != cairo_image_surface_get_height (output->surface))
+               return;
+
+       if (height < 1 || width < 1)
+               return;
+
+       kx = rx;
+       ky = ry;
+
+       if (kx < 1 && ky < 1)
+               return;
+
+       cairo_surface_flush (input->surface);
+       cairo = cairo_create (output->surface);
+
+       in_pixels = cairo_image_surface_get_data (input->surface);
+       output_pixels = cairo_image_surface_get_data (output->surface);
+       rowstride = cairo_image_surface_get_stride (input->surface);
+
+       x1 = CLAMP (input->subregion.x, 0, width);
+       x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
+       y1 = CLAMP (input->subregion.y, 0, height);
+       y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
+
+       for (y = y1; y < y2; y++)
+               for (x = x1; x < x2; x++)
+                       for (ch = 0; ch < 4; ch++) {
+                               if (op == LSM_SVG_MORPHOLOGY_OPERATOR_ERODE)
+                                       extreme = 255;
+                               else
+                                       extreme = 0;
+                               for (i = -ky; i < ky + 1; i++)
+                                       for (j = -kx; j < kx + 1; j++) {
+                                               if (y + i >= height || y + i < 0 || x + j >= width || x + j < 
0)
+                                                       continue;
+
+                                               val = in_pixels[(y + i) * rowstride + (x + j) * 4 + ch];
+
+
+                                               if (op == LSM_SVG_MORPHOLOGY_OPERATOR_ERODE) {
+                                                       if (extreme > val)
+                                                               extreme = val;
+                                               } else {
+                                                       if (extreme < val)
+                                                               extreme = val;
+                                               }
+
+                                       }
+                               output_pixels[y * rowstride + x * 4 + ch] = extreme;
+                       }
+
+       cairo_surface_mark_dirty (output->surface);
+
+       cairo_destroy (cairo);
+}
+
diff --git a/src/lsmsvgfiltersurface.h b/src/lsmsvgfiltersurface.h
index 48c9bfd..20574d1 100644
--- a/src/lsmsvgfiltersurface.h
+++ b/src/lsmsvgfiltersurface.h
@@ -66,6 +66,8 @@ void                  lsm_svg_filter_surface_color_matrix     (LsmSvgFilterSurface *input, 
LsmSvg
                                                                 LsmSvgColorFilterType type, unsigned 
n_values, const double *values);
 void                   lsm_svg_filter_surface_image            (LsmSvgFilterSurface *output, GdkPixbuf 
*pixbuf,
                                                                 LsmSvgPreserveAspectRatio 
preserve_aspect_ratio);
+void                   lsm_svg_filter_surface_morphology       (LsmSvgFilterSurface *input_surface, 
LsmSvgFilterSurface *output_surface,
+                                                                LsmSvgMorphologyOperator op, double rx, 
double ry);
 
 G_END_DECLS
 
diff --git a/src/lsmsvgtraits.h b/src/lsmsvgtraits.h
index 64f16aa..5ef84d4 100644
--- a/src/lsmsvgtraits.h
+++ b/src/lsmsvgtraits.h
@@ -95,6 +95,7 @@ extern const LsmTraitClass lsm_svg_line_join_trait_class;
 extern const LsmTraitClass lsm_svg_line_cap_trait_class;
 extern const LsmTraitClass lsm_svg_marker_units_trait_class;
 extern const LsmTraitClass lsm_svg_matrix_trait_class;
+extern const LsmTraitClass lsm_svg_morphology_operator_trait_class;
 extern const LsmTraitClass lsm_svg_one_or_two_double_trait_class;
 extern const LsmTraitClass lsm_svg_vector_trait_class;
 extern const LsmTraitClass lsm_svg_overflow_trait_class;
diff --git a/src/lsmsvgtypes.h b/src/lsmsvgtypes.h
index d3931da..554e2e4 100644
--- a/src/lsmsvgtypes.h
+++ b/src/lsmsvgtypes.h
@@ -54,6 +54,7 @@ typedef struct _LsmSvgFilterGaussianBlur LsmSvgFilterGaussianBlur;
 typedef struct _LsmSvgFilterImage LsmSvgFilterImage;
 typedef struct _LsmSvgFilterMerge LsmSvgFilterMerge;
 typedef struct _LsmSvgFilterMergeNode LsmSvgFilterMergeNode;
+typedef struct _LsmSvgFilterMorphology LsmSvgFilterMorphology;
 typedef struct _LsmSvgFilterOffset LsmSvgFilterOffset;
 typedef struct _LsmSvgFilterSpecularLighting LsmSvgFilterSpecularLighting;
 typedef struct _LsmSvgFilterTile LsmSvgFilterTile;
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 61647db..51e7386 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -2222,6 +2222,34 @@ lsm_svg_view_apply_color_matrix (LsmSvgView *view, const char *input, const char
        lsm_svg_filter_surface_color_matrix (input_surface, output_surface, type, n_values, values);
 }
 
+void 
+lsm_svg_view_apply_morphology (LsmSvgView *view, const char *input, const char *output, const LsmBox 
*subregion,
+                              LsmSvgMorphologyOperator op, double radius)
+{
+       LsmSvgFilterSurface *input_surface;
+       LsmSvgFilterSurface *output_surface;
+       LsmBox subregion_px;
+       double rx, ry;
+
+       g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+       input_surface = _get_filter_surface (view, input);
+
+       if (input_surface == NULL) {
+               lsm_debug_render ("[SvgView::apply_morphoogy] Input '%s' not found", input);
+               return;
+       }
+
+       lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
+       output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
+
+       rx = radius;
+       ry = radius;
+       cairo_user_to_device_distance (view->dom_view.cairo, &rx, &ry);
+
+       lsm_svg_filter_surface_morphology (input_surface, output_surface, op, rx, ry);
+}
+
 void
 lsm_svg_view_apply_merge (LsmSvgView *view, const char *input, const char *output, const LsmBox *subregion)
 {
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 128fc62..d1c4224 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -179,6 +179,8 @@ void                lsm_svg_view_apply_merge                (LsmSvgView *view, const char 
*input, const ch
 void           lsm_svg_view_apply_tile                 (LsmSvgView *view, const char *input, const char 
*output, const LsmBox *subregion);
 void           lsm_svg_view_apply_image                (LsmSvgView *view, const char *output, const LsmBox 
*subregion,
                                                         GdkPixbuf *pixbuf, LsmSvgPreserveAspectRatio 
preserve_aspect_ratio);
+void           lsm_svg_view_apply_morphology           (LsmSvgView *view, const char *input, const char 
*output, const LsmBox *subregion,
+                                                        LsmSvgMorphologyOperator op, double radius);
 
 G_END_DECLS
 



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