[gegl] spherize: add new op to workshop
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] spherize: add new op to workshop
- Date: Sun, 1 Oct 2017 15:00:28 +0000 (UTC)
commit 71ae8c663715d39427a47020000a4bf67694a652
Author: Ell <ell_se yahoo com>
Date: Sun Oct 1 10:53:29 2017 -0400
spherize: add new op to workshop
A map/distort op, that projects the input image atop a spherical
cap. Similar to the Photoshop filter of the same name.
operations/workshop/Makefile.am | 3 +-
operations/workshop/spherize.c | 304 +++++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
3 files changed, 307 insertions(+), 1 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 79cb947..6f2ba29 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -24,4 +24,5 @@ op_LTLIBRARIES = \
rawbayer-load.la \
segment-kmeans.la \
shadows-highlights.la \
- shadows-highlights-correction.la
+ shadows-highlights-correction.la \
+ spherize.la
diff --git a/operations/workshop/spherize.c b/operations/workshop/spherize.c
new file mode 100644
index 0000000..dadb599
--- /dev/null
+++ b/operations/workshop/spherize.c
@@ -0,0 +1,304 @@
+/* This file is an image processing operation for GEGL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2017 Ell
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+enum_start (gegl_spherize_mode)
+ enum_value (GEGL_SPHERIZE_MODE_RADIAL, "radial", N_("Radial"))
+ enum_value (GEGL_SPHERIZE_MODE_HORIZONTAL, "horizontal", N_("Horizontal"))
+ enum_value (GEGL_SPHERIZE_MODE_VERTICAL, "vertical", N_("Vertical"))
+enum_end (GeglSpherizeMode)
+
+property_enum (mode, _("Mode"),
+ GeglSpherizeMode, gegl_spherize_mode,
+ GEGL_SPHERIZE_MODE_RADIAL)
+ description (_("Displacement mode"))
+
+property_double (angle_of_view, _("Angle of view"), 90.0)
+ description (_("Camera angle of view"))
+ value_range (0.0, 180.0)
+ ui_meta ("unit", "degree")
+
+property_double (amount, _("Amount"), 1.0)
+ description (_("Spherical cap angle, as a fraction of the co-angle of view"))
+ value_range (-1.0, 1.0)
+
+property_enum (sampler_type, _("Resampling method"),
+ GeglSamplerType, gegl_sampler_type, GEGL_SAMPLER_LINEAR)
+ description(_("Mathematical method for reconstructing pixel values"))
+
+property_boolean (keep_surroundings, _("Keep original surroundings"), TRUE)
+ description(_("Keep image unchanged outside the sphewre"))
+ ui_meta ("visible", "mode {radial}")
+
+property_color (background_color, _("Background color"), "none")
+ ui_meta ("role", "color-secondary")
+ ui_meta ("visible", "$keep_surroundings.visible")
+ ui_meta ("sensitive", "! keep_surroundings")
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_NAME spherize
+#define GEGL_OP_C_SOURCE spherize.c
+
+#include "gegl-op.h"
+#include <math.h>
+
+static gboolean
+is_identity (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+
+ return o->angle_of_view < 1e-10 || fabs (o->amount) < 1e-10;
+}
+
+static gboolean
+is_nop (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+
+ return is_identity (operation) && ! (o->mode == GEGL_SPHERIZE_MODE_RADIAL &&
+ ! o->keep_surroundings);
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+ gegl_operation_set_format (operation, "input", babl_format ("RGBA float"));
+ gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
+{
+ GeglRectangle result = *roi;
+
+ if (! is_identity (operation))
+ {
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
+
+ if (in_rect)
+ {
+ switch (o->mode)
+ {
+ case GEGL_SPHERIZE_MODE_RADIAL:
+ result = *in_rect;
+ break;
+
+ case GEGL_SPHERIZE_MODE_HORIZONTAL:
+ result.x = in_rect->x;
+ result.width = in_rect->width;
+ break;
+
+ case GEGL_SPHERIZE_MODE_VERTICAL:
+ result.y = in_rect->y;
+ result.height = in_rect->height;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+static gboolean
+parent_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+
+ if (is_nop (operation))
+ {
+ GObject *input;
+
+ input = gegl_operation_context_get_object (context, "input");
+
+ gegl_operation_context_set_object (context, "output", input);
+
+ return TRUE;
+ }
+
+ return GEGL_OPERATION_CLASS (gegl_op_parent_class)->process (operation,
+ context,
+ output_prop,
+ result, level);
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = babl_format ("RGBA float");
+ GeglSampler *sampler;
+ GeglBufferIterator *iter;
+ gfloat bg_color[4];
+ const GeglRectangle *in_extent;
+ gdouble cx, cy;
+ gdouble dx = 0.0, dy = 0.0;
+ gdouble coangle_of_view_2;
+ gdouble cap_angle;
+ gdouble focal_length;
+ gdouble cap_radius;
+ gdouble cap_height;
+ gdouble f, f2, r2, f_h, f_h2, f_hf, sgn;
+ gboolean is_id;
+ gint i, j;
+
+ sampler = gegl_buffer_sampler_new_at_level (input, format,
+ o->sampler_type, level);
+
+ iter = gegl_buffer_iterator_new (output, roi, level, format,
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
+
+ gegl_buffer_iterator_add (iter, input, roi, level, format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+ gegl_color_get_pixel (o->background_color, format, bg_color);
+
+ in_extent = gegl_operation_source_get_bounding_box (operation, "input");
+
+ cx = in_extent->x + in_extent->width / 2.0;
+ cy = in_extent->y + in_extent->height / 2.0;
+
+ if (o->mode == GEGL_SPHERIZE_MODE_RADIAL ||
+ o->mode == GEGL_SPHERIZE_MODE_HORIZONTAL)
+ {
+ dx = 2.0 / in_extent->width;
+ }
+ if (o->mode == GEGL_SPHERIZE_MODE_RADIAL ||
+ o->mode == GEGL_SPHERIZE_MODE_VERTICAL)
+ {
+ dy = 2.0 / in_extent->height;
+ }
+
+ coangle_of_view_2 = MAX (180.0 - o->angle_of_view, 0.01) * G_PI / 360.0;
+ cap_angle = fabs (o->amount) * coangle_of_view_2;
+ focal_length = tan (coangle_of_view_2);
+ cap_radius = 1.0 / sin (cap_angle);
+ cap_height = cap_radius * cos (cap_angle);
+
+ f = focal_length;
+ f2 = focal_length * focal_length;
+ r2 = cap_radius * cap_radius;
+ f_h = o->amount >= 0.0 ? focal_length + cap_height :
+ focal_length - cap_height;
+ f_h2 = f_h * f_h;
+ f_hf = f_h * f;
+ sgn = o->amount >= 0.0 ? -1.0 : +1.0;
+
+ is_id = is_identity (operation);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *out_pixel = iter->data[0];
+ const gfloat *in_pixel = iter->data[1];
+ gfloat x, y;
+
+ y = dy * (iter->roi->y - cy);
+
+ for (j = iter->roi->y; j < iter->roi->y + iter->roi->height; j++, y += dy)
+ {
+ x = dx * (iter->roi->x - cx);
+
+ for (i = iter->roi->x; i < iter->roi->x + iter->roi->width; i++, x += dx)
+ {
+ gfloat d2;
+
+ d2 = x * x + y * y;
+
+ if (! is_id && d2 <= 1.0)
+ {
+ gdouble d = sqrt (d2);
+ gdouble d2_f2 = d2 + f2;
+ gdouble src_d;
+ gdouble src_x, src_y;
+
+ src_d = (f_hf + sgn * sqrt (d2_f2 * r2 - f_h2 * d2)) * d / d2_f2;
+
+ src_x = i;
+ src_y = j;
+
+ if (d)
+ {
+ if (dx) src_x = cx + src_d * x / (dx * d);
+ if (dy) src_y = cy + src_d * y / (dy * d);
+ }
+
+ gegl_sampler_get (sampler, src_x, src_y,
+ NULL, out_pixel, GEGL_ABYSS_NONE);
+ }
+ else
+ {
+ if (d2 <= 1.0 || o->keep_surroundings)
+ memcpy (out_pixel, in_pixel, sizeof (gfloat) * 4);
+ else
+ memcpy (out_pixel, bg_color, sizeof (gfloat) * 4);
+ }
+
+ out_pixel += 4;
+ in_pixel += 4;
+ }
+ }
+ }
+
+ g_object_unref (sampler);
+
+ return TRUE;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+ GeglOperationClass *operation_class;
+ GeglOperationFilterClass *filter_class;
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+ filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
+
+ operation_class->prepare = prepare;
+ operation_class->get_required_for_output = get_required_for_output;
+ operation_class->process = parent_process;
+
+ filter_class->process = process;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:spherize",
+ "title", _("Spherize"),
+ "categories", "distort:map",
+ "position-dependent", "true",
+ "license", "GPL3+",
+ "description", _("Project image atop a spherical cap"),
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c470cdc..88ffe2f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -255,3 +255,4 @@ operations/workshop/rawbayer-load.c
operations/workshop/segment-kmeans.c
operations/workshop/shadows-highlights.c
operations/workshop/shadows-highlights-correction.c
+operations/workshop/spherize.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]