Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gimp-gegl-utils.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimp-gegl-utils.h
 * Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
 *
 * 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 <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <string.h>

#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <gegl-plugin.h>

#include "libgimpcolor/gimpcolor.h"

#include "gimp-gegl-types.h"

#include "core/gimperror.h"
#include "core/gimppattern.h"
#include "core/gimpprogress.h"

#include "gimp-babl.h"
#include "gimp-gegl-loops.h"
#include "gimp-gegl-utils.h"


/*  local function prototypes  */

static gboolean   gimp_gegl_op_blacklisted    (const gchar        *name,
                                               const gchar        *categories,
                                               gboolean            block_gimp_ops,
                                               GError            **error);
static GList    * gimp_gegl_get_op_subclasses (GType               type,
                                               GList              *classes,
                                               gboolean            block_gimp_ops);
static gint       gimp_gegl_compare_op_names  (GeglOperationClass *a,
                                               GeglOperationClass *b);


/* Comes from gegl/operation/gegl-operations.h which is not public. */
GType gegl_operation_gtype_from_name (const gchar *name);


/*  public functions  */

GList *
gimp_gegl_get_op_classes (gboolean block_gimp_ops)
{
  GList *operations;

  operations = gimp_gegl_get_op_subclasses (GEGL_TYPE_OPERATION, NULL, block_gimp_ops);

  operations = g_list_sort (operations,
                            (GCompareFunc)
                            gimp_gegl_compare_op_names);

  return operations;
}

gboolean
gimp_gegl_op_nde_allowed (const gchar  *name,
                          GError      **error)
{
  GType               op_type;
  GeglOperationClass *klass;
  const gchar        *categories;

  g_return_val_if_fail (error != NULL && *error == NULL, FALSE);

  if (name == NULL || strlen (name) == 0)
    {
      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, "the filter has no name.");
      return FALSE;
    }
  else if (! gegl_has_operation (name))
    {
      g_set_error (error, GIMP_ERROR, GIMP_FAILED, "the filter \"%s\" is not installed.", name);
      return FALSE;
    }

  op_type    = gegl_operation_gtype_from_name (name);
  klass      = GEGL_OPERATION_CLASS (g_type_class_ref (op_type));
  categories = gegl_operation_class_get_key (klass, "categories");

  return ! gimp_gegl_op_blacklisted (name, categories, FALSE, error);
}

GType
gimp_gegl_get_op_enum_type (const gchar *operation,
                            const gchar *property)
{
  GeglNode   *node;
  GObject    *op;
  GParamSpec *pspec;

  g_return_val_if_fail (operation != NULL, G_TYPE_NONE);
  g_return_val_if_fail (property != NULL, G_TYPE_NONE);

  node = g_object_new (GEGL_TYPE_NODE,
                       "operation", operation,
                       NULL);
  g_object_get (node, "gegl-operation", &op, NULL);
  g_object_unref (node);

  g_return_val_if_fail (op != NULL, G_TYPE_NONE);

  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (op), property);

  g_return_val_if_fail (G_IS_PARAM_SPEC_ENUM (pspec), G_TYPE_NONE);

  g_object_unref (op);

  return G_TYPE_FROM_CLASS (G_PARAM_SPEC_ENUM (pspec)->enum_class);
}

static void
gimp_gegl_progress_callback (GObject      *object,
                             gdouble       value,
                             GimpProgress *progress)
{
  if (value == 0.0)
    {
      const gchar *text = g_object_get_data (object, "gimp-progress-text");

      if (gimp_progress_is_active (progress))
        gimp_progress_set_text (progress, "%s", text);
      else
        gimp_progress_start (progress, FALSE, "%s", text);
    }
  else
    {
      gimp_progress_set_value (progress, value);

      if (value == 1.0)
        gimp_progress_end (progress);
    }
}

void
gimp_gegl_progress_connect (GeglNode     *node,
                            GimpProgress *progress,
                            const gchar  *text)
{
  g_return_if_fail (GEGL_IS_NODE (node));
  g_return_if_fail (GIMP_IS_PROGRESS (progress));
  g_return_if_fail (text != NULL);

  g_signal_connect_object (node, "progress",
                           G_CALLBACK (gimp_gegl_progress_callback),
                           progress, 0);

  g_object_set_data_full (G_OBJECT (node),
                          "gimp-progress-text", g_strdup (text),
                          (GDestroyNotify) g_free);
}

void
gimp_gegl_progress_disconnect (GeglNode     *node,
                               GimpProgress *progress)
{
  g_return_if_fail (GEGL_IS_NODE (node));
  g_return_if_fail (GIMP_IS_PROGRESS (progress));

  g_signal_handlers_disconnect_by_func (node,
                                        gimp_gegl_progress_callback,
                                        progress);
}

gboolean
gimp_gegl_node_is_source_operation (GeglNode *node)
{
  GeglOperation *operation;

  g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);

  operation = gegl_node_get_gegl_operation (node);

  if (! operation)
    return FALSE;

  return GEGL_IS_OPERATION_SOURCE (operation);
}

gboolean
gimp_gegl_node_is_point_operation (GeglNode *node)
{
  GeglOperation *operation;

  g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);

  operation = gegl_node_get_gegl_operation (node);

  if (! operation)
    return FALSE;

  return GEGL_IS_OPERATION_POINT_RENDER    (operation) ||
         GEGL_IS_OPERATION_POINT_FILTER    (operation) ||
         GEGL_IS_OPERATION_POINT_COMPOSER  (operation) ||
         GEGL_IS_OPERATION_POINT_COMPOSER3 (operation);
}

gboolean
gimp_gegl_node_is_area_filter_operation (GeglNode *node)
{
  GeglOperation *operation;

  g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);

  operation = gegl_node_get_gegl_operation (node);

  if (! operation)
    return FALSE;

  return GEGL_IS_OPERATION_AREA_FILTER (operation) ||
         /* be conservative and return TRUE for meta ops, since they may
          * involve an area op
          */

         GEGL_IS_OPERATION_META (operation);
}

const gchar *
gimp_gegl_node_get_key (GeglNode    *node,
                        const gchar *key)
{
  const gchar *operation_name;

  g_return_val_if_fail (GEGL_IS_NODE (node), NULL);

  operation_name = gegl_node_get_operation (node);

  if (operation_name)
    return gegl_operation_get_key (operation_name, key);
  else
    return NULL;
}

gboolean
gimp_gegl_node_has_key (GeglNode    *node,
                        const gchar *key)
{
  return gimp_gegl_node_get_key (node, key) != NULL;
}

const Babl *
gimp_gegl_node_get_format (GeglNode    *node,
                           const gchar *pad_name)
{
  GeglOperation *op;
  const Babl    *format = NULL;

  g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
  g_return_val_if_fail (pad_name != NULL, NULL);

  g_object_get (node, "gegl-operation", &op, NULL);

  if (op)
    {
      format = gegl_operation_get_format (op, pad_name);

      g_object_unref (op);
    }

  if (! format)
    format = babl_format ("RGBA float");

  return format;
}

void
gimp_gegl_node_set_underlying_operation (GeglNode *node,
                                         GeglNode *operation)
{
  g_return_if_fail (GEGL_IS_NODE (node));
  g_return_if_fail (operation == NULL || GEGL_IS_NODE (operation));

  g_object_set_data (G_OBJECT (node),
                     "gimp-gegl-node-underlying-operation", operation);
}

GeglNode *
gimp_gegl_node_get_underlying_operation (GeglNode *node)
{
  GeglNode *operation;

  g_return_val_if_fail (GEGL_IS_NODE (node), NULL);

  operation = g_object_get_data (G_OBJECT (node),
                                 "gimp-gegl-node-underlying-operation");

  if (operation)
    return gimp_gegl_node_get_underlying_operation (operation);
  else
    return node;
}

gboolean
gimp_gegl_param_spec_has_key (GParamSpec  *pspec,
                              const gchar *key,
                              const gchar *value)
{
  const gchar *v = gegl_param_spec_get_property_key (pspec, key);

  if (v && ! strcmp (v, value))
    return TRUE;

  return FALSE;
}

GeglBuffer *
gimp_gegl_buffer_dup (GeglBuffer *buffer)
{
  GeglBuffer          *new_buffer;
  const GeglRectangle *extent;
  const GeglRectangle *abyss;
  GeglRectangle        rect;
  gint                 shift_x;
  gint                 shift_y;
  gint                 tile_width;
  gint                 tile_height;

  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);

  extent = gegl_buffer_get_extent (buffer);
  abyss  = gegl_buffer_get_abyss  (buffer);

  g_object_get (buffer,
                "shift-x",     &shift_x,
                "shift-y",     &shift_y,
                "tile-width",  &tile_width,
                "tile-height", &tile_height,
                NULL);

  new_buffer = g_object_new (GEGL_TYPE_BUFFER,
                             "format",       gegl_buffer_get_format (buffer),
                             "x",            extent->x,
                             "y",            extent->y,
                             "width",        extent->width,
                             "height",       extent->height,
                             "abyss-x",      abyss->x,
                             "abyss-y",      abyss->y,
                             "abyss-width",  abyss->width,
                             "abyss-height", abyss->height,
                             "shift-x",      shift_x,
                             "shift-y",      shift_y,
                             "tile-width",   tile_width,
                             "tile-height",  tile_height,
                             NULL);

  gegl_rectangle_align_to_buffer (&rect, extent, buffer,
                                  GEGL_RECTANGLE_ALIGNMENT_SUPERSET);

  gimp_gegl_buffer_copy (buffer, &rect, GEGL_ABYSS_NONE,
                         new_buffer, &rect);

  return new_buffer;
}

GeglBuffer *
gimp_gegl_buffer_resize (GeglBuffer   *buffer,
                         gint          new_width,
                         gint          new_height,
                         gint          offset_x,
                         gint          offset_y,
                         GeglColor    *color,
                         GimpPattern  *pattern,
                         gint          pattern_offset_x,
                         gint          pattern_offset_y)
{
  GeglBuffer          *new_buffer;
  gboolean             intersect;
  GeglRectangle        copy_rect;
  const GeglRectangle *extent;
  const Babl          *format;

  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);

  extent     = gegl_buffer_get_extent (buffer);
  format     = gegl_buffer_get_format (buffer);
  new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height),
                                format);

  intersect = gegl_rectangle_intersect (©_rect,
                                        GEGL_RECTANGLE (0, 0, extent->width,
                                                        extent->height),
                                        GEGL_RECTANGLE (offset_x, offset_y,
                                                        new_width, new_height));

  if (! intersect                   ||
      copy_rect.width  != new_width ||
      copy_rect.height != new_height)
    {
      /*  Clear the new buffer if needed and color/pattern is given */
      if (pattern)
        {
          GeglBuffer       *src_buffer;
          GeglBuffer       *dest_buffer;
          GimpColorProfile *src_profile;
          GimpColorProfile *dest_profile;

          src_buffer = gimp_pattern_create_buffer (pattern);

          src_profile  = gimp_babl_format_get_color_profile (
                           gegl_buffer_get_format (src_buffer));
          dest_profile = gimp_babl_format_get_color_profile (
                           gegl_buffer_get_format (new_buffer));

          if (gimp_color_transform_can_gegl_copy (src_profile, dest_profile))
            {
              dest_buffer = g_object_ref (src_buffer);
            }
          else
            {
              dest_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer),
                                             gegl_buffer_get_format (new_buffer));

              gimp_gegl_convert_color_profile (src_buffer,  NULL, src_profile,
                                               dest_buffer, NULL, dest_profile,
                                               GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
                                               TRUE, NULL);
            }

          g_object_unref (src_profile);
          g_object_unref (dest_profile);

          gegl_buffer_set_pattern (new_buffer, NULL, dest_buffer,
                                   pattern_offset_x, pattern_offset_y);

          g_object_unref (src_buffer);
          g_object_unref (dest_buffer);
        }
      else if (color)
        {
          gegl_buffer_set_color (new_buffer, NULL, color);
        }
    }

  if (intersect && copy_rect.width && copy_rect.height)
    {
      /*  Copy the pixels in the intersection  */
      gimp_gegl_buffer_copy (buffer, ©_rect, GEGL_ABYSS_NONE, new_buffer,
                             GEGL_RECTANGLE (copy_rect.x - offset_x,
                                             copy_rect.y - offset_y, 0, 0));
    }

  return new_buffer;
}

gboolean
gimp_gegl_buffer_set_extent (GeglBuffer          *buffer,
                             const GeglRectangle *extent)
{
  GeglRectangle aligned_old_extent;
  GeglRectangle aligned_extent;
  GeglRectangle old_extent_rem;
  GeglRectangle diff_rects[4];
  gint          n_diff_rects;
  gint          i;

  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE);
  g_return_val_if_fail (extent != NULL, FALSE);

  gegl_rectangle_align_to_buffer (&aligned_old_extent,
                                  gegl_buffer_get_extent (buffer), buffer,
                                  GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
  gegl_rectangle_align_to_buffer (&aligned_extent,
                                  extent, buffer,
                                  GEGL_RECTANGLE_ALIGNMENT_SUPERSET);

  n_diff_rects = gegl_rectangle_subtract (diff_rects,
                                          &aligned_old_extent,
                                          &aligned_extent);

  for (i = 0; i < n_diff_rects; i++)
    gegl_buffer_clear (buffer, &diff_rects[i]);

  if (gegl_rectangle_intersect (&old_extent_rem,
                                gegl_buffer_get_extent (buffer),
                                &aligned_extent))
    {
      n_diff_rects = gegl_rectangle_subtract (diff_rects,
                                              &old_extent_rem,
                                              extent);

      for (i = 0; i < n_diff_rects; i++)
        gegl_buffer_clear (buffer, &diff_rects[i]);
    }

  return gegl_buffer_set_extent (buffer, extent);
}


/*  private functions  */

static gboolean
gimp_gegl_op_blacklisted (const gchar  *name,
                          const gchar  *categories_str,
                          gboolean      block_gimp_ops,
                          GError      **error)
{
  static const gchar * const category_blacklist[] =
  {
    "compositors",
    "core",
    "debug",
    "display",
    "hidden",
    "input",
    "output",
    "programming",
    "transform",
    "video"
  };
  static const gchar * const name_blacklist[] =
  {
    /* these ops are blacklisted for other reasons */
    "gegl:color", /* pointless */
    "gegl:contrast-curve",
    "gegl:convert-format", /* pointless */
    "gegl:ditto", /* pointless */
    "gegl:fill-path",
    "gegl:gray", /* we use gimp's op */
    "gegl:hstack", /* deleted from GEGL and replaced by gegl:pack */
    "gegl:introspect", /* pointless */
    "gegl:json:dropshadow2", /* has shortcomings, and duplicates gegl:dropshadow */
    "gegl:json:grey2", /* has shortcomings, and duplicates gegl:gray */
    "gegl:layer", /* we use gimp's ops */
    "gegl:lcms-from-profile", /* not usable here */
    "gegl:linear-gradient", /* we use the blend tool */
    "gegl:map-absolute", /* pointless */
    "gegl:map-relative", /* pointless */
    "gegl:matting-global", /* used in the foreground select tool */
    "gegl:matting-levin", /* used in the foreground select tool */
    "gegl:nop", /* pointless */
    "gegl:opacity", /* poinless */
    "gegl:pack", /* pointless */
    "gegl:path",
    "gegl:posterize", /* we use gimp's op */
    "gegl:radial-gradient", /* we use the blend tool */
    "gegl:rectangle", /* pointless */
    "gegl:seamless-clone", /* used in the seamless clone tool */
    "gegl:text", /* we use gimp's text rendering */
    "gegl:threshold", /* we use gimp's op */
    "gegl:tile", /* pointless */
    "gegl:unpremul", /* pointless */
    "gegl:vector-stroke",
    "gegl:wavelet-blur", /* we use gimp's op wavelet-decompose */
  };

  GType   op_type;
  gint    i;

  /* Operations with no name are abstract base classes */
  if (! name)
    return TRUE;

  g_return_val_if_fail (error == NULL || *error == NULL, TRUE);

  /* use this flag to include all ops for testing */
  if (g_getenv ("GIMP_TESTING_NO_GEGL_BLACKLIST"))
    return FALSE;

  if (block_gimp_ops && g_str_has_prefix (name, "gimp"))
    {
      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                           "Filters in namespace \"gimp:\" are hidden.");
      return TRUE;
    }

  for (i = 0; i < G_N_ELEMENTS (name_blacklist); i++)
    {
      if (! strcmp (name, name_blacklist[i]))
        {
          g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                               "The filter is hidden.");
          return TRUE;
        }
    }

  if (g_strcmp0 (name, "gegl:gegl") == 0)
    {
      if (g_getenv ("GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT") == NULL)
        {
          g_set_error (error, GIMP_ERROR, GIMP_FAILED,
                       "%s\n%s", "The filter is unsafe.",
                       "For development purpose, set environment variable GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT.");
          return TRUE;
        }
      else
        {
          return FALSE;
        }
    }

  if (categories_str)
    {
      gchar **categories;

      categories = g_strsplit (categories_str, ":", 0);

      for (i = 0; i < G_N_ELEMENTS (category_blacklist); i++)
        {
          gint j;

          for (j = 0; categories[j]; j++)
            if (! strcmp (categories[j], category_blacklist[i]))
              {
                g_strfreev (categories);
                g_set_error (error, GIMP_ERROR, GIMP_FAILED,
                             "Filters from category \"%s\" are hidden.",
                             category_blacklist[i]);
                return TRUE;
              }
        }

      g_strfreev (categories);
    }

  op_type = gegl_operation_gtype_from_name (name);
  /* Forbid filters which directly write into files. These should
   * not be creatable through GIMP UI, but just in case someone
   * builds one such XCF file (maliciously or by mistake/through a
   * bug), let's prevent this filter to overwrite random files on
   * load.
   * Most of these sink ops are in group "output", but double-checking
   * is not a bad thing here.
   */

  if (g_type_is_a (op_type, GEGL_TYPE_OPERATION_SINK))
    {
      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                           "The filter is unsafe.");
      return TRUE;
    }

  return FALSE;
}

/* Builds a GList of the class structures of all subtypes of type.
 */

static GList *
gimp_gegl_get_op_subclasses (GType     type,
                             GList    *classes,
                             gboolean  block_gimp_ops)
{
  GeglOperationClass *klass;
  GType              *ops;
  const gchar        *categories;
  guint               n_ops;
  gint                i;

  if (! type)
    return classes;

  klass = GEGL_OPERATION_CLASS (g_type_class_ref (type));
  ops = g_type_children (type, &n_ops);

  categories = gegl_operation_class_get_key (klass, "categories");

  if (! gimp_gegl_op_blacklisted (klass->name, categories, block_gimp_ops, NULL))
    classes = g_list_prepend (classes, klass);

  for (i = 0; i < n_ops; i++)
    classes = gimp_gegl_get_op_subclasses (ops[i], classes, block_gimp_ops);

  if (ops)
    g_free (ops);

  return classes;
}

static gint
gimp_gegl_compare_op_names (GeglOperationClass *a,
                            GeglOperationClass *b)
{
  const gchar *name_a = gegl_operation_class_get_key (a, "title");
  const gchar *name_b = gegl_operation_class_get_key (b, "title");

  if (! name_a) name_a = a->name;
  if (! name_b) name_b = b->name;

  return strcmp (name_a, name_b);
}

Messung
CHZG
849710093

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499168