[gimp] app: improve gimp:mask-components



commit ee156b8fd63aacbc2b72b90e863aa4a929e52d75
Author: Ell <ell_se yahoo com>
Date:   Sat Feb 16 08:19:06 2019 -0500

    app: improve gimp:mask-components
    
    Add specialized versions of gimp:mask-components for 8-, 16-, and
    32-bpc formats, to improve efficiency, and to preserve the contents
    of masked-out components exactly.
    
    Provide public functions for format-selection and processing, which
    we'll use in the painting code, instead of reimplementing component
    masking.

 app/operations/gimpoperationmaskcomponents.cc | 286 +++++++++++++++++++++++---
 app/operations/gimpoperationmaskcomponents.h  |  12 +-
 2 files changed, 264 insertions(+), 34 deletions(-)
---
diff --git a/app/operations/gimpoperationmaskcomponents.cc b/app/operations/gimpoperationmaskcomponents.cc
index 53f564d9bd..459b41092c 100644
--- a/app/operations/gimpoperationmaskcomponents.cc
+++ b/app/operations/gimpoperationmaskcomponents.cc
@@ -146,28 +146,177 @@ gimp_operation_mask_components_set_property (GObject      *object,
     }
 }
 
+template <class T>
+struct ProcessGeneric
+{
+  static void
+  process (gconstpointer     in_buf,
+           gconstpointer     aux_buf,
+           gpointer          out_buf,
+           gint              n,
+           GimpComponentMask mask)
+  {
+    T    *out = (T *) out_buf;
+    gint  i;
+    gint  c;
+
+    if (aux_buf)
+      {
+        const T *in[4];
+
+        for (c = 0; c < 4; c++)
+          {
+            if (mask & (1 << c))
+              in[c] = (const T *) aux_buf + c;
+            else
+              in[c] = (const T *) in_buf  + c;
+          }
+
+        for (i = 0; i < n; i++)
+          {
+            for (c = 0; c < 4; c++)
+              {
+                out[c] = *in[c];
+
+                in[c] += 4;
+              }
+
+            out += 4;
+          }
+      }
+    else
+      {
+        const T *in = (const T*) in_buf;
+
+        for (i = 0; i < n; i++)
+          {
+            for (c = 0; c < 4; c++)
+              {
+                if (mask & (1 << c))
+                  out[c] = 0;
+                else
+                  out[c] = in[c];
+              }
+
+            in  += 4;
+            out += 4;
+          }
+      }
+  }
+};
+
+template <class T>
+struct Process : ProcessGeneric<T>
+{
+};
+
+template <>
+struct Process<guint8>
+{
+  static void
+  process (gconstpointer     in_buf,
+           gconstpointer     aux_buf,
+           gpointer          out_buf,
+           gint              n,
+           GimpComponentMask mask)
+  {
+    const guint32 *in;
+    guint32       *out;
+    guint32        in_mask = 0;
+    gint           i;
+    gint           c;
+
+    if (((guintptr) in_buf | (guintptr) aux_buf | (guintptr) out_buf) % 4)
+      {
+        ProcessGeneric<guint8>::process (in_buf, aux_buf, out_buf, n, mask);
+
+        return;
+      }
+
+    in  = (const guint32 *) in_buf;
+    out = (guint32       *) out_buf;
+
+    for (c = 0; c < 4; c++)
+      {
+        if (! (mask & (1 << c)))
+          in_mask |= 0xff << (8 * c);
+      }
+
+    if (aux_buf)
+      {
+        const guint32 *aux      = (const guint32 *) aux_buf;
+        guint32        aux_mask = ~in_mask;
+
+        for (i = 0; i < n; i++)
+          {
+            *out = (*in & in_mask) | (*aux & aux_mask);
+
+            in++;
+            aux++;
+            out++;
+          }
+      }
+    else
+      {
+        for (i = 0; i < n; i++)
+          {
+            *out = *in & in_mask;
+
+            in++;
+            out++;
+          }
+      }
+  }
+};
+
+template <class T>
+static gboolean
+gimp_operation_mask_components_process (GimpOperationMaskComponents *self,
+                                        void                        *in_buf,
+                                        void                        *aux_buf,
+                                        void                        *out_buf,
+                                        glong                        samples,
+                                        const GeglRectangle         *roi,
+                                        gint                         level)
+{
+  Process<T>::process (in_buf, aux_buf, out_buf, samples, self->mask);
+
+  return TRUE;
+}
+
 static void
 gimp_operation_mask_components_prepare (GeglOperation *operation)
 {
-  const Babl *format = gegl_operation_get_source_format (operation, "input");
-
-  if (format)
-    {
-      const Babl *model = babl_format_get_model (format);
+  GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (operation);
+  const Babl                  *format;
 
-      if (! strcmp (babl_get_name (model), "R'G'B'A"))
-        format = babl_format_with_space ("R'G'B'A float", format);
-      else
-        format = babl_format_with_space ("RGBA float", format);
-    }
-  else
-    {
-      format = babl_format ("RGBA float");
-    }
+  format = gimp_operation_mask_components_get_format (
+    gegl_operation_get_source_format (operation, "input"));
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
   gegl_operation_set_format (operation, "output", format);
+
+  switch (babl_format_get_bytes_per_pixel (format))
+    {
+    case 4:
+      self->process = (gpointer)
+                        gimp_operation_mask_components_process<guint8>;
+      break;
+
+    case 8:
+      self->process = (gpointer)
+                        gimp_operation_mask_components_process<guint16>;
+      break;
+
+    case 16:
+      self->process = (gpointer)
+                        gimp_operation_mask_components_process<guint32>;
+      break;
+
+    default:
+      g_return_if_reached ();
+    }
 }
 
 static gboolean
@@ -210,30 +359,101 @@ gimp_operation_mask_components_process (GeglOperation       *operation,
                                         const GeglRectangle *roi,
                                         gint                 level)
 {
-  GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (operation);
-  const gfloat                *src  = (const gfloat *) in_buf;
-  const gfloat                *aux  = (const gfloat *) aux_buf;
-  gfloat                      *dest = (gfloat       *) out_buf;
-  GimpComponentMask            mask = self->mask;
-  static const gfloat          nothing[] = { 0.0, 0.0, 0.0, 1.0 };
+  typedef gboolean (* ProcessFunc) (GimpOperationMaskComponents *self,
+                                    void                        *in_buf,
+                                    void                        *aux_buf,
+                                    void                        *out_buf,
+                                    glong                        samples,
+                                    const GeglRectangle         *roi,
+                                    gint                         level);
+
+  GimpOperationMaskComponents *self = (GimpOperationMaskComponents *) operation;
+
+  return ((ProcessFunc) self->process) (self,
+                                        in_buf, aux_buf, out_buf, samples,
+                                        roi, level);
+}
 
-  if (! aux)
-    aux = (gfloat *) nothing;
+const Babl *
+gimp_operation_mask_components_get_format (const Babl *input_format)
+{
+  const Babl *format = NULL;
 
-  while (samples--)
+  if (input_format)
     {
-      dest[RED]   = (mask & GIMP_COMPONENT_MASK_RED)   ? aux[RED]   : src[RED];
-      dest[GREEN] = (mask & GIMP_COMPONENT_MASK_GREEN) ? aux[GREEN] : src[GREEN];
-      dest[BLUE]  = (mask & GIMP_COMPONENT_MASK_BLUE)  ? aux[BLUE]  : src[BLUE];
-      dest[ALPHA] = (mask & GIMP_COMPONENT_MASK_ALPHA) ? aux[ALPHA] : src[ALPHA];
+      const Babl  *model      = babl_format_get_model (input_format);
+      const gchar *model_name = babl_get_name (model);
+      const Babl  *type       = babl_format_get_type (input_format, 0);
+      const gchar *type_name  = babl_get_name (type);
+
+      if (! strcmp (model_name, "Y")   ||
+          ! strcmp (model_name, "YA")  ||
+          ! strcmp (model_name, "RGB") ||
+          ! strcmp (model_name, "RGBA"))
+        {
+          if (! strcmp (type_name, "u8"))
+            format = babl_format ("RGBA u8");
+          else if (! strcmp (type_name, "u16"))
+            format = babl_format ("RGBA u16");
+          else if (! strcmp (type_name, "u32"))
+            format = babl_format ("RGBA u32");
+          else if (! strcmp (type_name, "float"))
+            format = babl_format ("RGBA float");
+        }
+      else if (! strcmp (model_name, "Y'")      ||
+               ! strcmp (model_name, "Y'A")     ||
+               ! strcmp (model_name, "R'G'B'")  ||
+               ! strcmp (model_name, "R'G'B'A") ||
+               babl_format_is_palette (input_format))
+        {
+          if (! strcmp (type_name, "u8"))
+            format = babl_format ("R'G'B'A u8");
+          else if (! strcmp (type_name, "u16"))
+            format = babl_format ("R'G'B'A u16");
+          else if (! strcmp (type_name, "u32"))
+            format = babl_format ("R'G'B'A u32");
+          else if (! strcmp (type_name, "float"))
+            format = babl_format ("R'G'B'A float");
+        }
+    }
 
-      src += 4;
+  if (! format)
+    format = babl_format ("RGBA float");
 
-      if (aux_buf)
-        aux  += 4;
+  if (input_format)
+    return babl_format_with_space ((const gchar *) format, input_format);
+  else
+    return format;
+}
 
-      dest += 4;
-    }
+void
+gimp_operation_mask_components_process (const Babl        *format,
+                                        gconstpointer      in,
+                                        gconstpointer      aux,
+                                        gpointer           out,
+                                        gint               n,
+                                        GimpComponentMask  mask)
+{
+  g_return_if_fail (format != NULL);
+  g_return_if_fail (in != NULL);
+  g_return_if_fail (out != NULL);
+  g_return_if_fail (n >= 0);
 
-  return TRUE;
+  switch (babl_format_get_bytes_per_pixel (format))
+    {
+    case 4:
+      Process<guint8>::process (in, aux, out, n, mask);
+      break;
+
+    case 8:
+      Process<guint16>::process (in, aux, out, n, mask);
+      break;
+
+    case 16:
+      Process<guint32>::process (in, aux, out, n, mask);
+      break;
+
+    default:
+      g_return_if_reached ();
+    }
 }
diff --git a/app/operations/gimpoperationmaskcomponents.h b/app/operations/gimpoperationmaskcomponents.h
index d4999c8c74..e04a21b948 100644
--- a/app/operations/gimpoperationmaskcomponents.h
+++ b/app/operations/gimpoperationmaskcomponents.h
@@ -40,6 +40,7 @@ struct _GimpOperationMaskComponents
   GeglOperationPointComposer  parent_instance;
 
   GimpComponentMask           mask;
+  gpointer                    process;
 };
 
 struct _GimpOperationMaskComponentsClass
@@ -48,7 +49,16 @@ struct _GimpOperationMaskComponentsClass
 };
 
 
-GType   gimp_operation_mask_components_get_type (void) G_GNUC_CONST;
+GType        gimp_operation_mask_components_get_type   (void) G_GNUC_CONST;
+
+const Babl * gimp_operation_mask_components_get_format (const Babl        *input_format);
+
+void         gimp_operation_mask_components_process    (const Babl        *format,
+                                                        gconstpointer      in,
+                                                        gconstpointer      aux,
+                                                        gpointer           out,
+                                                        gint               n,
+                                                        GimpComponentMask  mask);
 
 
 #endif /* __GIMP_OPERATION_MASK_COMPONENTS_H__ */


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