Esempio n. 1
0
void
gimp_gegl_apply_set_alpha (GeglBuffer    *src_buffer,
                           GimpProgress  *progress,
                           const gchar   *undo_desc,
                           GeglBuffer    *dest_buffer,
                           gdouble        value)
{
  GeglNode *node;

  g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
  g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));

  node = gegl_node_new_child (NULL,
                              "operation", "gimp:set-alpha",
                              "value",     value,
                              NULL);

  gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
                             node, dest_buffer, NULL);
  g_object_unref (node);
}
Esempio n. 2
0
GeglNode *
gimp_gegl_create_apply_opacity_node (GeglBuffer *mask,
                                     gint        mask_offset_x,
                                     gint        mask_offset_y,
                                     gdouble     opacity)
{
  GeglNode  *node;
  GeglNode  *input;
  GeglNode  *output;
  GeglNode  *opacity_node;
  GeglNode  *mask_source;

  g_return_val_if_fail (GEGL_IS_BUFFER (mask), NULL);

  node = gegl_node_new ();

  input  = gegl_node_get_input_proxy  (node, "input");
  output = gegl_node_get_output_proxy (node, "output");

  opacity_node = gegl_node_new_child (node,
                                      "operation", "gegl:opacity",
                                      "value",     opacity,
                                      NULL);

  mask_source = gimp_gegl_add_buffer_source (node, mask,
                                             mask_offset_x,
                                             mask_offset_y);

  gegl_node_connect_to (input,        "output",
                        opacity_node, "input");
  gegl_node_connect_to (mask_source,  "output",
                        opacity_node, "aux");
  gegl_node_connect_to (opacity_node, "output",
                        output,       "input");

  return node;
}
void
gimp_gegl_apply_gaussian_blur (GeglBuffer   *src_buffer,
                               GimpProgress *progress,
                               const gchar  *undo_desc,
                               GeglBuffer   *dest_buffer,
                               gdouble       std_dev_x,
                               gdouble       std_dev_y)
{
  GeglNode *node;

  g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
  g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));

  node = gegl_node_new_child (NULL,
                              "operation", "gegl:gaussian-blur",
                              "std-dev-x", std_dev_x,
                              "std-dev-y", std_dev_y,
                              NULL);

  gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
                             node, dest_buffer, NULL);
  g_object_unref (node);
}
Esempio n. 4
0
/* in attach we hook into graph adding the needed nodes */
static void
attach (GeglOperation *operation)
{
  GeglNode  *gegl = operation->node;
  GeglNode  *input, *output, *over, *translate, *opacity, *blur, *darken, *color;
  GeglColor *black_color = gegl_color_new ("rgb(0.0,0.0,0.0)");

  input     = gegl_node_get_input_proxy (gegl, "input");
  output    = gegl_node_get_output_proxy (gegl, "output");
  over      = gegl_node_new_child (gegl, "operation", "gegl:over", NULL);
  translate = gegl_node_new_child (gegl, "operation", "gegl:translate", NULL);
  opacity   = gegl_node_new_child (gegl, "operation", "gegl:opacity", NULL);
  blur      = gegl_node_new_child (gegl, "operation", "gegl:gaussian-blur", 
                                         "clip-extent", FALSE, 
                                         "abyss-policy", 0,
                                         NULL);
  darken    = gegl_node_new_child (gegl, "operation", "gegl:src-in", NULL);
  color     = gegl_node_new_child (gegl, "operation", "gegl:color",
                                   "value", black_color,
                                   NULL);

  g_object_unref (black_color);

  gegl_node_link_many (input, darken, blur, opacity, translate, over, output,
                       NULL);
  gegl_node_connect_from (over, "aux", input, "output");
  gegl_node_connect_from (darken, "aux", color, "output");

  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, "x", translate, "x");
  gegl_operation_meta_redirect (operation, "y", translate, "y");
  gegl_operation_meta_redirect (operation, "color", color, "value");
  gegl_operation_meta_redirect (operation, "opacity", opacity, "value");

  gegl_operation_meta_watch_nodes (operation,
                                   over, translate, opacity,
                                   blur, darken, color,
                                   NULL);
}
Esempio n. 5
0
/**
 * gimp_drawable_get_line_art_fill_buffer:
 * @drawable: the #GimpDrawable to edit.
 * @line_art: the #GimpLineArt computed as fill source.
 * @options: the #GimpFillOptions.
 * @sample_merged:
 * @seed_x: X coordinate to start the fill.
 * @seed_y: Y coordinate to start the fill.
 * @mask_buffer: mask of the fill in-progress when in an interactive
 *               filling process. Set to NULL if you need a one-time
 *               fill.
 * @mask_x: returned x bound of @mask_buffer.
 * @mask_y: returned x bound of @mask_buffer.
 * @mask_width: returned width bound of @mask_buffer.
 * @mask_height: returned height bound of @mask_buffer.
 *
 * Creates the fill buffer for a bucket fill operation on @drawable
 * based on @line_art and @options, without actually applying it.
 * If @mask_buffer is not NULL, the intermediate fill mask will also be
 * returned. This fill mask can later be reused in successive calls to
 * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
 *
 * Returns: a fill buffer which can be directly applied to @drawable, or
 *          used in a drawable filter as preview.
 */
GeglBuffer *
gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
                                        GimpLineArt      *line_art,
                                        GimpFillOptions  *options,
                                        gboolean          sample_merged,
                                        gdouble           seed_x,
                                        gdouble           seed_y,
                                        GeglBuffer      **mask_buffer,
                                        gdouble          *mask_x,
                                        gdouble          *mask_y,
                                        gint             *mask_width,
                                        gint             *mask_height)
{
  GimpImage  *image;
  GeglBuffer *buffer;
  GeglBuffer *new_mask;
  gint        x, y, width, height;
  gint        mask_offset_x = 0;
  gint        mask_offset_y = 0;
  gint        sel_x, sel_y, sel_width, sel_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &sel_x, &sel_y, &sel_width, &sel_height))
    return NULL;

  if (mask_buffer && *mask_buffer)
    {
      gfloat pixel;

      gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
                          babl_format ("Y float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      if (pixel != 0.0)
        /* Already selected. This seed won't change the selection. */
        return NULL;
    }

  gimp_set_busy (image->gimp);

  /*  Do a seed bucket fill...To do this, calculate a new
   *  contiguous region.
   */
  new_mask = gimp_pickable_contiguous_region_by_line_art (NULL, line_art,
                                                          (gint) seed_x,
                                                          (gint) seed_y);
  if (mask_buffer && *mask_buffer)
    {
      gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
                                     GIMP_CHANNEL_OP_ADD, 0, 0);
      g_object_unref (*mask_buffer);
    }
  if (mask_buffer)
    *mask_buffer = new_mask;

  gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
  width  -= x;
  height -= y;

  /*  If there is a selection, intersect the region bounds
   *  with the selection bounds, to avoid processing areas
   *  that are going to be masked out anyway.  The actual
   *  intersection of the fill region with the mask data
   *  happens when combining the fill buffer, in
   *  gimp_drawable_apply_buffer().
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      gint off_x = 0;
      gint off_y = 0;

      if (sample_merged)
        gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      if (! gimp_rectangle_intersect (x, y, width, height,

                                      sel_x + off_x, sel_y + off_y,
                                      sel_width,     sel_height,

                                      &x, &y, &width, &height))
        {
          if (! mask_buffer)
            g_object_unref (new_mask);
          /*  The fill region and the selection are disjoint; bail.  */
          gimp_unset_busy (image->gimp);

          return NULL;
        }
    }

  /*  make sure we handle the mask correctly if it was sample-merged  */
  if (sample_merged)
    {
      GimpItem *item = GIMP_ITEM (drawable);
      gint      off_x, off_y;

      /*  Limit the channel bounds to the drawable's extents  */
      gimp_item_get_offset (item, &off_x, &off_y);

      gimp_rectangle_intersect (x, y, width, height,

                                off_x, off_y,
                                gimp_item_get_width (item),
                                gimp_item_get_height (item),

                                &x, &y, &width, &height);

      mask_offset_x = x;
      mask_offset_y = y;

     /*  translate mask bounds to drawable coords  */
      x -= off_x;
      y -= off_y;
    }
  else
    {
      mask_offset_x = x;
      mask_offset_y = y;
    }

  buffer = gimp_fill_options_create_buffer (options, drawable,
                                            GEGL_RECTANGLE (0, 0,
                                                            width, height),
                                            -x, -y);

  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
                           -mask_offset_x, -mask_offset_y, 1.0);

  if (gimp_fill_options_get_antialias (options))
    {
      /* Antialias for the line art algorithm is not applied during mask
       * creation because it is not based on individual pixel colors.
       * Instead we just want to apply it on the borders of the mask at
       * the end (since the mask can evolve, we don't want to actually
       * touch it, but only the intermediate results).
       */
      GeglNode   *graph;
      GeglNode   *input;
      GeglNode   *op;

      graph = gegl_node_new ();
      input = gegl_node_new_child (graph,
                                   "operation", "gegl:buffer-source",
                                   "buffer", buffer,
                                   NULL);
      op  = gegl_node_new_child (graph,
                                 "operation", "gegl:gaussian-blur",
                                 "std-dev-x", 0.5,
                                 "std-dev-y", 0.5,
                                 NULL);
      gegl_node_connect_to (input, "output", op, "input");
      gegl_node_blit_buffer (op, buffer, NULL, 0,
                             GEGL_ABYSS_NONE);
      g_object_unref (graph);
    }

  if (mask_x)
    *mask_x = x;
  if (mask_y)
    *mask_y = y;
  if (mask_width)
    *mask_width = width;
  if (mask_height)
    *mask_height = height;

  if (! mask_buffer)
    g_object_unref (new_mask);

  gimp_unset_busy (image->gimp);

  return buffer;
}
static void
gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select,
                                     GimpDisplay              *display)
{
  GimpTool                    *tool     = GIMP_TOOL (fg_select);
  GimpForegroundSelectOptions *options  = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
  GimpImage                   *image    = gimp_display_get_image (display);
  GimpDrawable                *drawable = gimp_image_get_active_drawable (image);
  GeglBuffer                  *trimap_buffer;
  GeglBuffer                  *drawable_buffer;
  GeglNode                    *gegl;
  GeglNode                    *matting_node;
  GeglNode                    *input_image;
  GeglNode                    *input_trimap;
  GeglNode                    *output_mask;
  GeglBuffer                  *buffer;
  GimpProgress                *progress;
  GeglProcessor               *processor;
  gdouble                     value;

  if (fg_select->mask)
    {
      g_object_unref (fg_select->mask);
      fg_select->mask = NULL;
    }

  progress = gimp_progress_start (GIMP_PROGRESS (fg_select),
                                  _("Computing alpha of unknown pixels"),
                                  FALSE);

  trimap_buffer   = fg_select->trimap;
  drawable_buffer = gimp_drawable_get_buffer (drawable);

  gegl = gegl_node_new ();

  input_trimap = gegl_node_new_child (gegl,
                                      "operation", "gegl:buffer-source",
                                      "buffer",    trimap_buffer,
                                      NULL);
  input_image = gegl_node_new_child (gegl,
                                     "operation", "gegl:buffer-source",
                                     "buffer",    drawable_buffer,
                                     NULL);
  output_mask = gegl_node_new_child (gegl,
                                     "operation", "gegl:buffer-sink",
                                     "buffer",    &buffer,
                                     "format",    NULL,
                                     NULL);

  if (options->engine == GIMP_MATTING_ENGINE_GLOBAL)
    {
      matting_node = gegl_node_new_child (gegl,
                                          "operation",  "gegl:matting-global",
                                          "iterations", options->iterations,
                                          NULL);
    }
  else
    {
      matting_node = gegl_node_new_child (gegl,
                                          "operation",     "gegl:matting-levin",
                                          "levels",        options->levels,
                                          "active_levels", options->active_levels,
                                          NULL);
    }

  gegl_node_connect_to (input_image,  "output",
                        matting_node, "input");
  gegl_node_connect_to (input_trimap, "output",
                        matting_node, "aux");
  gegl_node_connect_to (matting_node, "output",
                        output_mask,  "input");

  processor = gegl_node_new_processor (output_mask, NULL);

  while (gegl_processor_work (processor, &value))
    {
      if (progress)
        gimp_progress_set_value (progress, value);
    }

  if (progress)
    gimp_progress_end (progress);

  g_object_unref (processor);

  fg_select->mask = buffer;

  gimp_foreground_select_tool_set_preview (fg_select, display);

  g_object_unref (gegl);
}
Esempio n. 7
0
static void
gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                              GimpDrawable     *drawable,
                              GimpPaintOptions *paint_options,
                              const GimpCoords *coords,
                              GimpPaintState    paint_state,
                              guint32           time)
{
  GimpSourceCore       *source_core   = GIMP_SOURCE_CORE (paint_core);
  GimpPerspectiveClone *clone         = GIMP_PERSPECTIVE_CLONE (paint_core);
  GimpContext          *context       = GIMP_CONTEXT (paint_options);
  GimpCloneOptions     *clone_options = GIMP_CLONE_OPTIONS (paint_options);
  GimpSourceOptions    *options       = GIMP_SOURCE_OPTIONS (paint_options);

  switch (paint_state)
    {
    case GIMP_PAINT_STATE_INIT:
      if (source_core->set_source)
        {
          g_object_set (source_core, "src-drawable", drawable, NULL);

          source_core->src_x = coords->x;
          source_core->src_y = coords->y;

          /* get source coordinates in front view perspective */
          gimp_matrix3_transform_point (&clone->transform_inv,
                                        source_core->src_x,
                                        source_core->src_y,
                                        &clone->src_x_fv,
                                        &clone->src_y_fv);

          source_core->first_stroke = TRUE;
        }
      else
        {
          GeglBuffer *orig_buffer = NULL;
          GeglNode   *tile        = NULL;
          GeglNode   *src_node;

          if (options->align_mode == GIMP_SOURCE_ALIGN_NO)
            {
              source_core->orig_src_x = source_core->src_x;
              source_core->orig_src_y = source_core->src_y;

              source_core->first_stroke = TRUE;
            }

          clone->node = gegl_node_new ();

          g_object_set (clone->node,
                        "dont-cache", TRUE,
                        NULL);

          switch (clone_options->clone_type)
            {
            case GIMP_IMAGE_CLONE:
              {
                GimpPickable *src_pickable;
                GimpImage    *src_image;
                GimpImage    *dest_image;

                /*  If the source image is different from the
                 *  destination, then we should copy straight from the
                 *  source image to the canvas.
                 *  Otherwise, we need a call to get_orig_image to make sure
                 *  we get a copy of the unblemished (offset) image
                 */
                src_pickable = GIMP_PICKABLE (source_core->src_drawable);
                src_image    = gimp_pickable_get_image (src_pickable);

                if (options->sample_merged)
                  src_pickable = GIMP_PICKABLE (gimp_image_get_projection (src_image));

                dest_image = gimp_item_get_image (GIMP_ITEM (drawable));

                if ((options->sample_merged &&
                     (src_image != dest_image)) ||
                    (! options->sample_merged &&
                     (source_core->src_drawable != drawable)))
                  {
                    orig_buffer = gimp_pickable_get_buffer (src_pickable);
                  }
                else
                  {
                    if (options->sample_merged)
                      orig_buffer = gimp_paint_core_get_orig_proj (paint_core);
                    else
                      orig_buffer = gimp_paint_core_get_orig_image (paint_core);
                  }
              }
              break;

            case GIMP_PATTERN_CLONE:
              {
                GimpPattern *pattern = gimp_context_get_pattern (context);

                orig_buffer = gimp_pattern_create_buffer (pattern);

                tile = gegl_node_new_child (clone->node,
                                            "operation", "gegl:tile",
                                            NULL);
                clone->crop = gegl_node_new_child (clone->node,
                                                   "operation", "gegl:crop",
                                                   NULL);
              }
              break;
            }

          src_node = gegl_node_new_child (clone->node,
                                          "operation", "gegl:buffer-source",
                                          "buffer",    orig_buffer,
                                          NULL);

          clone->transform_node =
            gegl_node_new_child (clone->node,
                                 "operation", "gegl:transform",
                                 "sampler",    GIMP_INTERPOLATION_LINEAR,
                                 NULL);

          clone->dest_node =
            gegl_node_new_child (clone->node,
                                 "operation", "gegl:write-buffer",
                                 NULL);

          if (tile)
            {
              gegl_node_link_many (src_node,
                                   tile,
                                   clone->crop,
                                   clone->transform_node,
                                   clone->dest_node,
                                   NULL);

              g_object_unref (orig_buffer);
            }
          else
            {
              gegl_node_link_many (src_node,
                                   clone->transform_node,
                                   clone->dest_node,
                                   NULL);
            }
        }
      break;

    case GIMP_PAINT_STATE_MOTION:
      if (source_core->set_source)
        {
          /*  If the control key is down, move the src target and return */

          source_core->src_x = coords->x;
          source_core->src_y = coords->y;

          /* get source coordinates in front view perspective */
          gimp_matrix3_transform_point (&clone->transform_inv,
                                        source_core->src_x,
                                        source_core->src_y,
                                        &clone->src_x_fv,
                                        &clone->src_y_fv);

          source_core->first_stroke = TRUE;
        }
      else
        {
          /*  otherwise, update the target  */

          gint dest_x;
          gint dest_y;

          dest_x = coords->x;
          dest_y = coords->y;

          if (options->align_mode == GIMP_SOURCE_ALIGN_REGISTERED)
            {
              source_core->offset_x = 0;
              source_core->offset_y = 0;
            }
          else if (options->align_mode == GIMP_SOURCE_ALIGN_FIXED)
            {
              source_core->offset_x = source_core->src_x - dest_x;
              source_core->offset_y = source_core->src_y - dest_y;
            }
          else if (source_core->first_stroke)
            {
              source_core->offset_x = source_core->src_x - dest_x;
              source_core->offset_y = source_core->src_y - dest_y;

              /* get destination coordinates in front view perspective */
              gimp_matrix3_transform_point (&clone->transform_inv,
                                            dest_x,
                                            dest_y,
                                            &clone->dest_x_fv,
                                            &clone->dest_y_fv);

              source_core->first_stroke = FALSE;
            }

          gimp_source_core_motion (source_core, drawable, paint_options, coords);
        }
      break;

    case GIMP_PAINT_STATE_FINISH:
      if (clone->node)
        {
          g_object_unref (clone->node);
          clone->node           = NULL;
          clone->crop           = NULL;
          clone->transform_node = NULL;
          clone->dest_node      = NULL;
        }
      break;

    default:
      break;
    }

  g_object_notify (G_OBJECT (clone), "src-x");
  g_object_notify (G_OBJECT (clone), "src-y");
}
Esempio n. 8
0
gint
main (gint    argc,
      gchar **argv)
{
    GeglNode      *gegl, *imgA, *imgB, *comparison;
    GeglRectangle  boundsA, boundsB;
    gdouble        max_diff, avg_diff_wrong, avg_diff_total;
    gint           wrong_pixels, total_pixels;

    gegl_init (&argc, &argv);

    if (argc != 3)
    {
        g_print ("This is simple image difference detection tool for use in regression testing.\n"
                 "Exit code is non zero if images are different, if they are equal"
                 "the output will contain the string identical.\n");
        g_print ("Usage: %s <imageA> <imageB>\n", argv[0]);
        return ERROR_WRONG_ARGUMENTS;
    }

    gegl = gegl_node_new ();
    imgA = gegl_node_new_child (gegl,
                                "operation", "gegl:load",
                                "path", argv[1],
                                NULL);
    imgB = gegl_node_new_child (gegl,
                                "operation", "gegl:load",
                                "path", argv[2],
                                NULL);

    boundsA = gegl_node_get_bounding_box (imgA);
    boundsB = gegl_node_get_bounding_box (imgB);
    total_pixels = boundsA.width * boundsA.height;

    if (boundsA.width != boundsB.width || boundsA.height != boundsB.height)
    {
        g_printerr ("%s and %s differ in size\n", argv[1], argv[2]);
        g_printerr ("  %ix%i vs %ix%i\n",
                    boundsA.width, boundsA.height, boundsB.width, boundsB.height);
        return ERROR_WRONG_SIZE;
    }

    comparison = gegl_node_create_child (gegl, "gegl:image-compare");
    gegl_node_link (imgA, comparison);
    gegl_node_connect_to (imgB, "output", comparison, "aux");
    gegl_node_process (comparison);
    gegl_node_get (comparison,
                   "max diff", &max_diff,
                   "avg-diff-wrong", &avg_diff_wrong,
                   "avg-diff-total", &avg_diff_total,
                   "wrong-pixels", &wrong_pixels,
                   NULL);

    if (max_diff >= 0.1)
    {
        g_printerr ("%s and %s differ\n"
                    "  wrong pixels   : %i/%i (%2.2f%%)\n"
                    "  max Δe         : %2.3f\n"
                    "  avg Δe (wrong) : %2.3f(wrong) %2.3f(total)\n",
                    argv[1], argv[2],
                    wrong_pixels, total_pixels,
                    (wrong_pixels*100.0/total_pixels), max_diff,
                    avg_diff_wrong, avg_diff_total);

        if (!strstr (argv[2], "broken"))
        {
            GeglNode *save;
            gchar *debug_path = g_malloc (strlen (argv[2])+16);

            memcpy (debug_path, argv[2], strlen (argv[2])+1);
            memcpy (debug_path + strlen(argv[2])-4, "-diff.png", 11);

            save = gegl_node_new_child (gegl,
                                        "operation", "gegl:png-save",
                                        "path", debug_path,
                                        NULL);
            gegl_node_link (comparison, save);
            gegl_node_process (save);


            /*gegl_graph (sink=gegl_node ("gegl:png-save",
                                        "path", debug_path, NULL,
                                        gegl_node ("gegl:buffer-source", "buffer", debug_buf, NULL)));*/
            if (max_diff > 1.5)
                return ERROR_PIXELS_DIFFERENT;
        }
        if (strstr (argv[2], "broken"))
            g_print ("because the test is expected to fail ");
        else
            g_print ("because the error is small ");
        g_print ("we'll say ");
    }

    g_print ("%s and %s are identical\n", argv[1], argv[2]);

    g_object_unref (gegl);

    gegl_exit ();
    return SUCCESS;
}
Esempio n. 9
0
File: json.c Progetto: GNOME/gegl
static void
attach (GeglOperation *operation)
{
  JsonOp *self = (JsonOp *)operation;
  GeglNode  *gegl = operation->node;
  JsonArray *connections;
  GList *l;

  // Processes
  JsonObject *root = self->json_root;
  JsonObject *processes = json_object_get_object_member(root, "processes");

  GList *process_names = json_object_get_members(processes);
  for (l = process_names; l != NULL; l = l->next) {
      const gchar *name = l->data;
      JsonObject *proc = json_object_get_object_member(processes, name);
      const gchar *component = json_object_get_string_member(proc, "component");
      gchar *opname = component2geglop(component);

      GeglNode *node = gegl_node_new_child (gegl, "operation", opname, NULL);
      gegl_operation_meta_watch_node (operation, node);
      g_assert(node);
      g_hash_table_insert(self->nodes, (gpointer)g_strdup(name), (gpointer)node);
      g_free(opname);
  }
  g_list_free(process_names);

  // Connections
  connections = json_object_get_array_member(root, "connections");
  g_assert(connections);
  for (int i=0; i<json_array_get_length(connections); i++) {
      JsonObject *conn = json_array_get_object_element(connections, i);
      JsonObject *tgt = json_object_get_object_member(conn, "tgt");
      const gchar *tgt_proc = json_object_get_string_member(tgt, "process");
      const gchar *tgt_port = json_object_get_string_member(tgt, "port");
      GeglNode *tgt_node = g_hash_table_lookup(self->nodes, tgt_proc);
      JsonNode *srcnode;

      g_assert(tgt_node);

      srcnode = json_object_get_member(conn, "src");
      if (srcnode) {
          // Connection
          JsonObject *src = json_object_get_object_member(conn, "src");
          const gchar *src_proc = json_object_get_string_member(src, "process");
          const gchar *src_port = json_object_get_string_member(src, "port");
          GeglNode *src_node = g_hash_table_lookup(self->nodes, src_proc);

          g_assert(src_node);

          gegl_node_connect_to (src_node, src_port, tgt_node, tgt_port);
      } else {
          // IIP
          JsonNode *datanode = json_object_get_member(conn, "data");
          GValue value = G_VALUE_INIT;
          GParamSpec *paramspec;

          g_assert(JSON_NODE_HOLDS_VALUE(datanode));
          json_node_get_value(datanode, &value);
          paramspec = gegl_node_find_property(tgt_node, tgt_port);

          set_prop(tgt_node, tgt_port, paramspec, &value);
          g_value_unset(&value);
      }
  }


  // Exported ports
  if (json_object_has_member(root, "inports")) {
      JsonObject *inports = json_object_get_object_member(root, "inports");
      GList *inport_names = json_object_get_members(inports);
      for (l = inport_names; l != NULL; l = l->next) {
          const gchar *name = l->data;
          JsonObject *conn = json_object_get_object_member(inports, name);
          const gchar *proc = json_object_get_string_member(conn, "process");
          const gchar *port = json_object_get_string_member(conn, "port");
          GeglNode *node = g_hash_table_lookup(self->nodes, proc);

          g_assert(node);

          if (g_strcmp0(name, "input") == 0) {
              GeglNode *input = gegl_node_get_input_proxy (gegl, "input");
              gegl_node_connect_to (input, "output", node, "input");
          } else {
            gegl_operation_meta_redirect (operation, name, node, port);
          }
      }

      g_list_free(inport_names);
  }

  if (json_object_has_member(root, "outports")) {
      JsonObject *outports = json_object_get_object_member(root, "outports");
      GList *outport_names = json_object_get_members(outports);
      for (l = outport_names; l != NULL; l = l->next) {
          const gchar *name = l->data;
          JsonObject *conn = json_object_get_object_member(outports, name);
          const gchar *proc = json_object_get_string_member(conn, "process");
          const gchar *port = json_object_get_string_member(conn, "port");
          GeglNode *node = g_hash_table_lookup(self->nodes, proc);
          g_assert(node);

          if (g_strcmp0(name, "output") == 0) {
            GeglNode *proxy = gegl_node_get_output_proxy (gegl, "output");
            gegl_node_connect_to (node, port, proxy, "input");
          } else {
            g_warning("Unsupported output '%s' exported in .json file", name);
          }
      }

      g_list_free(outport_names);
  }

}
Esempio n. 10
0
GeglBuffer *
gimp_drawable_transform_buffer_affine (GimpDrawable           *drawable,
                                       GimpContext            *context,
                                       GeglBuffer             *orig_buffer,
                                       gint                    orig_offset_x,
                                       gint                    orig_offset_y,
                                       const GimpMatrix3      *matrix,
                                       GimpTransformDirection  direction,
                                       GimpInterpolationType   interpolation_type,
                                       gint                    recursion_level,
                                       GimpTransformResize     clip_result,
                                       gint                   *new_offset_x,
                                       gint                   *new_offset_y,
                                       GimpProgress           *progress)
{
  GeglBuffer  *new_buffer;
  GimpMatrix3  m;
  GimpMatrix3  inv;
  gint         u1, v1, u2, v2;  /* source bounding box */
  gint         x1, y1, x2, y2;  /* target bounding box */
  GeglNode    *affine;
  GimpMatrix3  gegl_matrix;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
  g_return_val_if_fail (matrix != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);

  m   = *matrix;
  inv = *matrix;

  if (direction == GIMP_TRANSFORM_BACKWARD)
    {
      /*  keep the original matrix here, so we dont need to recalculate
       *  the inverse later
       */
      gimp_matrix3_invert (&inv);
    }
  else
    {
      /*  Find the inverse of the transformation matrix  */
      gimp_matrix3_invert (&m);
    }

  u1 = orig_offset_x;
  v1 = orig_offset_y;
  u2 = u1 + gegl_buffer_get_width  (orig_buffer);
  v2 = v1 + gegl_buffer_get_height (orig_buffer);

  /*  Always clip unfloated buffers since they must keep their size  */
  if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL &&
      ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
    clip_result = GIMP_TRANSFORM_RESIZE_CLIP;

  /*  Find the bounding coordinates of target */
  gimp_transform_resize_boundary (&inv, clip_result,
                                  u1, v1, u2, v2,
                                  &x1, &y1, &x2, &y2);

  /*  Get the new temporary buffer for the transformed result  */
  new_buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1),
                                     gegl_buffer_get_format (orig_buffer));

  gimp_matrix3_identity (&gegl_matrix);
  gimp_matrix3_translate (&gegl_matrix, u1, v1);
  gimp_matrix3_mult (&inv, &gegl_matrix);
  gimp_matrix3_translate (&gegl_matrix, -x1, -y1);

  affine = gegl_node_new_child (NULL,
                                "operation",  "gegl:transform",
                                "filter",     gimp_interpolation_to_gegl_filter (interpolation_type),
                                "hard-edges", TRUE,
                                NULL);

  gimp_gegl_node_set_matrix (affine, &gegl_matrix);

  gimp_apply_operation (orig_buffer, progress, NULL,
                        affine,
                        new_buffer, NULL);

  g_object_unref (affine);

  *new_offset_x = x1;
  *new_offset_y = y1;

  return new_buffer;
}
Esempio n. 11
0
void
gimp_drawable_edit_fill (GimpDrawable    *drawable,
                         GimpFillOptions *options,
                         const gchar     *undo_desc)
{
  GimpContext *context;
  gint         x, y, width, height;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
  g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &x, &y, &width, &height))
    {
      return;  /*  nothing to do, but the fill succeeded  */
    }

  context = GIMP_CONTEXT (options);

  if (gimp_layer_mode_is_alpha_only (gimp_context_get_paint_mode (context)))
    {
      if (! gimp_drawable_has_alpha (drawable) ||
          ! (gimp_drawable_get_active_mask (drawable) &
             GIMP_COMPONENT_MASK_ALPHA))
        {
          return;  /*  nothing to do, but the fill succeeded  */
        }
    }

  if (! undo_desc)
    undo_desc = gimp_fill_options_get_undo_desc (options);

  /* check if we can fill the drawable's buffer directly */
  if (gimp_drawable_edit_can_fill_direct (drawable, options))
    {
      gimp_drawable_edit_fill_direct (drawable, options, undo_desc);

      gimp_drawable_update (drawable, x, y, width, height);
    }
  else
    {
      GeglNode           *operation;
      GimpDrawableFilter *filter;
      gdouble             opacity;
      GimpLayerMode       mode;
      GimpLayerMode       composite_mode;

      opacity        = gimp_context_get_opacity (context);
      mode           = gimp_context_get_paint_mode (context);
      composite_mode = gimp_layer_mode_get_paint_composite_mode (mode);

      operation = gegl_node_new_child (NULL,
                                       "operation",        "gimp:fill-source",
                                       "options",          options,
                                       "drawable",         drawable,
                                       "pattern-offset-x", -x,
                                       "pattern-offset-y", -y,
                                       NULL);

      filter = gimp_drawable_filter_new (drawable, undo_desc, operation, NULL);

      gimp_drawable_filter_set_opacity (filter, opacity);
      gimp_drawable_filter_set_mode    (filter,
                                        mode,
                                        GIMP_LAYER_COLOR_SPACE_AUTO,
                                        GIMP_LAYER_COLOR_SPACE_AUTO,
                                        composite_mode);

      gimp_drawable_filter_apply  (filter, NULL);
      gimp_drawable_filter_commit (filter, NULL, FALSE);

      g_object_unref (filter);
      g_object_unref (operation);
    }
}
Esempio n. 12
0
static gboolean
test_operation (const char *operation_name)
{
  gboolean result = FALSE;

  const Babl *format = babl_format ("RGBA u8");
  const gint bpp = babl_format_get_bytes_per_pixel (format);
  const gint out_width = 5 + 10;
  const gint out_height = 5 + 10;

  guchar *output_with_abyss = gegl_malloc (out_width * out_height * bpp);
  guchar *output_no_abyss   = gegl_malloc (out_width * out_height * bpp);

  GeglColor *upper_color = gegl_color_new ("rgb(0.2, 0.8, 0.2)");
  GeglColor *lower_color = gegl_color_new ("rgb(0.0, 0.0, 0.0)");
  GeglColor *transparent = gegl_color_new ("rgba(0.0, 0.0, 0.0, 0.0)");

  {
    /* Using abyss */
    GeglNode *ptn = gegl_node_new();

    GeglNode *test_op, *upper_rect, *lower_rect;

    test_op = gegl_node_new_child (ptn,
                                   "operation", operation_name,
                                   NULL);

    upper_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", upper_color,
                                   "x", 5.0,
                                   "y", 5.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    lower_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", lower_color,
                                   "x", 0.0,
                                   "y", 0.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    gegl_node_connect_to (lower_rect, "output", test_op, "input");
    gegl_node_connect_to (upper_rect, "output", test_op, "aux");

    {
      int i;
      guchar *out = output_with_abyss;
      for (i = 0; i < out_height; i++)
        {
          gegl_node_blit (test_op,
                          1.0,
                          GEGL_RECTANGLE (0, i, out_width, 1),
                          format,
                          out,
                          GEGL_AUTO_ROWSTRIDE,
                          0);
          out += out_width * bpp;
        }
    }

    g_object_unref (ptn);
  }

  {
    /* Explicit transparency */
    GeglNode *ptn = gegl_node_new();

    GeglNode *test_op, *upper_rect, *lower_rect;
    GeglNode *upper_over, *lower_over;
    GeglNode *background;

    test_op = gegl_node_new_child (ptn,
                                   "operation", operation_name,
                                   NULL);

    background = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", transparent,
                                   "x", 0.0,
                                   "y", 0.0,
                                   "width", 10.0 + 5.0,
                                   "height", 10.0 + 5.0,
                                   NULL);

    upper_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", upper_color,
                                   "x", 5.0,
                                   "y", 5.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    upper_over = gegl_node_new_child (ptn,
                                   "operation", "gegl:over",
                                   NULL);

    lower_rect = gegl_node_new_child (ptn,
                                   "operation", "gegl:rectangle",
                                   "color", lower_color,
                                   "x", 0.0,
                                   "y", 0.0,
                                   "width", 10.0,
                                   "height", 10.0,
                                   NULL);

    lower_over = gegl_node_new_child (ptn,
                                   "operation", "gegl:over",
                                   NULL);

    gegl_node_connect_to (lower_rect, "output", lower_over, "aux");
    gegl_node_connect_to (upper_rect, "output", upper_over, "aux");

    gegl_node_connect_to (background, "output", lower_over, "input");
    gegl_node_connect_to (background, "output", upper_over, "input");

    gegl_node_connect_to (lower_over, "output", test_op, "input");
    gegl_node_connect_to (upper_over, "output", test_op, "aux");

    {
      int i;
      guchar *out = output_no_abyss;
      for (i = 0; i < out_height; i++)
        {
          gegl_node_blit (test_op,
                          1.0,
                          GEGL_RECTANGLE (0, i, out_width, 1),
                          format,
                          out,
                          GEGL_AUTO_ROWSTRIDE,
                          0);
          out += out_width * bpp;
        }
    }

    g_object_unref (ptn);
  }

  if (0 == memcmp (output_with_abyss, output_no_abyss, out_width * out_height * bpp))
    {
      printf (".");
      fflush(stdout);
      result = TRUE;
    }
  else
    {
      printf ("\n %s ... FAIL\n", operation_name);
      result = FALSE;
    }

  if (!result)
    {
      GeglBuffer *linear;
      gchar *filename;

      filename = g_strconcat (operation_name, " - with abyss.png", NULL);
      linear = gegl_buffer_linear_new_from_data (output_with_abyss,
                                                format,
                                                GEGL_RECTANGLE (0, 0, out_width, out_height),
                                                GEGL_AUTO_ROWSTRIDE,
                                                NULL,
                                                NULL);
      dump_to_png (filename, linear);
      g_free (filename);
      g_object_unref (linear);

      filename = g_strconcat (operation_name, " - no abyss.png", NULL);
      linear = gegl_buffer_linear_new_from_data (output_no_abyss,
                                                 format,
                                                 GEGL_RECTANGLE (0, 0, out_width, out_height),
                                                 GEGL_AUTO_ROWSTRIDE,
                                                 NULL,
                                                 NULL);
      dump_to_png (filename, linear);
      g_free (filename);
      g_object_unref (linear);
    }

  gegl_free (output_with_abyss);
  gegl_free (output_no_abyss);

  return result;
}
Esempio n. 13
0
GimpApplicator *
gimp_applicator_new (GeglNode *parent,
                     gboolean  linear,
                     gboolean  use_split_preview,
                     gboolean  use_result_cache)
{
  GimpApplicator *applicator;

  g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL);

  applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL);

  applicator->linear = linear;

  if (parent)
    applicator->node = g_object_ref (parent);
  else
    applicator->node = gegl_node_new ();

  applicator->input_node =
    gegl_node_get_input_proxy  (applicator->node, "input");

  applicator->aux_node =
    gegl_node_get_input_proxy  (applicator->node, "aux");

  applicator->output_node =
    gegl_node_get_output_proxy (applicator->node, "output");

  applicator->mode_node = gegl_node_new_child (applicator->node,
                                               "operation", "gimp:normal-mode",
                                               NULL);

  gimp_gegl_mode_node_set_mode (applicator->mode_node,
                                applicator->paint_mode,
                                applicator->linear);
  gimp_gegl_mode_node_set_opacity (applicator->mode_node,
                                   applicator->opacity);

  gegl_node_connect_to (applicator->input_node, "output",
                        applicator->mode_node,  "input");

  applicator->apply_offset_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:translate",
                         NULL);

  applicator->dup_apply_buffer_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:copy-buffer",
                         NULL);

  gegl_node_link_many (applicator->aux_node,
                       applicator->apply_offset_node,
                       applicator->dup_apply_buffer_node,
                       NULL);

  if (use_split_preview)
    {
      applicator->preview_cache_node =
        gegl_node_new_child (applicator->node,
                             "operation", "gegl:cache",
                             NULL);

      applicator->preview_crop_node =
        gegl_node_new_child (applicator->node,
                             "operation", "gegl:nop",
                             NULL);

      gegl_node_link_many (applicator->dup_apply_buffer_node,
                           applicator->preview_cache_node,
                           applicator->preview_crop_node,
                           NULL);
      gegl_node_connect_to (applicator->preview_crop_node, "output",
                            applicator->mode_node,         "aux");
    }
  else
    {
      gegl_node_connect_to (applicator->dup_apply_buffer_node, "output",
                            applicator->mode_node,             "aux");
    }

  applicator->mask_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:buffer-source",
                         NULL);

  applicator->mask_offset_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:translate",
                         NULL);

  gegl_node_connect_to (applicator->mask_node,        "output",
                        applicator->mask_offset_node, "input");
  /* don't connect the the mask offset node to mode's aux2 yet */

  applicator->affect_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gimp:mask-components",
                         "mask",      applicator->affect,
                         NULL);

  if (use_result_cache)
    {
      applicator->output_cache_node =
        gegl_node_new_child (applicator->node,
                             "operation", "gegl:cache",
                             NULL);

      gegl_node_link_many (applicator->input_node,
                           applicator->affect_node,
                           applicator->output_cache_node,
                           applicator->output_node,
                           NULL);
    }
  else
    {
      gegl_node_link_many (applicator->input_node,
                           applicator->affect_node,
                           applicator->output_node,
                           NULL);
    }

  gegl_node_connect_to (applicator->mode_node,   "output",
                        applicator->affect_node, "aux");

  return applicator;
}
Esempio n. 14
0
int main(int argc, char *argv[])
{
  int           result = SUCCESS;
  GeglNode     *graph  = NULL;
  GeglNode     *node   = NULL;
  GeglColor    *color  = NULL;
  double        x      = -5;
  double        y      = -5;
  char         *name   = NULL;
  gboolean      cache  = TRUE;

  /* Init */
  gegl_init (&argc, &argv);

  color = gegl_color_new ("rgb(0.0, 1.0, 0.0)");

  graph = gegl_node_new ();
  node  = gegl_node_new_child (graph,
                               "operation", "gegl:color",
                               "value",     color,
                               NULL);

  gegl_node_get (node, "operation", &name, NULL);
  
  if (!(!strcmp (name, "gegl:color")))
    {
      result = FAILURE;
      printf ("operation: %s\n", name); 
      goto abort;
    }

  gegl_node_set (node,
                 "operation", "gegl:translate",
                 "x", 50.0,
                 "y", 100.0,
                 NULL);
  
  gegl_node_get (node,
                 "operation", &name,
                 "x", &x,
                 "y", &y,
                 NULL);

  if (!(!strcmp (name, "gegl:translate") &&
        (int)x == 50 && (int)y == 100))
    {
      result = FAILURE;
      printf ("operation: %s\n", name); 
      printf ("x, y: %f, %f\n", x, y);
      goto abort;
    }

  gegl_node_set (node,
                 "x", 5.0,
                 "y", 10.0,
                 NULL);
  
  gegl_node_get (node,
                 "y", &y,
                 "operation", &name,
                 "x", &x,
                 NULL);
  
  if (!(!strcmp (name, "gegl:translate") &&
        (int)x == 5 && (int)y == 10))
    {
      result = FAILURE;
      printf ("operation: %s\n", name); 
      printf ("x, y: %f, %f\n", x, y);
      goto abort;
    }

  gegl_node_set (node,
                 "operation", "gegl:doesnt-exist",
                 NULL);

  gegl_node_get (node, "operation", &name, NULL);
  
  if (!(!strcmp (name, "gegl:nop")))
    {
      result = FAILURE;
      printf ("operation: %s\n", name); 
      goto abort;
    }
  
  gegl_node_set (node,
                 "operation", "gegl:nop",
                 NULL);

  gegl_node_get (node, "operation", &name, NULL);
  
  if (!(!strcmp (name, "gegl:nop")))
    {
      result = FAILURE;
      printf ("operation: %s\n", name); 
      goto abort;
    }



  gegl_node_set (node,
                 "operation", "gegl:translate",
                 NULL);
  
  gegl_node_get (node,
                 "operation", &name,
                 "x", &x,
                 "y", &y,
                 NULL);

  if (!(!strcmp (name, "gegl:translate") &&
        (int)x == 0 && (int)y == 0))
    {
      result = FAILURE;
      printf ("operation: %s\n", name); 
      printf ("x, y: %f, %f\n", x, y);
      goto abort;
    }
  
  gegl_node_set (node,
                 "operation", "gegl:translate",
                 "name", "Brian",
                 "dont-cache", FALSE,
                 NULL);
  
  gegl_node_get (node,
                 "name", &name,
                 "dont-cache", &cache,
                 NULL);

  if (!(!strcmp (name, "Brian") &&
        cache == FALSE))
    {
      result = FAILURE;
      printf ("name:  %s\n", name);
      printf ("cache: %d\n", cache); 
      goto abort;
    }

  gegl_node_set (node,
                 "dont-cache", TRUE,
                 "name", "Steve",
                 NULL);

  gegl_node_get (node,
                 "name", &name,
                 "dont-cache", &cache,
                 NULL);

  if (!(!strcmp (name, "Steve") &&
        cache == TRUE))
    {
      result = FAILURE;
      printf ("name: %s\n", name);
      printf ("cache: %d\n", cache);
      goto abort;
    }

abort:
  /* Cleanup */
  g_object_unref (graph);
  g_object_unref (color);
  gegl_exit ();

  return result;
}
Esempio n. 15
0
gint
main (gint    argc,
      gchar **argv)
{
  gegl_init (&argc, &argv);  /* initialize the GEGL library */

  /* license for this application, needed by fractal-explorer */
  g_object_set (gegl_config (),
                "application-license", "GPL3",
                NULL);

  {
    /* instantiate a graph */
    GeglNode *gegl = gegl_node_new ();

/*
This is the graph we're going to construct:

.-----------.
| display   |
`-----------'
    |
.--------.
|  crop  |
`--------'
    |
.--------.
|  over  |
`--------'
    |   \
    |    \
    |     \
    |      |
    |   .------.
    |   | text |
    |   `------'
.------------------.
| fractal-explorer |
`------------------'

*/

    /*< The image nodes representing operations we want to perform */
    GeglNode *display    = gegl_node_create_child (gegl, "gegl:ff-save");
    GeglNode *crop       = gegl_node_new_child (gegl,
                                 "operation", "gegl:crop",
                                 "width", 512.0,
                                 "height", 384.0,
                                  NULL);
    GeglNode *over       = gegl_node_new_child (gegl,
                                 "operation", "gegl:over",
                                 NULL);
    GeglNode *text       = gegl_node_new_child (gegl,
                                 "operation", "gegl:text",
                                 "size", 10.0,
                                 "color", gegl_color_new ("rgb(1.0,1.0,1.0)"),
                                 NULL);
    GeglNode *mandelbrot = gegl_node_new_child (gegl,
                                "operation", "gegl:fractal-explorer",
                                "shiftx", -256.0,
                                NULL);

    gegl_node_link_many (mandelbrot, over, crop, display, NULL);
    gegl_node_connect_to (text, "output",  over, "aux");

    /* request that the save node is processed, all dependencies will
     * be processed as well
     */
    {
      gint frame;
      gint frames = 200;

      for (frame=0; frame<frames; frame++)
        {
          gchar string[512];
          gdouble t = frame * 1.0/frames;

#define INTERPOLATE(min,max) ((max)*(t)+(min)*(1.0-t))

          gdouble shiftx = INTERPOLATE(-256.0, -512.0);
          gdouble shifty = INTERPOLATE(0.0,    -256.0);
          gdouble zoom   = INTERPOLATE(300.0,   400.0);

          gegl_node_set (mandelbrot, "shiftx", shiftx,
                                     "shifty", shifty,
                                     "zoom", zoom,
                                     NULL);
          g_sprintf (string, "x=%1.3f y=%1.3f z=%1.3f", shiftx, shifty, zoom);
          gegl_node_set (text, "string", string, NULL);
          gegl_node_process (display);
        }
    }

    /* free resources used by the graph and the nodes it owns */
    g_object_unref (gegl);
  }

  /* free resources globally used by GEGL */
  gegl_exit ();

  return 0;
}
Esempio n. 16
0
static gboolean
test_operation (const gchar *op_name,
                const gchar *image,
                gchar       *output_path)
{
  gchar         *ref_path;
  GeglNode      *img, *ref_img, *gegl;
  GeglRectangle  ref_bounds, comp_bounds;
  gint           ref_pixels;
  gboolean       result = TRUE;

  gegl = gegl_node_new ();

  ref_path = g_build_path (G_DIR_SEPARATOR_S, reference_dir, image, NULL);
  ref_img = gegl_node_new_child (gegl,
                                 "operation", "gegl:load",
                                 "path", ref_path,
                                 NULL);
  g_free (ref_path);

  img = gegl_node_new_child (gegl,
                             "operation", "gegl:load",
                             "path", output_path,
                             NULL);

  ref_bounds  = gegl_node_get_bounding_box (ref_img);
  comp_bounds = gegl_node_get_bounding_box (img);
  ref_pixels  = ref_bounds.width * ref_bounds.height;

  if (ref_bounds.width != comp_bounds.width ||
      ref_bounds.height != comp_bounds.height)
    {
      g_printf ("FAIL\n  Reference and composition differ in size\n");
      result = FALSE;
    }
  else
    {
      GeglNode *comparison;
      gdouble   max_diff;

      comparison = gegl_node_create_child (gegl, "gegl:image-compare");
      gegl_node_link (img, comparison);
      gegl_node_connect_to (ref_img, "output", comparison, "aux");
      gegl_node_process (comparison);
      gegl_node_get (comparison, "max diff", &max_diff, NULL);

      if (max_diff < 1.0)
        {
          g_printf ("PASS\n");
          result = TRUE;
        }
      else
        {
          GeglNode *output;
          gchar    *diff_path;
          gdouble   avg_diff_wrong, avg_diff_total;
          gint      wrong_pixels;

          gegl_node_get (comparison, "avg_diff_wrong", &avg_diff_wrong,
                         "avg_diff_total", &avg_diff_total, "wrong_pixels",
                         &wrong_pixels, NULL);

          g_printf ("FAIL\n  Reference image and composition differ\n"
                    "    wrong pixels : %i/%i (%2.2f%%)\n"
                    "    max Δe       : %2.3f\n"
                    "    avg Δe       : %2.3f (wrong) %2.3f (total)\n",
                    wrong_pixels, ref_pixels,
                    (wrong_pixels * 100.0 / ref_pixels),
                    max_diff, avg_diff_wrong, avg_diff_total);

          diff_path = operation_to_path (op_name, TRUE);
          output = gegl_node_new_child (gegl,
                                        "operation", "gegl:png-save",
                                        "path", diff_path,
                                        NULL);
          gegl_node_link (comparison, output);
          gegl_node_process (output);

          g_free (diff_path);

          result = FALSE;
        }
    }

  g_object_unref (gegl);
  return result;
}
Esempio n. 17
0
static gboolean
process_operations (GType type)
{
  GType    *operations;
  gboolean  result = TRUE;
  guint     count;
  gint      i;

  operations = g_type_children (type, &count);

  if (!operations)
    {
      g_free (operations);
      return TRUE;
    }

  for (i = 0; i < count; i++)
    {
      GeglOperationClass *operation_class;
      const gchar        *image, *xml, *name;
      gboolean            matches;

      operation_class = g_type_class_ref (operations[i]);
      image           = gegl_operation_class_get_key (operation_class, "reference-image");
      xml             = gegl_operation_class_get_key (operation_class, "reference-composition");
      name            = gegl_operation_class_get_key (operation_class, "name");

      if (name == NULL)
        {
          result = result && process_operations (operations[i]);
          continue;
        }

      matches = g_regex_match (regex, name, 0, NULL) &&
        !g_regex_match (exc_regex, name, 0, NULL);

      if (xml && matches)
        {
          GeglNode *composition;

          if (output_all)
            g_printf ("%s\n", name);
          else if (image)
            g_printf ("%s: ", name); /* more information will follow
                                        if we're testing */

          composition = gegl_node_new_from_xml (xml, data_dir);
          if (!composition)
            {
              g_printf ("FAIL\n  Composition graph is flawed\n");
              result = FALSE;
            }
          else if (image || output_all)
            {
              gchar    *output_path = operation_to_path (name, FALSE);
              GeglNode *output      =
                gegl_node_new_child (composition,
                                     "operation", "gegl:png-save",
                                     "compression", 9,
                                     "path", output_path,
                                     NULL);
              gegl_node_link (composition, output);
              gegl_node_process (output);
              g_object_unref (composition);

              /* don't test if run with --all */
              if (!output_all && image)
                result = test_operation (name, image, output_path) && result;

              g_free (output_path);
            }
        }
      /* if we are running with --all and the operation doesn't have a
         composition, use standard composition and images, don't test */
      else if (output_all && matches &&
               !(g_type_is_a (operations[i], GEGL_TYPE_OPERATION_SINK) ||
                 g_type_is_a (operations[i], GEGL_TYPE_OPERATION_TEMPORAL)))
        {
          g_printf ("%s\n", name);
          standard_output (name);
        }

      result = process_operations (operations[i]) && result;
    }

  g_free (operations);

  return result;
}
Esempio n. 18
0
static void
standard_output (const gchar *op_name)
{
  GeglNode *composition, *input, *aux, *operation, *crop, *output, *translate;
  GeglNode *background,  *over;
  gchar    *input_path  = g_build_path (G_DIR_SEPARATOR_S, data_dir,
                                        "standard-input.png", NULL);
  gchar    *aux_path    = g_build_path (G_DIR_SEPARATOR_S, data_dir,
                                        "standard-aux.png", NULL);
  gchar    *output_path = operation_to_path (op_name, FALSE);

  composition = gegl_node_new ();
  operation = gegl_node_create_child (composition, op_name);

  if (gegl_node_has_pad (operation, "output"))
    {
      input = gegl_node_new_child (composition,
                                   "operation", "gegl:load",
                                   "path", input_path,
                                   NULL);
      translate  = gegl_node_new_child (composition,
                                 "operation", "gegl:translate",
                                 "x", 0.0,
                                 "y", 80.0,
                                 NULL);
      aux = gegl_node_new_child (composition,
                                 "operation", "gegl:load",
                                 "path", aux_path,
                                 NULL);
      crop = gegl_node_new_child (composition,
                                  "operation", "gegl:crop",
                                  "width", 200.0,
                                  "height", 200.0,
                                  NULL);
      output = gegl_node_new_child (composition,
                                    "operation", "gegl:png-save",
                                    "compression", 9,
                                    "path", output_path,
                                    NULL);
      background = gegl_node_new_child (composition,
                                        "operation", "gegl:checkerboard",
                                        "color1", gegl_color_new ("rgb(0.75,0.75,0.75)"),
                                        "color2", gegl_color_new ("rgb(0.25,0.25,0.25)"),
                                        NULL);
      over = gegl_node_new_child (composition, "operation", "gegl:over", NULL);


      if (gegl_node_has_pad (operation, "input"))
        gegl_node_link (input, operation);

      if (gegl_node_has_pad (operation, "aux"))
      {
        gegl_node_connect_to (aux, "output", translate, "input");
        gegl_node_connect_to (translate, "output", operation, "aux");
      }

      gegl_node_connect_to (background, "output", over, "input");
      gegl_node_connect_to (operation,  "output", over, "aux");
      gegl_node_connect_to (over,       "output", crop, "input");
      gegl_node_connect_to (crop,       "output", output, "input");


      gegl_node_process (output);
    }

  g_free (input_path);
  g_free (aux_path);
  g_free (output_path);
  g_object_unref (composition);
}
int main(int argc, char *argv[])
{
  gint           result       = SUCCESS;
  GeglRectangle  rect1        = { 0, 0, 1, 1 };
  GeglRectangle  rect2        = { 1, 0, 1, 1 };
  GeglRectangle  rect3        = { 1, 1, 1, 1 };
  GeglRectangle  rect4        = { 0, 1, 1, 1 };
  GeglColor     *color_white = NULL;
  GeglColor     *color_black = NULL;
  GeglNode      *gegl        = NULL;
  GeglNode      *white       = NULL;
  GeglNode      *translate   = NULL;
  GeglNode      *over        = NULL;
  GeglNode      *black       = NULL;
  GeglNode      *crop        = NULL;
  GeglNode      *sink        = NULL;
  GeglProcessor *processor   = NULL;

  /* Convenient line to keep around:
  g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
   */

  gegl_init (&argc, &argv);

  color_white = gegl_color_new ("rgb(1.0, 1.0, 1.0)");
  color_black = gegl_color_new ("rgb(0.0, 0.0, 0.0)");

  gegl         = gegl_node_new ();
  white        = gegl_node_new_child (gegl,
                                      "operation", "gegl:color",
                                      "value", color_white,
                                      NULL);
  translate    = gegl_node_new_child (gegl,
                                      "operation", "gegl:translate",
                                      "x", -50.0,
                                      "y", -20.0,
                                      NULL);
  over         = gegl_node_new_child (gegl,
                                      "operation", "gegl:over",
                                      NULL);
  black        = gegl_node_new_child (gegl,
                                      "operation", "gegl:color",
                                      "value", color_black,
                                      NULL);
  crop         = gegl_node_new_child (gegl,
                                      "operation", "gegl:crop",
                                      "x", 10.0,
                                      "y", 10.0,
                                      "width", 100.0,
                                      "height", 100.0,
                                      NULL);
  sink         = gegl_node_new_child (gegl,
                                      "operation", "gegl:buffer-sink",
                                      NULL);

  /* We build our graph for processing complexity, not for compositing
   * complexity
   */
  gegl_node_link_many (black, over, sink, NULL);
  gegl_node_link_many (white, crop, translate, NULL);
  gegl_node_connect_to (translate, "output",  over, "aux");

  /* Create a processor */
  processor = gegl_node_new_processor (sink, NULL);

  /* Do the tests */
  if (!test_change_processor_rect_do_test (processor, &rect1, sink))
    {
      g_printerr ("test-change-processor-rect: First compare failed\n");
      result = FAILURE;
      goto abort;
    }
  if (!test_change_processor_rect_do_test (processor, &rect2, sink))
    {
      g_printerr ("test-change-processor-rect: Second compare failed\n");
      result = FAILURE;
      goto abort;
    }
  if (!test_change_processor_rect_do_test (processor, &rect3, sink))
    {
      g_printerr ("test-change-processor-rect: Third compare failed\n");
      result = FAILURE;
      goto abort;
    }
  if (!test_change_processor_rect_do_test (processor, &rect4, sink))
    {
      g_printerr ("test-change-processor-rect: Fourth compare failed\n");
      result = FAILURE;
      goto abort;
    }

  /* Cleanup */
 abort:
  g_object_unref (processor);
  g_object_unref (color_white);
  g_object_unref (color_black);
  g_object_unref (gegl);
  gegl_exit ();

  return result;
}
Esempio n. 20
0
gint
main (gint    argc,
      gchar **argv)
{
  GeglRectangle terrain_rect;
  if (argc < 2)
    usage();

  gegl_init (&argc, &argv);
  parse_args (argc, argv);

  gegl_decode = gegl_node_new ();

  store = gegl_node_new_child (gegl_decode,
                               "operation", "gegl:buffer-sink",
                               "buffer", &video_frame, NULL);
  load = gegl_node_new_child (gegl_decode,
                              "operation", "gegl:ff-load",
                              "frame", 0,
                              "path", video_path,
                              NULL);
  gegl_node_link_many (load, store, NULL);

  decode_frame_no (0); /* we issue a processing/decoding of a frame - to get metadata */
  {
    gegl_node_get (load, "frame-rate", &frame_rate, NULL);
    total_frames = 0; gegl_node_get (load, "frames", &total_frames, NULL);

    if (frame_end == 0)
      frame_end = total_frames;
  }

  if (horizontal)
   terrain_rect = (GeglRectangle){0, 0,
                                frame_end - frame_start + 1,
                                1024};
  else
   terrain_rect = (GeglRectangle){0, 0,
                                1024,
                                frame_end - frame_start + 1};

  if (input_analysis_path && g_file_test (input_analysis_path, G_FILE_TEST_IS_REGULAR))
  {
    GeglNode *load_graph = gegl_node_new ();
    GeglNode *load = gegl_node_new_child (load_graph, "operation", "gegl:load", "path", input_analysis_path, NULL);
    GeglNode *store = gegl_node_new_child (load_graph, "operation",
                                           "gegl:buffer-sink",
                                           "buffer", &terrain, NULL);
    gegl_node_link_many (load, store, NULL);
    gegl_node_process (store);
    g_object_unref (load_graph);

    frame_end = frame_start + gegl_buffer_get_extent (terrain)->height;
    /* the last frame aavilavle for analysis is the last one loaded rom cache,.. perhaps with some timeout */
  }
  else
  {
    terrain = gegl_buffer_new (&terrain_rect, babl_format ("RGBA u8"));
    {
      gint frame;
      gint max_buf_pos = 0;
      for (frame = frame_start; frame <= frame_end; frame++)
        {
          FrameInfo info = {{0}};
          uint8_t buffer[4096] = {0,};
          int buffer_pos = 0;
          GeglRectangle terrain_row;
          char *p = format;
          GString *word = g_string_new ("");

          if (show_progress)
          {
            double percent_full = 100.0 * (frame-frame_start) / (frame_end-frame_start);
            double percent_time = time_out?100.0 * babl_ticks()/1000.0/1000.0 / time_out:0.0;
            fprintf (stdout, "\r%2.1f%% %i/%i (%i)",
                     percent_full>percent_time?percent_full:percent_time,
                     frame-frame_start,
                     frame_end-frame_start,
                     frame);
            fflush (stdout);
          }

          if (horizontal)
            terrain_row = (GeglRectangle){frame-frame_start, 0, 1, 1024};
          else
            terrain_row = (GeglRectangle){0, frame-frame_start, 1024, 1};

          decode_frame_no (frame);

          //for (int i=0;i<(signed)sizeof(buffer);i++)buffer[i]=0;

          while (*p == ' ') p++;
          for (p= format;p==format || p[-1]!='\0';p++)
          {
            if (*p != '\0' && *p != ' ')
              {
                g_string_append_c (word, *p);
              }
            else
              {
               if (!strcmp (word->str, "histogram"))
               {
                 record_pix_stats (video_frame, previous_video_frame,
                                   &(info.rgb_hist[0]),
                                   &(info.rgb_square_diff)[0]);
                 for (int i = 0; i < NEGL_RGB_HIST_SLOTS; i++)
                 {
                  buffer[buffer_pos] = info.rgb_hist[i];
                  buffer_pos++;
                 }
                 for (int i = 0; i < 3; i++)
                 {
                   buffer[buffer_pos] = info.rgb_square_diff[i];
                   buffer_pos++;
                 }
               }
               else if (!strcmp (word->str, "mid-row"))
               {
                  int samples = NEGL_RGB_HEIGHT;
                  if (p[1] >= '0' && p[1] <= '9')
                  {
                    samples = g_strtod (&p[1], &p);
                  }
                  buffer_pos += extract_mid_row (video_frame, &(buffer)[buffer_pos], samples);
               }
               else if (!strcmp (word->str, "mid-col"))
               {
                  int samples = NEGL_RGB_HEIGHT;
                  if (p[1] >= '0' && p[1] <= '9')
                  {
                    samples = g_strtod (&p[1], &p);
                  }
                  buffer_pos += extract_mid_col (video_frame, &(buffer)[buffer_pos], samples);
               }
               else if (!strcmp (word->str, "thumb"))
               {
                  int samples  = NEGL_RGB_THEIGHT;
                  int samples2;

                  if (p[1] >= '0' && p[1] <= '9')
                  {
                    samples = g_strtod (&p[1], &p);
                  }

                  if (horizontal)
                    samples2 = samples * gegl_buffer_get_width (video_frame)/gegl_buffer_get_height(video_frame);
                  else
                    samples2 = samples * gegl_buffer_get_height (video_frame)/gegl_buffer_get_width(video_frame);

                  buffer_pos += extract_thumb (video_frame, &(buffer)[buffer_pos], samples, samples2);
               }
               else if (!strcmp (word->str, "audio"))
               {
                  int dups = 1;
                  GeglAudioFragment *audio = NULL;

                  if (p[1] >= '0' && p[1] <= '9')
                  {
                    dups = g_strtod (&p[1], &p);
                  }
                 gegl_node_get (load, "audio", &audio, NULL);
                 if (audio)
                  {
                    extract_audio_energy (audio, &buffer[buffer_pos], dups);
                    g_object_unref (audio);
                  }
                 buffer_pos+=3 * dups;
               }
               g_string_assign (word, "");
            }
          }
          max_buf_pos = buffer_pos;
          g_string_free (word, TRUE);

          gegl_buffer_set (terrain, &terrain_row, 0, babl_format("RGB u8"),
                           buffer,
                           GEGL_AUTO_ROWSTRIDE);

          if (time_out > 1.0 &&
              babl_ticks()/1000.0/1000.0 > time_out)
            {
               frame_end = frame;
               if (horizontal)
                 terrain_rect.width = frame_end - frame_start + 1;
               else
                 terrain_rect.height = frame_end - frame_start + 1;
          //     gegl_buffer_set_extent (terrain, &terrain_rect);
            }

          if (horizontal)
            terrain_rect.height = max_buf_pos/3;
          else
            terrain_rect.width = max_buf_pos/3;
          gegl_buffer_set_extent (terrain, &terrain_rect);
        }
        if (show_progress)
        {
          fprintf (stdout, "\n");
          fflush (stdout);
        }
    }

    if (output_analysis_path)
    {
      GeglNode *save_graph = gegl_node_new ();
      GeglNode *readbuf = gegl_node_new_child (save_graph, "operation", "gegl:buffer-source", "buffer", terrain, NULL);
      GeglNode *save = gegl_node_new_child (save_graph, "operation", "gegl:png-save",
        "path", output_analysis_path, NULL);
        gegl_node_link_many (readbuf, save, NULL);
      gegl_node_process (save);
      g_object_unref (save_graph);
    }
  }

  if (thumb_path)
  {
    GeglNode *save_graph = gegl_node_new ();
    find_best_thumb ();
    if (frame_thumb != 0)
      decode_frame_no (frame_thumb-1);
    decode_frame_no (frame_thumb);
    {
    GeglNode *readbuf = gegl_node_new_child (save_graph, "operation", "gegl:buffer-source", "buffer", video_frame, NULL);
    GeglNode *save = gegl_node_new_child (save_graph, "operation", "gegl:png-save",
      "path", thumb_path, NULL);
      gegl_node_link_many (readbuf, save, NULL);
    gegl_node_process (save);
    g_object_unref (save_graph);
    }
  }

  if (video_frame)
    g_object_unref (video_frame);
  video_frame = NULL;
  if (previous_video_frame)
    g_object_unref (previous_video_frame);
  previous_video_frame = NULL;
  if (terrain)
    g_object_unref (terrain);
  terrain = NULL;
  g_object_unref (gegl_decode);

  gegl_exit ();

  return 0;
}
Esempio n. 21
0
/**
 * gimp_seamless_clone_tool_create_render_node:
 * @sc: The GimpSeamlessCloneTool to initialize
 *
 * This function creates a Gegl node graph of the composition which is
 * needed to render the drawable. The graph should have an "input" pad
 * which will receive the drawable on which the preview is applied, and
 * it should also have an "output" pad to which the final result will be
 * rendered
 */
static void
gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sc)
{
  /* Here is a textual description of the graph we are going to create:
   *
   * <input>  <- drawable
   * +--+--------------------------+
   * |  |output                    |
   * |  |                          |
   * |  | <buffer-source> <- paste |
   * |  |       |output            |
   * |  |       |                  |
   * |  |input  |aux               |
   * |<seamless-paste-render>      |
   * |    |output                  |
   * |    |                        |
   * |    |input                   |
   * +----+------------------------+
   *   <output>
   */
  GimpSeamlessCloneOptions *options = GIMP_SEAMLESS_CLONE_TOOL_GET_OPTIONS (sc);
  GeglNode *node;
  GeglNode *op, *paste, *overlay;
  GeglNode *input, *output;

  node = gegl_node_new ();

  input  = gegl_node_get_input_proxy  (node, "input");
  output = gegl_node_get_output_proxy (node, "output");

  paste = gegl_node_new_child (node,
                               "operation", "gegl:buffer-source",
                               "buffer",    sc->paste,
                               NULL);

  op = gegl_node_new_child (node,
                            "operation",         "gegl:seamless-clone",
                            "max-refine-scale",  options->max_refine_scale,
                            NULL);

  overlay = gegl_node_new_child (node,
                                 "operation", "svg:dst-over",
                                 NULL);

  gegl_node_connect_to (input,   "output",
                        op,      "input");

  gegl_node_connect_to (paste,   "output",
                        op,      "aux");

  gegl_node_connect_to (op,      "output",
                        overlay, "input");

  gegl_node_connect_to (input,   "output",
                        overlay, "aux");

  gegl_node_connect_to (overlay, "output",
                        output,  "input");

  sc->render_node = node;
  sc->sc_node     = op;
}
Esempio n. 22
0
static gboolean
test_scale (const gdouble scale, const gint x, const gint y, const Babl *format)
{
  GeglNode *checkerboard;
  GeglBuffer *tmp_buffer;
  gboolean result = FALSE;

  const gint bpp = babl_format_get_bytes_per_pixel (format);
  const gint scaled_width  = 32;
  const gint scaled_height = 32;
  gint pad = 32;

  guchar *output_buffer_scaled = gegl_malloc (scaled_width * scaled_height * bpp);
  guchar *output_node_scaled   = gegl_malloc (scaled_width * scaled_height * bpp);

  if (2 / scale > pad)
    pad = 2 / scale + 2;

  tmp_buffer = gegl_buffer_new (GEGL_RECTANGLE ((x / scale) - pad,
                                                (y / scale) - pad,
                                                (scaled_width / scale) + (2 * pad),
                                                (scaled_height / scale) + (2 * pad)),
                                babl_format ("RGBA float"));

  checkerboard = gegl_node_new_child(NULL,
                                     "operation", "gegl:checkerboard",
                                     "x", 16,
                                     "y", 16,
                                     NULL);

  gegl_node_blit_buffer (checkerboard,
                         tmp_buffer,
                         NULL,
                         0,
                         GEGL_ABYSS_NONE);

  gegl_buffer_get (tmp_buffer,
                   GEGL_RECTANGLE (x, y, scaled_width, scaled_height),
                   scale,
                   format,
                   output_buffer_scaled,
                   GEGL_AUTO_ROWSTRIDE,
                   GEGL_ABYSS_NONE);

  g_object_unref (checkerboard);
  g_object_unref (tmp_buffer);

  /* Re-create the node so we don't hit its cache */
  checkerboard = gegl_node_new_child(NULL,
                                     "operation", "gegl:checkerboard",
                                     "x", 16,
                                     "y", 16,
                                     NULL);

  gegl_node_blit (checkerboard,
                  scale,
                  GEGL_RECTANGLE (x, y, scaled_width, scaled_height),
                  format,
                  output_node_scaled,
                  GEGL_AUTO_ROWSTRIDE,
                  0);

  g_object_unref (checkerboard);

  if (0 == memcmp (output_buffer_scaled, output_node_scaled, scaled_width * scaled_height * bpp))
    {
      printf (".");
      fflush(stdout);
      result = TRUE;
    }
  else
    {
      printf ("\n scale=%.4f at %d, %d in \"%s\" ... FAIL\n", scale, x, y, babl_get_name (format));
      result = FALSE;
    }

  gegl_free (output_buffer_scaled);
  gegl_free (output_node_scaled);

  return result;
}
Esempio n. 23
0
gint
main (gint    argc,
      gchar **argv)
{
  g_thread_init (NULL);
  gtk_init (&argc, &argv);
  gegl_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "GEGL destructive painter");

  if (argv[1] == NULL)
    {
      GeglRectangle rect = {0, 0, 512, 512};
      gpointer buf;

      /* XXX: for best overall performance, this format should probably
       * be RaGaBaA float, overeager in-place processing code makes that fail though.
       */
      buffer = gegl_buffer_new (&rect, babl_format("R'G'B' u8"));
      /* it would be useful to have a programmatic way of doing this, filling
       * with a given pixel value
       */
      buf    = gegl_buffer_linear_open (buffer, NULL, NULL, babl_format ("Y' u8"));
      memset (buf, 255, 512 * 512);
      gegl_buffer_linear_close (buffer, buf);
    }
  else
    {
      buffer = gegl_buffer_open (argv[1]);
    }

  gegl = gegl_node_new ();
  {
    GeglNode *loadbuf = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", buffer, NULL);
    out  = gegl_node_new_child (gegl, "operation", "gegl:nop", NULL);

    gegl_node_link_many (loadbuf, out, NULL);

    view = g_object_new (GEGL_TYPE_VIEW, "node", out, NULL);
    top  = loadbuf;
  }

  g_signal_connect (GTK_OBJECT (view), "motion-notify-event",
                    (GCallback) paint_motion, NULL);
  g_signal_connect (GTK_OBJECT (view), "button-press-event",
                    (GCallback) paint_press, NULL);
  g_signal_connect (GTK_OBJECT (view), "button-release-event",
                    (GCallback) paint_release, NULL);
  gtk_widget_add_events (view, GDK_BUTTON_RELEASE_MASK);

  gtk_container_add (GTK_CONTAINER (window), view);
  gtk_widget_set_size_request (view, 512, 512);

  g_signal_connect (G_OBJECT (window), "delete-event",
                    G_CALLBACK (gtk_main_quit), window);
  gtk_widget_show_all (window);

  gtk_main ();
  g_object_unref (gegl);
  gegl_buffer_destroy (buffer);

  gegl_exit ();
  return 0;
}
Esempio n. 24
0
void
gimp_operation_tool_set_operation (GimpOperationTool *tool,
                                   const gchar       *operation,
                                   const gchar       *undo_desc,
                                   const gchar       *icon_name)
{
  GimpImageMapTool *im_tool;

  g_return_if_fail (GIMP_IS_OPERATION_TOOL (tool));
  g_return_if_fail (operation != NULL);

  im_tool = GIMP_IMAGE_MAP_TOOL (tool);

  if (tool->operation)
    g_free (tool->operation);

  if (tool->undo_desc)
    g_free (tool->undo_desc);

  if (tool->icon_name)
    g_free (tool->icon_name);

  tool->operation = g_strdup (operation);
  tool->undo_desc = g_strdup (undo_desc);
  tool->icon_name = g_strdup (icon_name);

  if (tool->aux_input)
    {
      g_object_unref (tool->aux_input);
      tool->aux_input = NULL;
    }

  if (tool->aux2_input)
    {
      g_object_unref (tool->aux2_input);
      tool->aux2_input = NULL;
    }

  gimp_image_map_tool_get_operation (im_tool);

  if (undo_desc)
    GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name = "yes"; /* XXX hack */
  else
    GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name = NULL; /* XXX hack */

  if (tool->aux_input_box)
    {
      gtk_widget_destroy (tool->aux_input_box);
      tool->aux_input_button = NULL;
      tool->aux_input_box    = NULL;
    }

  if (tool->aux2_input_box)
    {
      gtk_widget_destroy (tool->aux2_input_box);
      tool->aux2_input_button = NULL;
      tool->aux2_input_box    = NULL;
    }

  if (tool->options_gui)
    {
      gtk_widget_destroy (tool->options_gui);
      tool->options_gui = NULL;

      if (im_tool->active_picker)
        {
          im_tool->active_picker = NULL;
          gimp_color_tool_disable (GIMP_COLOR_TOOL (tool));
        }
    }

  if (gegl_node_has_pad (im_tool->operation, "aux"))
    {
      GimpContext *context;
      GtkWidget   *label;

      tool->aux_input = gegl_node_new_child (NULL,
                                             "operation", "gegl:buffer-source",
                                             NULL);

      gegl_node_connect_to (tool->aux_input,    "output",
                            im_tool->operation, "aux");

      context = GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool));

      tool->aux_input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);

      label = gtk_label_new_with_mnemonic (_("_Aux Input"));
      gtk_box_pack_start (GTK_BOX (tool->aux_input_box), label,
                          FALSE, FALSE, 0);
      gtk_widget_show (label);

      tool->aux_input_button =
        gimp_pickable_button_new (context, GIMP_VIEW_SIZE_LARGE, 1);
      gtk_box_pack_start (GTK_BOX (tool->aux_input_box),
                          tool->aux_input_button, FALSE, FALSE, 0);
      gtk_widget_show (tool->aux_input_button);

      gtk_label_set_mnemonic_widget (GTK_LABEL (label),
                                     tool->aux_input_button);

      if (tool->options_box)
        {
          gtk_box_pack_start (GTK_BOX (tool->options_box), tool->aux_input_box,
                              FALSE, FALSE, 0);
          gtk_widget_show (tool->aux_input_box);
        }

      g_signal_connect_object (tool->aux_input_button, "notify::pickable",
                               G_CALLBACK (gimp_operation_tool_aux_notify),
                               tool->aux_input, 0);
    }

  if (gegl_node_has_pad (im_tool->operation, "aux2"))
    {
      GimpContext *context;
      GtkWidget   *label;

      tool->aux2_input = gegl_node_new_child (NULL,
                                             "operation", "gegl:buffer-source",
                                             NULL);

      gegl_node_connect_to (tool->aux2_input,   "output",
                            im_tool->operation, "aux2");

      context = GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool));

      tool->aux2_input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);

      label = gtk_label_new_with_mnemonic (_("_Aux2 Input"));
      gtk_box_pack_start (GTK_BOX (tool->aux2_input_box), label,
                          FALSE, FALSE, 0);
      gtk_widget_show (label);

      tool->aux2_input_button =
        gimp_pickable_button_new (context, GIMP_VIEW_SIZE_LARGE, 1);
      gtk_box_pack_start (GTK_BOX (tool->aux2_input_box),
                          tool->aux2_input_button, FALSE, FALSE, 0);
      gtk_widget_show (tool->aux2_input_button);

      gtk_label_set_mnemonic_widget (GTK_LABEL (label),
                                     tool->aux2_input_button);

      if (tool->options_box)
        {
          gtk_box_pack_start (GTK_BOX (tool->options_box), tool->aux2_input_box,
                              FALSE, FALSE, 0);
          gtk_widget_show (tool->aux2_input_box);
        }

      g_signal_connect_object (tool->aux2_input_button, "notify::pickable",
                               G_CALLBACK (gimp_operation_tool_aux_notify),
                               tool->aux2_input, 0);
    }

  if (im_tool->config)
    {
      tool->options_gui =
        gimp_prop_gui_new (G_OBJECT (im_tool->config),
                           G_TYPE_FROM_INSTANCE (im_tool->config),
                           GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool)),
                           (GimpCreatePickerFunc) gimp_image_map_tool_add_color_picker,
                           tool);

      if (tool->options_box)
        {
          gtk_box_pack_start (GTK_BOX (tool->options_box), tool->options_gui,
                              FALSE, FALSE, 0);
          gtk_widget_show (tool->options_gui);
        }
    }

  if (im_tool->gui)
    {
      if (undo_desc)
        gimp_tool_gui_set_description (im_tool->gui, undo_desc);

      if (icon_name)
        gimp_tool_gui_set_icon_name (im_tool->gui, icon_name);
    }

  if (GIMP_TOOL (tool)->drawable)
    {
      gimp_operation_tool_sync_op (tool, GIMP_TOOL (tool)->drawable);
      gimp_image_map_tool_preview (im_tool);
    }
}
static void
gimp_n_point_deformation_tool_start (GimpNPointDeformationTool *npd_tool,
                                     GimpDisplay               *display)
{
  GimpTool                     *tool = GIMP_TOOL (npd_tool);
  GimpNPointDeformationOptions *npd_options;
  GimpImage                    *image;
  GeglBuffer                   *source_buffer;
  GeglBuffer                   *preview_buffer;
  NPDModel                     *model;

  npd_options = GIMP_N_POINT_DEFORMATION_TOOL_GET_OPTIONS (npd_tool);

  gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);

  image = gimp_display_get_image (display);

  tool->display  = display;
  tool->drawable = gimp_image_get_active_drawable (image);

  npd_tool->active = TRUE;

  /* create GEGL graph */
  source_buffer  = gimp_drawable_get_buffer (tool->drawable);

  preview_buffer = gegl_buffer_new (gegl_buffer_get_extent (source_buffer),
                                    babl_format ("cairo-ARGB32"));

  npd_tool->graph    = gegl_node_new ();

  npd_tool->source   = gegl_node_new_child (npd_tool->graph,
                                            "operation", "gegl:buffer-source",
                                            "buffer",    source_buffer,
                                            NULL);
  npd_tool->npd_node = gegl_node_new_child (npd_tool->graph,
                                            "operation", "gegl:npd",
                                            NULL);
  npd_tool->sink     = gegl_node_new_child (npd_tool->graph,
                                            "operation", "gegl:write-buffer",
                                            "buffer",    preview_buffer,
                                            NULL);

  gegl_node_link_many (npd_tool->source,
                       npd_tool->npd_node,
                       npd_tool->sink,
                       NULL);

  /* initialize some options */
  g_object_set (G_OBJECT (npd_options), "mesh-visible", TRUE, NULL);
  gimp_n_point_deformation_options_set_sensitivity (npd_options, TRUE);

  /* compute and get model */
  gegl_node_process (npd_tool->npd_node);
  gegl_node_get (npd_tool->npd_node, "model", &model, NULL);

  npd_tool->model          = model;
  npd_tool->preview_buffer = preview_buffer;
  npd_tool->selected_cp    = NULL;
  npd_tool->hovering_cp    = NULL;
  npd_tool->selected_cps   = NULL;
  npd_tool->rubber_band    = FALSE;
  npd_tool->lattice_points = g_new (GimpVector2,
                                    5 * model->hidden_model->num_of_bones);

  gimp_item_get_offset (GIMP_ITEM (tool->drawable),
                        &npd_tool->offset_x, &npd_tool->offset_y);
  gimp_npd_debug (("offset: %f %f\n", npd_tool->offset_x, npd_tool->offset_y));

  gimp_draw_tool_start (GIMP_DRAW_TOOL (npd_tool), display);

  gimp_n_point_deformation_tool_perform_deformation (npd_tool);

  /* hide original image */
  gimp_item_set_visible (GIMP_ITEM (tool->drawable), FALSE, FALSE);
  gimp_image_flush (image);

  /* create and start a deformation thread */
  npd_tool->deform_thread =
    g_thread_new ("deform thread",
                  (GThreadFunc) gimp_n_point_deformation_tool_deform_thread_func,
                  npd_tool);

  /* create and start canvas update timeout */
  npd_tool->draw_timeout_id =
    gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT_IDLE,
                                  GIMP_NPD_DRAW_INTERVAL,
                                  (GSourceFunc) gimp_n_point_deformation_tool_canvas_update_timeout,
                                  npd_tool,
                                  NULL);
}
int main(int argc, char *argv[])
{
  gint           result       = SUCCESS;
  GeglRectangle  rect1        = { 0, 0, 1, 1 };
  GeglRectangle  rect2        = { 1, 0, 1, 1 };
  GeglRectangle  rect3        = { 1, 1, 1, 1 };
  GeglRectangle  rect4        = { 0, 1, 1, 1 };
  GeglColor     *common_color = NULL;
  GeglNode      *gegl         = NULL;
  GeglNode      *color        = NULL;
  GeglNode      *layer        = NULL;
  GeglNode      *text         = NULL;
  GeglNode      *sink         = NULL;
  GeglProcessor *processor    = NULL;

  /* Convenient line to keep around:
  g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
   */

  g_thread_init (NULL);
  gegl_init (&argc, &argv);

  common_color = gegl_color_new ("rgb(1.0, 1.0, 1.0)");

  gegl         = gegl_node_new ();
  color        = gegl_node_new_child (gegl,
                                      "operation", "gegl:color",
                                      "value", common_color,
                                      NULL);
  layer        = gegl_node_new_child (gegl,
                                      "operation", "gegl:layer",
                                      "x", 0.0,
                                      "y", 0.0,
                                      NULL);
  text         = gegl_node_new_child (gegl,
                                      "operation", "gegl:text",
                                      "color", common_color,
                                      "string", "█████████████████████████",
                                      "size", 200.0,
                                      NULL);
  sink         = gegl_node_new_child (gegl,
                                      "operation", "gegl:buffer-sink",
                                      NULL);

  /* We build our graph for processing complexity, not for compositing
   * complexity
   */
  gegl_node_link_many (color, layer, sink, NULL);
  gegl_node_connect_to (text, "output",  layer, "aux");

  /* Create a processor */
  processor = gegl_node_new_processor (sink, NULL);

  /* Do the tests */
  if (!test_change_processor_rect_do_test (processor, &rect1, sink))
    {
      g_printerr ("test-change-processor-rect: First compare failed\n");
      result = FAILURE;
      goto abort;
    }
  if (!test_change_processor_rect_do_test (processor, &rect2, sink))
    {
      g_printerr ("test-change-processor-rect: Second compare failed\n");
      result = FAILURE;
      goto abort;
    }
  if (!test_change_processor_rect_do_test (processor, &rect3, sink))
    {
      g_printerr ("test-change-processor-rect: Third compare failed\n");
      result = FAILURE;
      goto abort;
    }
  if (!test_change_processor_rect_do_test (processor, &rect4, sink))
    {
      g_printerr ("test-change-processor-rect: Fourth compare failed\n");
      result = FAILURE;
      goto abort;
    }

  /* Cleanup */
 abort:
  g_object_unref (processor);
  g_object_unref (common_color);
  g_object_unref (gegl);
  gegl_exit ();

  return result;
}
Esempio n. 27
0
GimpApplicator *
gimp_applicator_new (GeglNode *parent)
{
  GimpApplicator *applicator;

  g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL);

  applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL);

  if (parent)
    applicator->node = g_object_ref (parent);
  else
    applicator->node = gegl_node_new ();

  applicator->input_node =
    gegl_node_get_input_proxy  (applicator->node, "input");

  applicator->aux_node =
    gegl_node_get_input_proxy  (applicator->node, "aux");

  applicator->output_node =
    gegl_node_get_output_proxy (applicator->node, "output");

  applicator->mode_node = gegl_node_new_child (applicator->node,
                                               "operation", "gimp:normal",
                                               NULL);

  gimp_gegl_mode_node_set_mode (applicator->mode_node,
                                applicator->paint_mode,
                                applicator->blend_space,
                                applicator->composite_space,
                                applicator->composite_mode);
  gimp_gegl_mode_node_set_opacity (applicator->mode_node,
                                   applicator->opacity);

  gegl_node_connect_to (applicator->input_node, "output",
                        applicator->mode_node,  "input");

  applicator->apply_offset_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:translate",
                         NULL);

  gegl_node_link_many (applicator->aux_node,
                       applicator->apply_offset_node,
                       NULL);

  gegl_node_connect_to (applicator->apply_offset_node, "output",
                        applicator->mode_node,         "aux");

  applicator->mask_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:buffer-source",
                         NULL);

  applicator->mask_offset_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:translate",
                         NULL);

  gegl_node_connect_to (applicator->mask_node,        "output",
                        applicator->mask_offset_node, "input");
  /* don't connect the the mask offset node to mode's aux2 yet */

  applicator->affect_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gimp:mask-components",
                         "mask",      applicator->affect,
                         NULL);

  applicator->convert_format_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:nop",
                         NULL);

  applicator->cache_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:nop",
                         NULL);

  applicator->crop_node =
    gegl_node_new_child (applicator->node,
                         "operation", "gegl:nop",
                         NULL);

  gegl_node_link_many (applicator->input_node,
                       applicator->affect_node,
                       applicator->convert_format_node,
                       applicator->cache_node,
                       applicator->crop_node,
                       applicator->output_node,
                       NULL);

  gegl_node_connect_to (applicator->mode_node,   "output",
                        applicator->affect_node, "aux");

  return applicator;
}
Esempio n. 28
0
void
gimp_gegl_apply_operation (GeglBuffer          *src_buffer,
                           GimpProgress        *progress,
                           const gchar         *undo_desc,
                           GeglNode            *operation,
                           GeglBuffer          *dest_buffer,
                           const GeglRectangle *dest_rect)
{
  GeglNode      *gegl;
  GeglNode      *dest_node;
  GeglRectangle  rect = { 0, };
  gdouble        value;
  gboolean       progress_active = FALSE;

  g_return_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer));
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
  g_return_if_fail (GEGL_IS_NODE (operation));
  g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));

  if (dest_rect)
    {
      rect = *dest_rect;
    }
  else
    {
      rect = *GEGL_RECTANGLE (0, 0, gegl_buffer_get_width  (dest_buffer),
                                    gegl_buffer_get_height (dest_buffer));
    }

  gegl = gegl_node_new ();

  if (! gegl_node_get_parent (operation))
    gegl_node_add_child (gegl, operation);

  if (src_buffer && gegl_node_has_pad (operation, "input"))
    {
      GeglNode *src_node;

      /* dup() because reading and writing the same buffer doesn't
       * work with area ops when using a processor. See bug #701875.
       */
      if (progress && (src_buffer == dest_buffer))
        src_buffer = gegl_buffer_dup (src_buffer);
      else
        g_object_ref (src_buffer);

      src_node = gegl_node_new_child (gegl,
                                      "operation", "gegl:buffer-source",
                                      "buffer",    src_buffer,
                                      NULL);

      g_object_unref (src_buffer);

      gegl_node_connect_to (src_node,  "output",
                            operation, "input");
    }

  dest_node = gegl_node_new_child (gegl,
                                   "operation", "gegl:write-buffer",
                                   "buffer",    dest_buffer,
                                   NULL);


  gegl_node_connect_to (operation, "output",
                        dest_node, "input");

  if (progress)
    {
      GeglProcessor *processor;

      processor = gegl_node_new_processor (dest_node, &rect);

      progress_active = gimp_progress_is_active (progress);

      if (progress_active)
        {
          if (undo_desc)
            gimp_progress_set_text (progress, undo_desc);
        }
      else
        {
          gimp_progress_start (progress, undo_desc, FALSE);
        }

      while (gegl_processor_work (processor, &value))
        gimp_progress_set_value (progress, value);

      g_object_unref (processor);
    }
  else
    {
      gegl_node_blit (dest_node, 1.0, &rect,
                      NULL, NULL, 0, GEGL_BLIT_DEFAULT);
    }

  g_object_unref (gegl);

  if (progress && ! progress_active)
    gimp_progress_end (progress);
}
Esempio n. 29
0
static GeglBuffer *
gradient_precalc_shapeburst (GimpImage           *image,
                             GimpDrawable        *drawable,
                             const GeglRectangle *region,
                             gdouble              dist,
                             GimpProgress        *progress)
{
  GimpChannel *mask;
  GeglBuffer  *dist_buffer;
  GeglBuffer  *temp_buffer;
  GeglNode    *shapeburst;
  gdouble      max;
  gfloat       max_iteration;

  gimp_progress_set_text (progress, _("Calculating distance map"));

  /*  allocate the distance map  */
  dist_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                 region->width, region->height),
                                 babl_format ("Y float"));

  /*  allocate the selection mask copy
   *  XXX: its format should be the same of gimp:shapeburst input buffer
   *       porting the op to 'float' should be reflected here as well
   */
  temp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                 region->width, region->height),
                                 babl_format ("Y u8"));

  mask = gimp_image_get_mask (image);

  /*  If the image mask is not empty, use it as the shape burst source  */
  if (! gimp_channel_is_empty (mask))
    {
      gint x, y, width, height;
      gint off_x, off_y;

      gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      /*  copy the mask to the temp mask  */
      gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
                        GEGL_RECTANGLE (x + off_x, y + off_y, width, height),
                        temp_buffer,
                        GEGL_RECTANGLE (0, 0, 0, 0));
    }
  else
    {
      /*  If the intended drawable has an alpha channel, use that  */
      if (gimp_drawable_has_alpha (drawable))
        {
          const Babl *component_format;

          component_format = babl_format ("A u8");

          /*  extract the aplha into the temp mask  */
          gegl_buffer_set_format (temp_buffer, component_format);
          gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
                            GEGL_RECTANGLE (region->x, region->y,
                                            region->width, region->height),
                            temp_buffer,
                            GEGL_RECTANGLE (0, 0, 0, 0));
          gegl_buffer_set_format (temp_buffer, NULL);
        }
      else
        {
          GeglColor *white = gegl_color_new ("white");

          /*  Otherwise, just fill the shapeburst to white  */
          gegl_buffer_set_color (temp_buffer, NULL, white);
          g_object_unref (white);
        }
    }

  shapeburst = gegl_node_new_child (NULL,
                                    "operation", "gimp:shapeburst",
                                    NULL);

  gimp_gegl_progress_connect (shapeburst, progress, NULL);

  gimp_gegl_apply_operation (temp_buffer, NULL, NULL,
                             shapeburst,
                             dist_buffer, NULL);

  gegl_node_get (shapeburst, "max-iterations", &max, NULL);

  g_object_unref (shapeburst);

  max_iteration = max;

  g_object_unref (temp_buffer);

  /*  normalize the shapeburst with the max iteration  */
  if (max_iteration > 0)
    {
      GeglBufferIterator *iter;

      iter = gegl_buffer_iterator_new (dist_buffer, NULL, 0, NULL,
                                       GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          gint    count = iter->length;
          gfloat *data  = iter->data[0];

          while (count--)
            *data++ /= max_iteration;
        }
    }

  return dist_buffer;
}
Esempio n. 30
0
static GeglBuffer *
gradient_precalc_shapeburst (GimpImage           *image,
                             GimpDrawable        *drawable,
                             const GeglRectangle *region,
                             gdouble              dist,
                             GimpProgress        *progress)
{
  GimpChannel *mask;
  GeglBuffer  *dist_buffer;
  GeglBuffer  *temp_buffer;
  GeglNode    *shapeburst;

  gimp_progress_set_text (progress, _("Calculating distance map"));

  /*  allocate the distance map  */
  dist_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                 region->width, region->height),
                                 babl_format ("Y float"));

  /*  allocate the selection mask copy
   */
  temp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                 region->width, region->height),
                                 babl_format ("Y float"));

  mask = gimp_image_get_mask (image);

  /*  If the image mask is not empty, use it as the shape burst source  */
  if (! gimp_channel_is_empty (mask))
    {
      gint x, y, width, height;
      gint off_x, off_y;

      gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      /*  copy the mask to the temp mask  */
      gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
                        GEGL_RECTANGLE (x + off_x, y + off_y, width, height),
                        temp_buffer,
                        GEGL_RECTANGLE (0, 0, 0, 0));
    }
  else
    {
      /*  If the intended drawable has an alpha channel, use that  */
      if (gimp_drawable_has_alpha (drawable))
        {
          const Babl *component_format;

          component_format = babl_format ("A float");

          /*  extract the aplha into the temp mask  */
          gegl_buffer_set_format (temp_buffer, component_format);
          gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
                            GEGL_RECTANGLE (region->x, region->y,
                                            region->width, region->height),
                            temp_buffer,
                            GEGL_RECTANGLE (0, 0, 0, 0));
          gegl_buffer_set_format (temp_buffer, NULL);
        }
      else
        {
          GeglColor *white = gegl_color_new ("white");

          /*  Otherwise, just fill the shapeburst to white  */
          gegl_buffer_set_color (temp_buffer, NULL, white);
          g_object_unref (white);
        }
    }

  shapeburst = gegl_node_new_child (NULL,
                                    "operation", "gimp:shapeburst",
                                    "normalize", TRUE,
                                    NULL);

  gimp_gegl_progress_connect (shapeburst, progress, NULL);

  gimp_gegl_apply_operation (temp_buffer, NULL, NULL,
                             shapeburst,
                             dist_buffer, NULL);

  g_object_unref (shapeburst);

  g_object_unref (temp_buffer);

  return dist_buffer;
}