[gnome-photos] Absorb gegl:shadows-highlights



commit 1fa3d66965355b4f41a0a168ab1db638bb3e6dd6
Author: Debarshi Ray <debarshir gnome org>
Date:   Sat Dec 9 12:25:44 2017 +0100

    Absorb gegl:shadows-highlights
    
    This is a GEGL port of Darktable's shadhi operation. It is being
    carried in-tree until gegl:shadows-highlights is considered stable
    enough to be moved out of the workshop.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=788201

 src/Makefile.am                                    |    8 +
 src/photos-gegl.c                                  |    6 +
 ...hotos-operation-shadows-highlights-correction.c |  457 ++++++++++++++++++++
 ...hotos-operation-shadows-highlights-correction.h |   42 ++
 src/photos-operation-shadows-highlights.c          |  380 ++++++++++++++++
 src/photos-operation-shadows-highlights.h          |   42 ++
 6 files changed, 935 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 543f1c9..b91f6e6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -170,6 +170,10 @@ gnome_photos_SOURCES = \
        photos-operation-png-guess-sizes.h \
        photos-operation-saturation.c \
        photos-operation-saturation.h \
+       photos-operation-shadows-highlights.c \
+       photos-operation-shadows-highlights.h \
+       photos-operation-shadows-highlights-correction.c \
+       photos-operation-shadows-highlights-correction.h \
        photos-operation-svg-multiply.c \
        photos-operation-svg-multiply.h \
        photos-organize-collection-dialog.c \
@@ -340,6 +344,10 @@ gnome_photos_thumbnailer_SOURCES = \
        photos-operation-png-guess-sizes.h \
        photos-operation-saturation.c \
        photos-operation-saturation.h \
+       photos-operation-shadows-highlights.c \
+       photos-operation-shadows-highlights.h \
+       photos-operation-shadows-highlights-correction.c \
+       photos-operation-shadows-highlights-correction.h \
        photos-operation-svg-multiply.c \
        photos-operation-svg-multiply.h \
        photos-pipeline.c \
diff --git a/src/photos-gegl.c b/src/photos-gegl.c
index 8e80028..766c4e6 100644
--- a/src/photos-gegl.c
+++ b/src/photos-gegl.c
@@ -35,6 +35,8 @@
 #include "photos-operation-jpg-guess-sizes.h"
 #include "photos-operation-png-guess-sizes.h"
 #include "photos-operation-saturation.h"
+#include "photos-operation-shadows-highlights.h"
+#include "photos-operation-shadows-highlights-correction.h"
 #include "photos-operation-svg-multiply.h"
 #include "photos-quarks.h"
 
@@ -53,8 +55,10 @@ static const gchar *REQUIRED_GEGL_OPS[] =
 {
   "gegl:buffer-sink",
   "gegl:buffer-source",
+  "gegl:convert-format",
   "gegl:crop",
   "gegl:exposure",
+  "gegl:gaussian-blur",
   "gegl:gray",
   "gegl:load",
   "gegl:noise-reduction",
@@ -564,6 +568,8 @@ photos_gegl_ensure_builtins (void)
       g_type_ensure (PHOTOS_TYPE_OPERATION_JPG_GUESS_SIZES);
       g_type_ensure (PHOTOS_TYPE_OPERATION_PNG_GUESS_SIZES);
       g_type_ensure (PHOTOS_TYPE_OPERATION_SATURATION);
+      g_type_ensure (PHOTOS_TYPE_OPERATION_SHADOWS_HIGHLIGHTS);
+      g_type_ensure (PHOTOS_TYPE_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION);
       g_type_ensure (PHOTOS_TYPE_OPERATION_SVG_MULTIPLY);
 
       g_once_init_leave (&once_init_value, 1);
diff --git a/src/photos-operation-shadows-highlights-correction.c 
b/src/photos-operation-shadows-highlights-correction.c
new file mode 100644
index 0000000..d04172e
--- /dev/null
+++ b/src/photos-operation-shadows-highlights-correction.c
@@ -0,0 +1,457 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ * Copyright © 2017 Thomas Manni
+ * Copyright © 2012 – 2015 Ulrich Pegelow
+ *
+ * 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/>.
+ */
+
+/* Based on code from:
+ *   + Darktable
+ *   + GEGL
+ */
+
+
+#include "config.h"
+
+#include <math.h>
+
+#include <babl/babl.h>
+#include <gegl.h>
+
+#include "photos-operation-shadows-highlights-correction.h"
+
+
+struct _PhotosOperationShadowsHighlightsCorrection
+{
+  GeglOperationPointComposer parent_instance;
+  gdouble compress;
+  gdouble highlights;
+  gdouble highlights_color_correct;
+  gdouble shadows;
+  gdouble shadows_color_correct;
+  gdouble whitepoint;
+};
+
+enum
+{
+  PROP_0,
+  PROP_COMPRESS,
+  PROP_HIGHLIGHTS,
+  PROP_HIGHLIGHTS_COLOR_CORRECT,
+  PROP_SHADOWS,
+  PROP_SHADOWS_COLOR_CORRECT,
+  PROP_WHITEPOINT
+};
+
+
+G_DEFINE_TYPE (PhotosOperationShadowsHighlightsCorrection,
+               photos_operation_shadows_highlights_correction,
+               GEGL_TYPE_OPERATION_POINT_COMPOSER);
+
+
+static GeglRectangle
+photos_operation_shadows_highlights_correction_get_bounding_box (GeglOperation *operation)
+{
+  GeglRectangle *in_bbox;
+  GeglRectangle bbox;
+
+  gegl_rectangle_set (&bbox, 0, 0, 0, 0);
+
+  in_bbox = gegl_operation_source_get_bounding_box (operation, "input");
+  if (in_bbox == NULL)
+    goto out;
+
+  bbox = *in_bbox;
+
+ out:
+  return bbox;
+}
+
+
+static void
+photos_operation_shadows_highlights_correction_prepare (GeglOperation *operation)
+{
+  const Babl *format_cie_l;
+  const Babl *format_cie_laba;
+
+  format_cie_l = babl_format ("CIE L float");
+  format_cie_laba = babl_format ("CIE Lab alpha float");
+
+  gegl_operation_set_format (operation, "aux", format_cie_l);
+  gegl_operation_set_format (operation, "input", format_cie_laba);
+  gegl_operation_set_format (operation, "output", format_cie_laba);
+}
+
+
+static gboolean
+photos_operation_shadows_highlights_correction_process (GeglOperation *operation,
+                                                        void *in_buf,
+                                                        void *aux_buf,
+                                                        void *out_buf,
+                                                        glong n_pixels,
+                                                        const GeglRectangle *roi,
+                                                        gint level)
+{
+  PhotosOperationShadowsHighlightsCorrection *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION 
(operation);
+  gfloat *aux = aux_buf;
+  gfloat *in = in_buf;
+  gfloat *out = out_buf;
+  gfloat compress;
+  gfloat compress_100 = (gfloat) self->compress / 100.0f;
+  gfloat compress_inverted;
+  gfloat doublemax;
+  gfloat halfmax;
+  gfloat highlights;
+  gfloat highlights_100 = (gfloat) self->highlights / 100.0f;
+  gfloat highlights_color_correct;
+  gfloat highlights_color_correct_100 = (gfloat) self->highlights_color_correct / 100.0f;
+  gfloat highlights_color_correct_inverted;
+  gfloat highlights_sign_negated;
+  gfloat lmax = 1.0f;
+  gfloat low_approximation = 0.01f;
+  gfloat shadows;
+  gfloat shadows_100 = (gfloat) self->shadows / 100.0f;
+  gfloat shadows_color_correct;
+  gfloat shadows_color_correct_100 = (gfloat) self->shadows_color_correct / 100.0f;
+  gfloat shadows_color_correct_inverted;
+  gfloat shadows_sign;
+  gfloat whitepoint = 1.0f - (gfloat) self->whitepoint / 100.0f;
+  glong i;
+
+  doublemax = lmax * 2.0f;
+  halfmax = lmax / 2.0f;
+
+  compress = fminf (compress_100, 0.99f);
+  g_return_val_if_fail (compress >= 0.0f, FALSE);
+
+  compress_inverted = 1.0f - compress;
+
+  g_return_val_if_fail (-1.0f <= highlights_100 && highlights_100 <= 1.0f, FALSE);
+  highlights = 2.0f * highlights_100;
+
+  g_return_val_if_fail (0.0f <= highlights_color_correct_100 && highlights_color_correct_100 <= 1.0f, FALSE);
+  highlights_sign_negated = -highlights < 0.0f ? -1.0f : 1.0f;
+  highlights_color_correct = (highlights_color_correct_100 - 0.5f) * highlights_sign_negated + 0.5f;
+  highlights_color_correct_inverted = 1.0f - highlights_color_correct;
+
+  g_return_val_if_fail (-1.0f <= shadows_100 && shadows_100 <= 1.0f, FALSE);
+  shadows = 2.0f * shadows_100;
+
+  g_return_val_if_fail (0.0f <= shadows_color_correct_100 && shadows_color_correct_100 <= 1.0f, FALSE);
+  shadows_sign = shadows < 0.0f ? -1.0f : 1.0f;
+  shadows_color_correct = (shadows_color_correct_100 - 0.5f) * shadows_sign + 0.5f;
+  shadows_color_correct_inverted = 1.0f - shadows_color_correct;
+
+  g_return_val_if_fail (whitepoint >= 0.01f, FALSE);
+
+  for (i = 0; i < n_pixels; i++)
+    {
+      gfloat ta[3];
+      gfloat tb[3];
+      gfloat highlights_xform;
+      gfloat highlights2 = highlights * highlights;
+      gfloat shadows_xform;
+      gfloat shadows2 = shadows * shadows;
+
+      ta[0] = in[0] / 100.0f;
+      ta[1] = in[1] / 128.0f;
+      ta[2] = in[2] / 128.0f;
+
+      tb[0] = (100.0f - aux[0]) / 100.0f;
+      tb[1] = 0.0f;
+      tb[2] = 0.0f;
+
+      ta[0] = ta[0] > 0.0f ? ta[0] / whitepoint : ta[0];
+      tb[0] = tb[0] > 0.0f ? tb[0] / whitepoint : tb[0];
+
+      highlights_xform = CLAMP (1.0f - tb[0] / compress_inverted, 0.0f, 1.0f);
+
+      while (highlights2 > 0.0f)
+        {
+          gfloat chunk;
+          gfloat href;
+          gfloat la;
+          gfloat la_abs;
+          gfloat la_inverted;
+          gfloat la_inverted_abs;
+          gfloat lb;
+          gfloat lmax_la_sign;
+          gfloat lref;
+          gfloat optrans;
+          gfloat optrans_inverted;
+
+          la = ta[0];
+          lmax_la_sign = lmax - la < 0.0f ? -1.0f : 1.0f;
+          lb = (tb[0] - halfmax) * highlights_sign_negated * lmax_la_sign + halfmax;
+
+          la_abs = fabsf (la);
+          lref = copysignf (la_abs > low_approximation ? 1.0f / la_abs : 1.0f / low_approximation, la);
+
+          la_inverted = 1.0f - la;
+          la_inverted_abs = fabsf (1.0f - la);
+          href = copysignf (la_inverted_abs > low_approximation ? 1.0f / la_inverted_abs : 1.0f / 
low_approximation,
+                            la_inverted);
+
+          chunk = fminf (highlights2, 1.0f);
+          optrans = chunk * highlights_xform;
+          optrans_inverted = 1.0f - optrans;
+
+          highlights2 -= 1.0f;
+
+          ta[0] = la * optrans_inverted
+            + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax - lb) : doublemax * la * 
lb) * optrans;
+
+          ta[1] = ta[1] * optrans_inverted
+            + (ta[1] + tb[1]) * (ta[0] * lref * highlights_color_correct_inverted
+                                 + (1.0f - ta[0]) * href * highlights_color_correct) * optrans;
+
+          ta[2] = ta[2] * optrans_inverted
+            + (ta[2] + tb[2]) * (ta[0] * lref * highlights_color_correct_inverted
+                                 + (1.0f - ta[0]) * href * highlights_color_correct) * optrans;
+        }
+
+      shadows_xform = CLAMP (tb[0] / compress_inverted - compress / compress_inverted, 0.0f, 1.0f);
+
+      while (shadows2 > 0.0f)
+        {
+          gfloat chunk;
+          gfloat href;
+          gfloat la;
+          gfloat la_abs;
+          gfloat la_inverted;
+          gfloat la_inverted_abs;
+          gfloat lb;
+          gfloat lmax_la_sign;
+          gfloat lref;
+          gfloat optrans;
+          gfloat optrans_inverted;
+
+          la = ta[0];
+          lmax_la_sign = lmax - la < 0.0f ? -1.0f : 1.0f;
+          lb = (tb[0] - halfmax) * shadows_sign * lmax_la_sign + halfmax;
+
+          la_abs = fabsf (la);
+          lref = copysignf (la_abs > low_approximation ? 1.0f / la_abs : 1.0f / low_approximation, la);
+
+          la_inverted = 1.0f - la;
+          la_inverted_abs = fabsf (1.0f - la);
+          href = copysignf (la_inverted_abs > low_approximation ? 1.0f / la_inverted_abs : 1.0f / 
low_approximation,
+                            la_inverted);
+
+          chunk = fminf (shadows2, 1.0f);
+          optrans = chunk * shadows_xform;
+          optrans_inverted = 1.0f - optrans;
+
+          shadows2 -= 1.0f;
+
+          ta[0] = la * optrans_inverted
+            + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax - lb) : doublemax * la * 
lb) * optrans;
+
+          ta[1] = ta[1] * optrans_inverted
+            + (ta[1] + tb[1]) * (ta[0] * lref * shadows_color_correct
+                                 + (1.0f - ta[0]) * href * shadows_color_correct_inverted) * optrans;
+
+          ta[2] = ta[2] * optrans_inverted
+            + (ta[2] + tb[2]) * (ta[0] * lref * shadows_color_correct
+                                 + (1.0f - ta[0]) * href * shadows_color_correct_inverted) * optrans;
+        }
+
+      out[0] = ta[0] * 100.0f;
+      out[1] = ta[1] * 128.0f;
+      out[2] = ta[2] * 128.0f;
+      out[3] = in[3];
+
+      aux++;
+      in += 4;
+      out += 4;
+    }
+
+  return TRUE;
+}
+
+
+static void
+photos_operation_shadows_highlights_correction_get_property (GObject *object,
+                                                             guint prop_id,
+                                                             GValue *value,
+                                                             GParamSpec *pspec)
+{
+  PhotosOperationShadowsHighlightsCorrection *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_COMPRESS:
+      g_value_set_double (value, self->compress);
+      break;
+
+    case PROP_HIGHLIGHTS:
+      g_value_set_double (value, self->highlights);
+      break;
+
+    case PROP_HIGHLIGHTS_COLOR_CORRECT:
+      g_value_set_double (value, self->highlights_color_correct);
+      break;
+
+    case PROP_SHADOWS:
+      g_value_set_double (value, self->shadows);
+      break;
+
+    case PROP_SHADOWS_COLOR_CORRECT:
+      g_value_set_double (value, self->shadows_color_correct);
+      break;
+
+    case PROP_WHITEPOINT:
+      g_value_set_double (value, self->whitepoint);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+photos_operation_shadows_highlights_correction_set_property (GObject *object,
+                                                             guint prop_id,
+                                                             const GValue *value,
+                                                             GParamSpec *pspec)
+{
+  PhotosOperationShadowsHighlightsCorrection *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_COMPRESS:
+      self->compress = g_value_get_double (value);
+      break;
+
+    case PROP_HIGHLIGHTS:
+      self->highlights = g_value_get_double (value);
+      break;
+
+    case PROP_HIGHLIGHTS_COLOR_CORRECT:
+      self->highlights_color_correct = g_value_get_double (value);
+      break;
+
+    case PROP_SHADOWS:
+      self->shadows = g_value_get_double (value);
+      break;
+
+    case PROP_SHADOWS_COLOR_CORRECT:
+      self->shadows_color_correct = g_value_get_double (value);
+      break;
+
+    case PROP_WHITEPOINT:
+      self->whitepoint = g_value_get_double (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+photos_operation_shadows_highlights_correction_init (PhotosOperationShadowsHighlightsCorrection *self)
+{
+}
+
+
+static void
+photos_operation_shadows_highlights_correction_class_init (PhotosOperationShadowsHighlightsCorrectionClass 
*class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (class);
+  GeglOperationPointComposerClass *point_composer_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (class);
+
+  operation_class->opencl_support = FALSE;
+
+  object_class->get_property = photos_operation_shadows_highlights_correction_get_property;
+  object_class->set_property = photos_operation_shadows_highlights_correction_set_property;
+  operation_class->get_bounding_box = photos_operation_shadows_highlights_correction_get_bounding_box;
+  operation_class->prepare = photos_operation_shadows_highlights_correction_prepare;
+  point_composer_class->process = photos_operation_shadows_highlights_correction_process;
+
+  g_object_class_install_property (object_class,
+                                   PROP_COMPRESS,
+                                   g_param_spec_double ("compress",
+                                                        "Compress",
+                                                        "Compress the effect on shadows/highlights and 
preserve "
+                                                        "midtones",
+                                                        0.0,
+                                                        100.0,
+                                                        50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_HIGHLIGHTS,
+                                   g_param_spec_double ("highlights",
+                                                        "Highlights",
+                                                        "Adjust exposure of highlights",
+                                                        -100.0,
+                                                        100.0,
+                                                        -50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_HIGHLIGHTS_COLOR_CORRECT,
+                                   g_param_spec_double ("highlights-color-correct",
+                                                        "Highlights Color Correct",
+                                                        "Adjust saturation of highlights",
+                                                        0.0,
+                                                        100.0,
+                                                        50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHADOWS,
+                                   g_param_spec_double ("shadows",
+                                                        "Shadows",
+                                                        "Adjust exposure of shadows",
+                                                        -100.0,
+                                                        100.0,
+                                                        50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHADOWS_COLOR_CORRECT,
+                                   g_param_spec_double ("shadows-color-correct",
+                                                        "Shadows Color Correct",
+                                                        "Adjust saturation of shadows",
+                                                        0.0,
+                                                        100.0,
+                                                        100.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_WHITEPOINT,
+                                   g_param_spec_double ("whitepoint",
+                                                        "Whitepoint",
+                                                        "Shift white point",
+                                                        -10.0,
+                                                        10.0,
+                                                        0.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  gegl_operation_class_set_keys (operation_class,
+                                 "name", "photos:shadows-highlights-correction",
+                                 "title", "Shadows Highlights Correction",
+                                 "description", "Adjust shadows and highlights using a blurred auxiliary",
+                                 "categories", "hidden",
+                                 "license", "GPL3+",
+                                 NULL);
+}
diff --git a/src/photos-operation-shadows-highlights-correction.h 
b/src/photos-operation-shadows-highlights-correction.h
new file mode 100644
index 0000000..c280833
--- /dev/null
+++ b/src/photos-operation-shadows-highlights-correction.h
@@ -0,0 +1,42 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ * Copyright © 2017 Thomas Manni
+ * Copyright © 2012 – 2015 Ulrich Pegelow
+ *
+ * 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/>.
+ */
+
+/* Based on code from:
+ *   + Darktable
+ *   + GEGL
+ */
+
+#ifndef PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION_H
+#define PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION_H
+
+#include <gegl-plugin.h>
+
+G_BEGIN_DECLS
+
+#define PHOTOS_TYPE_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION 
(photos_operation_shadows_highlights_correction_get_type ())
+G_DECLARE_FINAL_TYPE (PhotosOperationShadowsHighlightsCorrection,
+                      photos_operation_shadows_highlights_correction,
+                      PHOTOS,
+                      OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION,
+                      GeglOperationPointComposer);
+
+G_END_DECLS
+
+#endif /* PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_CORRECTION_H */
diff --git a/src/photos-operation-shadows-highlights.c b/src/photos-operation-shadows-highlights.c
new file mode 100644
index 0000000..7c51a5e
--- /dev/null
+++ b/src/photos-operation-shadows-highlights.c
@@ -0,0 +1,380 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ * Copyright © 2017 Thomas Manni
+ * Copyright © 2012 – 2015 Ulrich Pegelow
+ *
+ * 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/>.
+ */
+
+/* Based on code from:
+ *   + Darktable
+ *   + GEGL
+ */
+
+
+#include "config.h"
+
+#include <math.h>
+
+#include <babl/babl.h>
+#include <gegl.h>
+
+#include "photos-operation-shadows-highlights.h"
+
+
+struct _PhotosOperationShadowsHighlights
+{
+  GeglOperationMeta parent_instance;
+  const Babl *format_blur;
+  GeglNode *convert_blur;
+  GeglNode *input;
+  GeglNode *output;
+  gfloat compress;
+  gfloat highlights;
+  gfloat highlights_color_correct;
+  gfloat radius;
+  gfloat shadows;
+  gfloat shadows_color_correct;
+  gfloat whitepoint;
+};
+
+enum
+{
+  PROP_0,
+  PROP_COMPRESS,
+  PROP_HIGHLIGHTS,
+  PROP_HIGHLIGHTS_COLOR_CORRECT,
+  PROP_RADIUS,
+  PROP_SHADOWS,
+  PROP_SHADOWS_COLOR_CORRECT,
+  PROP_WHITEPOINT
+};
+
+
+G_DEFINE_TYPE (PhotosOperationShadowsHighlights, photos_operation_shadows_highlights, 
GEGL_TYPE_OPERATION_META);
+
+
+static gboolean
+photos_operation_shadows_highlights_is_nop (PhotosOperationShadowsHighlights *self)
+{
+  return GEGL_FLOAT_EQUAL (self->shadows, 0.0f)
+    && GEGL_FLOAT_EQUAL (self->highlights, 0.0f)
+    && GEGL_FLOAT_EQUAL (self->whitepoint, 0.0f);
+}
+
+
+static void
+photos_operation_shadows_highlights_setup (PhotosOperationShadowsHighlights *self)
+{
+  g_autoptr (GSList) children = NULL;
+  GSList *l;
+  GeglOperation *operation = GEGL_OPERATION (self);
+
+  g_return_if_fail (GEGL_IS_NODE (operation->node));
+  g_return_if_fail (GEGL_IS_NODE (self->input));
+  g_return_if_fail (GEGL_IS_NODE (self->output));
+
+  self->convert_blur = NULL;
+
+  children = gegl_node_get_children (operation->node);
+  for (l = children; l != NULL; l = l->next)
+    {
+      GeglNode *child = GEGL_NODE (l->data);
+
+      if (child == self->input || child == self->output)
+        continue;
+
+      gegl_node_remove_child (operation->node, child);
+    }
+
+  if (photos_operation_shadows_highlights_is_nop (self))
+    {
+      gegl_node_link (self->input, self->output);
+    }
+  else
+    {
+      GeglNode *blur;
+      GeglNode *shadows_highlights;
+
+      blur = gegl_node_new_child (operation->node,
+                                  "operation", "gegl:gaussian-blur",
+                                  "abyss-policy", 1,
+                                  NULL);
+
+      if (self->format_blur == NULL)
+        self->format_blur = babl_format ("YaA float");
+
+      self->convert_blur = gegl_node_new_child (operation->node,
+                                                "operation", "gegl:convert-format",
+                                                "format", self->format_blur,
+                                                NULL);
+
+      shadows_highlights = gegl_node_new_child (operation->node,
+                                                "operation", "photos:shadows-highlights-correction",
+                                                NULL);
+
+      gegl_node_link_many (self->input, self->convert_blur, blur, NULL);
+      gegl_node_connect_to (blur, "output", shadows_highlights, "aux");
+
+      gegl_node_link_many (self->input, shadows_highlights, self->output, NULL);
+
+      gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-x");
+      gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-y");
+
+      gegl_operation_meta_redirect (operation, "compress", shadows_highlights, "compress");
+      gegl_operation_meta_redirect (operation, "highlights", shadows_highlights, "highlights");
+      gegl_operation_meta_redirect (operation, "highlights-color-correct",
+                                    shadows_highlights, "highlights-color-correct");
+      gegl_operation_meta_redirect (operation, "shadows", shadows_highlights, "shadows");
+      gegl_operation_meta_redirect (operation, "shadows-color-correct", shadows_highlights, 
"shadows-color-correct");
+      gegl_operation_meta_redirect (operation, "whitepoint", shadows_highlights, "whitepoint");
+
+      gegl_operation_meta_watch_nodes (operation, blur, self->convert_blur, shadows_highlights, NULL);
+    }
+}
+
+
+static void
+photos_operation_shadows_highlights_attach (GeglOperation *operation)
+{
+  PhotosOperationShadowsHighlights *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS (operation);
+
+  self->input = gegl_node_get_output_proxy (operation->node, "input");
+  self->output = gegl_node_get_output_proxy (operation->node, "output");
+  photos_operation_shadows_highlights_setup (self);
+}
+
+
+static void
+photos_operation_shadows_highlights_prepare (GeglOperation *operation)
+{
+  PhotosOperationShadowsHighlights *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS (operation);
+  const Babl *format_blur = NULL;
+  const Babl *format_input;
+
+  format_input = gegl_operation_get_source_format (operation, "input");
+  if (format_input == NULL)
+    {
+      format_blur = babl_format ("YaA float");
+      goto out;
+    }
+
+  if (babl_format_has_alpha (format_input))
+    format_blur = babl_format ("YaA float");
+  else
+    format_blur = babl_format ("Y float");
+
+ out:
+  g_return_if_fail (format_blur != NULL);
+
+  if (self->format_blur != format_blur)
+    {
+      self->format_blur = format_blur;
+      if (self->convert_blur != NULL)
+        gegl_node_set (self->convert_blur, "format", self->format_blur, NULL);
+    }
+}
+
+
+static void
+photos_operation_shadows_highlights_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec 
*pspec)
+{
+  PhotosOperationShadowsHighlights *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS (object);
+
+  switch (prop_id)
+    {
+    case PROP_COMPRESS:
+      g_value_set_double (value, (gdouble) self->compress);
+      break;
+
+    case PROP_HIGHLIGHTS:
+      g_value_set_double (value, (gdouble) self->highlights);
+      break;
+
+    case PROP_HIGHLIGHTS_COLOR_CORRECT:
+      g_value_set_double (value, (gdouble) self->highlights_color_correct);
+      break;
+
+    case PROP_RADIUS:
+      g_value_set_double (value, (gdouble) self->radius);
+      break;
+
+    case PROP_SHADOWS:
+      g_value_set_double (value, (gdouble) self->shadows);
+      break;
+
+    case PROP_SHADOWS_COLOR_CORRECT:
+      g_value_set_double (value, (gdouble) self->shadows_color_correct);
+      break;
+
+    case PROP_WHITEPOINT:
+      g_value_set_double (value, (gdouble) self->whitepoint);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+photos_operation_shadows_highlights_set_property (GObject *object, guint prop_id, const GValue *value, 
GParamSpec *pspec)
+{
+  PhotosOperationShadowsHighlights *self = PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS (object);
+  gboolean is_nop;
+  gboolean was_nop;
+
+  was_nop = photos_operation_shadows_highlights_is_nop (self);
+
+  switch (prop_id)
+    {
+    case PROP_COMPRESS:
+      self->compress = (gfloat) g_value_get_double (value);
+      break;
+
+    case PROP_HIGHLIGHTS:
+      self->highlights = (gfloat) g_value_get_double (value);
+      break;
+
+    case PROP_HIGHLIGHTS_COLOR_CORRECT:
+      self->highlights_color_correct = (gfloat) g_value_get_double (value);
+      break;
+
+    case PROP_RADIUS:
+      self->radius = (gfloat) g_value_get_double (value);
+      break;
+
+    case PROP_SHADOWS:
+      self->shadows = (gfloat) g_value_get_double (value);
+      break;
+
+    case PROP_SHADOWS_COLOR_CORRECT:
+      self->shadows_color_correct = (gfloat) g_value_get_double (value);
+      break;
+
+    case PROP_WHITEPOINT:
+      self->whitepoint = (gfloat) g_value_get_double (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+
+  is_nop = photos_operation_shadows_highlights_is_nop (self);
+  if (GEGL_OPERATION (self)->node != NULL && is_nop != was_nop)
+    photos_operation_shadows_highlights_setup (self);
+}
+
+
+static void
+photos_operation_shadows_highlights_init (PhotosOperationShadowsHighlights *self)
+{
+}
+
+
+static void
+photos_operation_shadows_highlights_class_init (PhotosOperationShadowsHighlightsClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (class);
+
+  operation_class->opencl_support = FALSE;
+
+  object_class->get_property = photos_operation_shadows_highlights_get_property;
+  object_class->set_property = photos_operation_shadows_highlights_set_property;
+  operation_class->attach = photos_operation_shadows_highlights_attach;
+  operation_class->prepare = photos_operation_shadows_highlights_prepare;
+
+  g_object_class_install_property (object_class,
+                                   PROP_COMPRESS,
+                                   g_param_spec_double ("compress",
+                                                        "Compress",
+                                                        "Compress the effect on shadows/highlights and 
preserve "
+                                                        "midtones",
+                                                        0.0,
+                                                        100.0,
+                                                        50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_HIGHLIGHTS,
+                                   g_param_spec_double ("highlights",
+                                                        "Highlights",
+                                                        "Adjust exposure of highlights",
+                                                        -100.0,
+                                                        100.0,
+                                                        -50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_HIGHLIGHTS_COLOR_CORRECT,
+                                   g_param_spec_double ("highlights-color-correct",
+                                                        "Highlights Color Correct",
+                                                        "Adjust saturation of highlights",
+                                                        0.0,
+                                                        100.0,
+                                                        50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_RADIUS,
+                                   g_param_spec_double ("radius",
+                                                        "Radius",
+                                                        "Spatial extent",
+                                                        0.1,
+                                                        1500.0,
+                                                        100.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHADOWS,
+                                   g_param_spec_double ("shadows",
+                                                        "Shadows",
+                                                        "Adjust exposure of shadows",
+                                                        -100.0,
+                                                        100.0,
+                                                        50.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHADOWS_COLOR_CORRECT,
+                                   g_param_spec_double ("shadows-color-correct",
+                                                        "Shadows Color Correct",
+                                                        "Adjust saturation of shadows",
+                                                        0.0,
+                                                        100.0,
+                                                        100.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_WHITEPOINT,
+                                   g_param_spec_double ("whitepoint",
+                                                        "Whitepoint",
+                                                        "Shift white point",
+                                                        -10.0,
+                                                        10.0,
+                                                        0.0,
+                                                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  gegl_operation_class_set_keys (operation_class,
+                                 "name", "photos:shadows-highlights",
+                                 "title", "Shadows Highlights",
+                                 "description", "Adjust shadows and highlights",
+                                 "categories", "light",
+                                 "license", "GPL3+",
+                                 NULL);
+}
diff --git a/src/photos-operation-shadows-highlights.h b/src/photos-operation-shadows-highlights.h
new file mode 100644
index 0000000..65d93f5
--- /dev/null
+++ b/src/photos-operation-shadows-highlights.h
@@ -0,0 +1,42 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ * Copyright © 2017 Thomas Manni
+ * Copyright © 2012 – 2015 Ulrich Pegelow
+ *
+ * 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/>.
+ */
+
+/* Based on code from:
+ *   + Darktable
+ *   + GEGL
+ */
+
+#ifndef PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_H
+#define PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_H
+
+#include <gegl-plugin.h>
+
+G_BEGIN_DECLS
+
+#define PHOTOS_TYPE_OPERATION_SHADOWS_HIGHLIGHTS (photos_operation_shadows_highlights_get_type ())
+G_DECLARE_FINAL_TYPE (PhotosOperationShadowsHighlights,
+                      photos_operation_shadows_highlights,
+                      PHOTOS,
+                      OPERATION_SHADOWS_HIGHLIGHTS,
+                      GeglOperationMeta);
+
+G_END_DECLS
+
+#endif /* PHOTOS_OPERATION_SHADOWS_HIGHLIGHTS_H */



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