Beispiel #1
0
GimpPlugIn *
gimp_plug_in_new (GimpPlugInManager   *manager,
                  GimpContext         *context,
                  GimpProgress        *progress,
                  GimpPlugInProcedure *procedure,
                  GFile               *file)
{
  GimpPlugIn *plug_in;

  g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL);
  g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
  g_return_val_if_fail (procedure == NULL ||
                        GIMP_IS_PLUG_IN_PROCEDURE (procedure), NULL);
  g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
  g_return_val_if_fail ((procedure != NULL || file != NULL) &&
                        ! (procedure != NULL && file != NULL), NULL);

  plug_in = g_object_new (GIMP_TYPE_PLUG_IN, NULL);

  if (! file)
    file = gimp_plug_in_procedure_get_file (procedure);

  gimp_object_take_name (GIMP_OBJECT (plug_in),
                         g_path_get_basename (gimp_file_get_utf8_name (file)));

  plug_in->manager = manager;
  plug_in->file    = g_object_ref (file);

  gimp_plug_in_proc_frame_init (&plug_in->main_proc_frame,
                                context, progress, procedure);

  return plug_in;
}
Beispiel #2
0
void
gimp_thumb_box_take_uri (GimpThumbBox *box,
                         gchar        *uri)
{
  g_return_if_fail (GIMP_IS_THUMB_BOX (box));

  if (box->idle_id)
    {
      g_source_remove (box->idle_id);
      box->idle_id = 0;
    }

  gimp_object_take_name (GIMP_OBJECT (box->imagefile), uri);

  if (uri)
    {
      gchar *basename = file_utils_uri_display_basename (uri);

      gtk_label_set_text (GTK_LABEL (box->filename), basename);
      g_free (basename);
    }
  else
    {
      gtk_label_set_text (GTK_LABEL (box->filename), _("No selection"));
    }

  gtk_widget_set_sensitive (GTK_WIDGET (box), uri != NULL);
  gimp_imagefile_update (box->imagefile);
}
Beispiel #3
0
static void
tool_manager_preset_changed (GimpContext     *user_context,
                             GimpToolPreset  *preset,
                             GimpToolManager *tool_manager)
{
  GimpToolInfo *preset_tool;
  gchar        *options_name;
  gboolean      tool_change = FALSE;

  if (! preset || user_context->gimp->busy)
    return;

  preset_tool = gimp_context_get_tool (GIMP_CONTEXT (preset->tool_options));

  if (preset_tool != gimp_context_get_tool (user_context))
    tool_change = TRUE;

  /*  save the name, we don't want to overwrite it  */
  options_name = g_strdup (gimp_object_get_name (preset_tool->tool_options));

  gimp_config_copy (GIMP_CONFIG (preset->tool_options),
                    GIMP_CONFIG (preset_tool->tool_options), 0);

  /*  restore the saved name  */
  gimp_object_take_name (GIMP_OBJECT (preset_tool->tool_options), options_name);

  if (tool_change)
    gimp_context_set_tool (user_context, preset_tool);

  gimp_context_copy_properties (GIMP_CONTEXT (preset->tool_options),
                                user_context,
                                gimp_tool_preset_get_prop_mask (preset));

  if (GIMP_IS_PAINT_OPTIONS (preset->tool_options))
    {
      GimpToolOptions     *src;
      GimpToolOptions     *dest;
      GimpContextPropMask  prop_mask = 0;

      src  = preset->tool_options;
      dest = tool_manager->active_tool->tool_info->tool_options;

      /*  copy various data objects' additional tool options again
       *  manually, they might have been overwritten by e.g. the "link
       *  brush stuff to brush defaults" logic in gimptooloptions.c
       */
      if (preset->use_brush)
        prop_mask |= GIMP_CONTEXT_PROP_MASK_BRUSH;

      if (preset->use_dynamics)
        prop_mask |= GIMP_CONTEXT_PROP_MASK_DYNAMICS;

      if (preset->use_gradient)
        prop_mask |= GIMP_CONTEXT_PROP_MASK_GRADIENT;

      gimp_paint_options_copy_props (GIMP_PAINT_OPTIONS (src),
                                     GIMP_PAINT_OPTIONS (dest),
                                     prop_mask);
    }
}
Beispiel #4
0
GimpPlugIn *
gimp_plug_in_new (GimpPlugInManager   *manager,
                  GimpContext         *context,
                  GimpProgress        *progress,
                  GimpPlugInProcedure *procedure,
                  const gchar         *prog)
{
  GimpPlugIn *plug_in;

  g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL);
  g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
  g_return_val_if_fail (procedure == NULL ||
                        GIMP_IS_PLUG_IN_PROCEDURE (procedure), NULL);
  g_return_val_if_fail (prog == NULL || g_path_is_absolute (prog), NULL);
  g_return_val_if_fail ((procedure != NULL || prog != NULL) &&
                        ! (procedure != NULL && prog != NULL), NULL);

  plug_in = g_object_new (GIMP_TYPE_PLUG_IN, NULL);

  if (! prog)
    prog = gimp_plug_in_procedure_get_progname (procedure);

  gimp_object_take_name (GIMP_OBJECT (plug_in),
                         g_filename_display_basename (prog));

  plug_in->manager = manager;
  plug_in->prog    = g_strdup (prog);

  gimp_plug_in_proc_frame_init (&plug_in->main_proc_frame,
                                context, progress, procedure);

  return plug_in;
}
Beispiel #5
0
static void
gimp_display_shell_drop_component (GtkWidget       *widget,
                                   gint             x,
                                   gint             y,
                                   GimpImage       *image,
                                   GimpChannelType  component,
                                   gpointer         data)
{
  GimpDisplayShell *shell      = GIMP_DISPLAY_SHELL (data);
  GimpImage        *dest_image = gimp_display_get_image (shell->display);
  GimpChannel      *channel;
  GimpItem         *new_item;
  const gchar      *desc;

  GIMP_LOG (DND, NULL);

  if (shell->display->gimp->busy)
    return;

  if (! dest_image)
    {
      dest_image = gimp_image_new_from_component (image->gimp,
                                                  image, component);
      gimp_create_display (dest_image->gimp, dest_image, GIMP_UNIT_PIXEL, 1.0,
                           G_OBJECT (gtk_widget_get_screen (widget)),
                           gimp_widget_get_monitor (widget));
      g_object_unref (dest_image);

      return;
    }

  channel = gimp_channel_new_from_component (image, component, NULL, NULL);

  new_item = gimp_item_convert (GIMP_ITEM (channel),
                                dest_image, GIMP_TYPE_LAYER);
  g_object_unref (channel);

  if (new_item)
    {
      GimpLayer *new_layer = GIMP_LAYER (new_item);

      gimp_enum_get_value (GIMP_TYPE_CHANNEL_TYPE, component,
                           NULL, NULL, &desc, NULL);
      gimp_object_take_name (GIMP_OBJECT (new_layer),
                             g_strdup_printf (_("%s Channel Copy"), desc));

      gimp_image_undo_group_start (dest_image, GIMP_UNDO_GROUP_EDIT_PASTE,
                                   _("Drop New Layer"));

      gimp_display_shell_dnd_position_item (shell, image, new_item);

      gimp_image_add_layer (dest_image, new_layer,
                            GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);

      gimp_image_undo_group_end (dest_image);

      gimp_display_shell_dnd_flush (shell, dest_image);
    }
}
static void
gimp_data_factory_view_tree_name_edited (GtkCellRendererText *cell,
                                         const gchar         *path_str,
                                         const gchar         *new_name,
                                         GimpDataFactoryView *view)
{
  GimpContainerTreeView *tree_view;
  GtkTreePath           *path;
  GtkTreeIter            iter;

  tree_view = GIMP_CONTAINER_TREE_VIEW (GIMP_CONTAINER_EDITOR (view)->view);

  path = gtk_tree_path_new_from_string (path_str);

  if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
    {
      GimpViewRenderer *renderer;
      GimpData         *data;
      gchar            *name;

      gtk_tree_model_get (tree_view->model, &iter,
                          tree_view->model_column_renderer, &renderer,
                          -1);

      data = GIMP_DATA (renderer->viewable);

      if (! new_name)
        new_name = "";

      name = g_strstrip (g_strdup (new_name));

      if (data->writable && strlen (name))
        {
          gimp_object_take_name (GIMP_OBJECT (data), name);
        }
      else
        {
          g_free (name);

          name = gimp_viewable_get_description (renderer->viewable, NULL);
          gtk_list_store_set (GTK_LIST_STORE (tree_view->model), &iter,
                              tree_view->model_column_name, name,
                              -1);
          g_free (name);
        }

      g_object_unref (renderer);
    }

  gtk_tree_path_free (path);
}
Beispiel #7
0
void
gimp_layer_mask_set_layer (GimpLayerMask *layer_mask,
                           GimpLayer     *layer)
{
  g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask));
  g_return_if_fail (layer == NULL || GIMP_IS_LAYER (layer));

  layer_mask->layer = layer;

  if (layer)
    {
      gchar *mask_name;

      GIMP_ITEM (layer_mask)->offset_x = GIMP_ITEM (layer)->offset_x;
      GIMP_ITEM (layer_mask)->offset_y = GIMP_ITEM (layer)->offset_y;

      mask_name = g_strdup_printf (_("%s mask"),
                                   gimp_object_get_name (GIMP_OBJECT (layer)));

      gimp_object_take_name (GIMP_OBJECT (layer_mask), mask_name);
    }
}
Beispiel #8
0
static void
gimp_data_editor_name_activate (GtkWidget      *widget,
                                GimpDataEditor *editor)
{
  if (editor->data)
    {
      gchar *new_name;

      new_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
      new_name = g_strstrip (new_name);

      if (strlen (new_name))
        {
          gimp_object_take_name (GIMP_OBJECT (editor->data), new_name);
        }
      else
        {
          gtk_entry_set_text (GTK_ENTRY (widget),
                              gimp_object_get_name (editor->data));
          g_free (new_name);
        }
    }
}
Beispiel #9
0
static GTokenType
plug_in_procedure_deserialize (GScanner             *scanner,
                               Gimp                 *gimp,
                               GFile                *file,
                               GimpPlugInProcedure **proc)
{
  GimpProcedure   *procedure;
  GTokenType       token;
  gchar           *str;
  gint             proc_type;
  gint             n_args;
  gint             n_return_vals;
  gint             n_menu_paths;
  gint             i;

  if (! gimp_scanner_parse_string (scanner, &str))
    return G_TOKEN_STRING;

  if (! gimp_scanner_parse_int (scanner, &proc_type))
    {
      g_free (str);
      return G_TOKEN_INT;
    }

  procedure = gimp_plug_in_procedure_new (proc_type, file);

  *proc = GIMP_PLUG_IN_PROCEDURE (procedure);

  gimp_object_take_name (GIMP_OBJECT (procedure),
                         gimp_canonicalize_identifier (str));

  procedure->original_name = str;

  if (! gimp_scanner_parse_string (scanner, &procedure->blurb))
    return G_TOKEN_STRING;
  if (! gimp_scanner_parse_string (scanner, &procedure->help))
    return G_TOKEN_STRING;
  if (! gimp_scanner_parse_string (scanner, &procedure->author))
    return G_TOKEN_STRING;
  if (! gimp_scanner_parse_string (scanner, &procedure->copyright))
    return G_TOKEN_STRING;
  if (! gimp_scanner_parse_string (scanner, &procedure->date))
    return G_TOKEN_STRING;
  if (! gimp_scanner_parse_string (scanner, &(*proc)->menu_label))
    return G_TOKEN_STRING;

  if (! gimp_scanner_parse_int (scanner, &n_menu_paths))
    return G_TOKEN_INT;

  for (i = 0; i < n_menu_paths; i++)
    {
      token = plug_in_menu_path_deserialize (scanner, *proc);
      if (token != G_TOKEN_LEFT_PAREN)
        return token;
    }

  token = plug_in_icon_deserialize (scanner, *proc);
  if (token != G_TOKEN_LEFT_PAREN)
    return token;

  token = plug_in_file_proc_deserialize (scanner, *proc);
  if (token != G_TOKEN_LEFT_PAREN)
    return token;

  if (! gimp_scanner_parse_string (scanner, &str))
    return G_TOKEN_STRING;

  gimp_plug_in_procedure_set_image_types (*proc, str);
  g_free (str);

  if (! gimp_scanner_parse_int (scanner, (gint *) &n_args))
    return G_TOKEN_INT;
  if (! gimp_scanner_parse_int (scanner, (gint *) &n_return_vals))
    return G_TOKEN_INT;

  for (i = 0; i < n_args; i++)
    {
      token = plug_in_proc_arg_deserialize (scanner, gimp, procedure, FALSE);
      if (token != G_TOKEN_LEFT_PAREN)
        return token;
    }

  for (i = 0; i < n_return_vals; i++)
    {
      token = plug_in_proc_arg_deserialize (scanner, gimp, procedure, TRUE);
      if (token != G_TOKEN_LEFT_PAREN)
        return token;
    }

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
    return G_TOKEN_RIGHT_PAREN;

  return G_TOKEN_LEFT_PAREN;
}
GList *
gimp_gradient_load (GimpContext  *context,
                    const gchar  *filename,
                    GError      **error)
{
  GimpGradient        *gradient;
  GimpGradientSegment *prev;
  gint                 num_segments;
  gint                 i;
  FILE                *file;
  gchar                line[1024];
  gint                 linenum;

  g_return_val_if_fail (filename != NULL, NULL);
  g_return_val_if_fail (g_path_is_absolute (filename), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  file = g_fopen (filename, "rb");

  if (!file)
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN,
                   _("Could not open '%s' for reading: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return NULL;
    }

  linenum = 1;
  if (! fgets (line, sizeof (line), file))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in gradient file '%s': "
                     "Read error in line %d."),
                   gimp_filename_to_utf8 (filename), linenum);
      fclose (file);
      return NULL;
    }

  if (! g_str_has_prefix (line, "GIMP Gradient"))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in gradient file '%s': "
                     "Not a GIMP gradient file."),
                   gimp_filename_to_utf8 (filename));
      fclose (file);
      return NULL;
    }

  gradient = g_object_new (GIMP_TYPE_GRADIENT,
                           "mime-type", "application/x-gimp-gradient",
                           NULL);

  linenum++;
  if (! fgets (line, sizeof (line), file))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in gradient file '%s': "
                     "Read error in line %d."),
                   gimp_filename_to_utf8 (filename), linenum);
      fclose (file);
      g_object_unref (gradient);
      return NULL;
    }

  if (g_str_has_prefix (line, "Name: "))
    {
      gchar *utf8;

      utf8 = gimp_any_to_utf8 (g_strstrip (line + strlen ("Name: ")), -1,
                               _("Invalid UTF-8 string in gradient file '%s'."),
                               gimp_filename_to_utf8 (filename));
      gimp_object_take_name (GIMP_OBJECT (gradient), utf8);

      linenum++;
      if (! fgets (line, sizeof (line), file))
        {
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                       _("Fatal parse error in gradient file '%s': "
                         "Read error in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);
          fclose (file);
          g_object_unref (gradient);
          return NULL;
        }
    }
  else /* old gradient format */
    {
      gimp_object_take_name (GIMP_OBJECT (gradient),
                             g_filename_display_basename (filename));
    }

  num_segments = atoi (line);

  if (num_segments < 1)
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in gradient file '%s': "
                     "File is corrupt in line %d."),
                   gimp_filename_to_utf8 (filename), linenum);
      g_object_unref (gradient);
      fclose (file);
      return NULL;
    }

  prev = NULL;

  for (i = 0; i < num_segments; i++)
    {
      GimpGradientSegment *seg;
      gchar               *end;
      gint                 color;
      gint                 type;
      gint                 left_color_type;
      gint                 right_color_type;

      seg = gimp_gradient_segment_new ();

      seg->prev = prev;

      if (prev)
        prev->next = seg;
      else
        gradient->segments = seg;

      linenum++;
      if (! fgets (line, sizeof (line), file))
        {
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                       _("Fatal parse error in gradient file '%s': "
                         "Read error in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);
          fclose (file);
          g_object_unref (gradient);
          return NULL;
        }

      seg->left = g_ascii_strtod (line, &end);
      if (end && errno != ERANGE)
        seg->middle = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->right = g_ascii_strtod (end, &end);

      if (end && errno != ERANGE)
        seg->left_color.r = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->left_color.g = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->left_color.b = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->left_color.a = g_ascii_strtod (end, &end);

      if (end && errno != ERANGE)
        seg->right_color.r = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->right_color.g = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->right_color.b = g_ascii_strtod (end, &end);
      if (end && errno != ERANGE)
        seg->right_color.a = g_ascii_strtod (end, &end);

      if (errno != ERANGE)
        {
          switch (sscanf (end, "%d %d %d %d",
                          &type, &color,
                          &left_color_type, &right_color_type))
            {
            case 4:
              seg->left_color_type  = (GimpGradientColor) left_color_type;
              seg->right_color_type = (GimpGradientColor) right_color_type;
              /* fall thru */

            case 2:
              seg->type  = (GimpGradientSegmentType) type;
              seg->color = (GimpGradientSegmentColor) color;
              break;

            default:
              g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                           _("Fatal parse error in gradient file '%s': "
                             "Corrupt segment %d in line %d."),
                           gimp_filename_to_utf8 (filename), i, linenum);
              g_object_unref (gradient);
              fclose (file);
              return NULL;
            }
        }
      else
        {
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                       _("Fatal parse error in gradient file '%s': "
                         "Corrupt segment %d in line %d."),
                       gimp_filename_to_utf8 (filename), i, linenum);
          g_object_unref (gradient);
          fclose (file);
          return NULL;
        }

      if ( (prev && (prev->right < seg->left))
           || (!prev && (0. < seg->left) ))
        {
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                       _("Gradient file '%s' is corrupt: "
                         "Segments do not span the range 0-1."),
                       gimp_filename_to_utf8 (filename));
          g_object_unref (gradient);
          fclose (file);
          return NULL;
        }

      prev = seg;
    }

  if (prev->right < 1.0)
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Gradient file '%s' is corrupt: "
                     "Segments do not span the range 0-1."),
                   gimp_filename_to_utf8 (filename));
      g_object_unref (gradient);
      fclose (file);
      return NULL;
    }

  fclose (file);

  return g_list_prepend (NULL, gradient);
}
Beispiel #11
0
static GimpLayer *
gimp_image_merge_layers (GimpImage     *image,
                         GSList        *merge_list,
                         GimpContext   *context,
                         GimpMergeType  merge_type,
                         const gchar   *undo_desc)
{
  GList           *list;
  GSList          *reverse_list = NULL;
  PixelRegion      src1PR, src2PR, maskPR;
  PixelRegion     *mask;
  GimpLayer       *merge_layer;
  GimpLayer       *layer;
  GimpLayer       *bottom_layer;
  GimpImageType    type;
  gint             count;
  gint             x1, y1, x2, y2;
  gint             x3, y3, x4, y4;
  CombinationMode  operation;
  gint             position;
  gboolean         active[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE };
  gint             off_x, off_y;
  gchar           *name;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);

  layer        = NULL;
  type         = GIMP_RGBA_IMAGE;
  x1 = y1      = 0;
  x2 = y2      = 0;
  bottom_layer = NULL;

  /*  Get the layer extents  */
  count = 0;
  while (merge_list)
    {
      layer = merge_list->data;

      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);

      switch (merge_type)
        {
        case GIMP_EXPAND_AS_NECESSARY:
        case GIMP_CLIP_TO_IMAGE:
          if (! count)
            {
              x1 = off_x;
              y1 = off_y;
              x2 = off_x + gimp_item_width  (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_height (GIMP_ITEM (layer));
            }
          else
            {
              if (off_x < x1)
                x1 = off_x;
              if (off_y < y1)
                y1 = off_y;
              if ((off_x + gimp_item_width (GIMP_ITEM (layer))) > x2)
                x2 = (off_x + gimp_item_width (GIMP_ITEM (layer)));
              if ((off_y + gimp_item_height (GIMP_ITEM (layer))) > y2)
                y2 = (off_y + gimp_item_height (GIMP_ITEM (layer)));
            }

          if (merge_type == GIMP_CLIP_TO_IMAGE)
            {
              x1 = CLAMP (x1, 0, gimp_image_get_width  (image));
              y1 = CLAMP (y1, 0, gimp_image_get_height (image));
              x2 = CLAMP (x2, 0, gimp_image_get_width  (image));
              y2 = CLAMP (y2, 0, gimp_image_get_height (image));
            }
          break;

        case GIMP_CLIP_TO_BOTTOM_LAYER:
          if (merge_list->next == NULL)
            {
              x1 = off_x;
              y1 = off_y;
              x2 = off_x + gimp_item_width (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_height (GIMP_ITEM (layer));
            }
          break;

        case GIMP_FLATTEN_IMAGE:
          if (merge_list->next == NULL)
            {
              x1 = 0;
              y1 = 0;
              x2 = gimp_image_get_width  (image);
              y2 = gimp_image_get_height (image);
            }
          break;
        }

      count ++;
      reverse_list = g_slist_prepend (reverse_list, layer);
      merge_list = g_slist_next (merge_list);
    }

  if ((x2 - x1) == 0 || (y2 - y1) == 0)
    return NULL;

  /*  Start a merge undo group. */

  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
                               undo_desc);

  name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer)));

  if (merge_type == GIMP_FLATTEN_IMAGE ||
      gimp_drawable_type (GIMP_DRAWABLE (layer)) == GIMP_INDEXED_IMAGE)
    {
      guchar bg[4] = { 0, 0, 0, 0 };

      type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (image));

      merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1),
                                    type,
                                    gimp_object_get_name (GIMP_OBJECT (layer)),
                                    GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);
      if (! merge_layer)
        {
          g_warning ("%s: could not allocate merge layer.", G_STRFUNC);
          return NULL;
        }

      GIMP_ITEM (merge_layer)->offset_x = x1;
      GIMP_ITEM (merge_layer)->offset_y = y1;

      /*  get the background for compositing  */
      gimp_image_get_background (image, context,
                                 gimp_drawable_type (GIMP_DRAWABLE (merge_layer)),
                                 bg);

      /*  init the pixel region  */
      pixel_region_init (&src1PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)),
                         0, 0, (x2 - x1), (y2 - y1),
                         TRUE);

      /*  set the region to the background color  */
      color_region (&src1PR, bg);

      position = 0;
    }
  else
    {
      /*  The final merged layer inherits the name of the bottom most layer
       *  and the resulting layer has an alpha channel whether or not the
       *  original did. Opacity is set to 100% and the MODE is set to normal.
       */

      merge_layer =
        gimp_layer_new (image, (x2 - x1), (y2 - y1),
                        gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)),
                        "merged layer",
                        GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);

      if (!merge_layer)
        {
          g_warning ("%s: could not allocate merge layer", G_STRFUNC);
          return NULL;
        }

      GIMP_ITEM (merge_layer)->offset_x = x1;
      GIMP_ITEM (merge_layer)->offset_y = y1;

      /*  clear the layer  */
      pixel_region_init (&src1PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)),
                         0, 0,
                         (x2 - x1), (y2 - y1),
                         TRUE);
      clear_region (&src1PR);

      /*  Find the index in the layer list of the bottom layer--we need this
       *  in order to add the final, merged layer to the layer list correctly
       */
      layer = reverse_list->data;
      position =
        gimp_container_num_children (image->layers) -
        gimp_container_get_child_index (image->layers, GIMP_OBJECT (layer));
    }

  bottom_layer = layer;

  /* Copy the tattoo and parasites of the bottom layer to the new layer */
  gimp_item_set_tattoo (GIMP_ITEM (merge_layer),
                        gimp_item_get_tattoo (GIMP_ITEM (bottom_layer)));

  g_object_unref (GIMP_ITEM (merge_layer)->parasites);
  GIMP_ITEM (merge_layer)->parasites =
    gimp_parasite_list_copy (GIMP_ITEM (bottom_layer)->parasites);

  while (reverse_list)
    {
      GimpLayerModeEffects  mode;

      layer = reverse_list->data;

      /*  determine what sort of operation is being attempted and
       *  if it's actually legal...
       */
      operation = gimp_image_merge_layers_get_operation (merge_layer, layer);

      if (operation == -1)
        {
          gimp_layer_add_alpha (layer);

          /*  try again ...  */
          operation = gimp_image_merge_layers_get_operation (merge_layer,
                                                             layer);
        }

      if (operation == -1)
        {
          g_warning ("%s: attempting to merge incompatible layers.", G_STRFUNC);
          return NULL;
        }

      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);

      x3 = CLAMP (off_x, x1, x2);
      y3 = CLAMP (off_y, y1, y2);
      x4 = CLAMP (off_x + gimp_item_width  (GIMP_ITEM (layer)), x1, x2);
      y4 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), y1, y2);

      /* configure the pixel regions  */
      pixel_region_init (&src1PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)),
                         (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3),
                         TRUE);
      pixel_region_init (&src2PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)),
                         (x3 - off_x), (y3 - off_y),
                         (x4 - x3), (y4 - y3),
                         FALSE);

      if (gimp_layer_get_mask (layer) &&
          gimp_layer_mask_get_apply (layer->mask))
        {
          TileManager *tiles;

          tiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (layer->mask));

          pixel_region_init (&maskPR, tiles,
                             (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3),
                             FALSE);
          mask = &maskPR;
        }
      else
        {
          mask = NULL;
        }

      /* DISSOLVE_MODE is special since it is the only mode that does not
       *  work on the projection with the lower layer, but only locally on
       *  the layers alpha channel.
       */
      mode = gimp_layer_get_mode (layer);
      if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE)
        mode = GIMP_NORMAL_MODE;

      combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL,
                       gimp_layer_get_opacity (layer) * 255.999,
                       mode,
                       active,
                       operation);

      gimp_image_remove_layer (image, layer);

      reverse_list = g_slist_next (reverse_list);
    }

  g_slist_free (reverse_list);

  /*  if the type is flatten, remove all the remaining layers  */
  if (merge_type == GIMP_FLATTEN_IMAGE)
    {
      list = GIMP_LIST (image->layers)->list;
      while (list)
        {
          layer = list->data;

          list = g_list_next (list);
          gimp_image_remove_layer (image, layer);
        }

      gimp_image_add_layer (image, merge_layer, position);
    }
  else
    {
      /*  Add the layer to the image  */
      gimp_image_add_layer (image, merge_layer,
         gimp_container_num_children (image->layers) - position + 1);
    }

  /* set the name after the original layers have been removed so we
   * don't end up with #2 appended to the name
   */
  gimp_object_take_name (GIMP_OBJECT (merge_layer), name);

  gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, TRUE);

  /*  End the merge undo group  */
  gimp_image_undo_group_end (image);

  gimp_drawable_update (GIMP_DRAWABLE (merge_layer),
                        0, 0,
                        gimp_item_width  (GIMP_ITEM (merge_layer)),
                        gimp_item_height (GIMP_ITEM (merge_layer)));

  return merge_layer;
}
Beispiel #12
0
GimpVectors *
gimp_image_merge_visible_vectors (GimpImage  *image,
                                  GError    **error)
{
  GList       *list           = NULL;
  GSList      *merge_list     = NULL;
  GSList      *cur_item       = NULL;
  GimpVectors *vectors        = NULL;
  GimpVectors *target_vectors = NULL;
  gchar       *name           = NULL;
  gint         pos            = 0;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  for (list = GIMP_LIST (image->vectors)->list;
       list;
       list = g_list_next (list))
    {
      vectors = list->data;

      if (gimp_item_get_visible (GIMP_ITEM (vectors)))
        merge_list = g_slist_append (merge_list, vectors);
    }

  if (merge_list && merge_list->next)
    {
      gimp_set_busy (image->gimp);

      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_VECTORS_MERGE,
                                   _("Merge Visible Paths"));

      cur_item = merge_list;
      vectors = GIMP_VECTORS (cur_item->data);

      name = g_strdup (gimp_object_get_name (GIMP_OBJECT (vectors)));
      target_vectors = GIMP_VECTORS (gimp_item_duplicate (GIMP_ITEM (vectors),
                                                          GIMP_TYPE_VECTORS));
      pos = gimp_image_get_vectors_index (image, vectors);
      gimp_image_remove_vectors (image, vectors);
      cur_item = cur_item->next;

      while (cur_item)
        {
          vectors = GIMP_VECTORS (cur_item->data);
          gimp_vectors_add_strokes (vectors, target_vectors);
          gimp_image_remove_vectors (image, vectors);

          cur_item = g_slist_next (cur_item);
        }

      gimp_object_take_name (GIMP_OBJECT (target_vectors), name);

      g_slist_free (merge_list);

      gimp_image_add_vectors (image, target_vectors, pos);
      gimp_unset_busy (image->gimp);

      gimp_image_undo_group_end (image);

      return target_vectors;
    }
  else
    {
      g_set_error (error, 0, 0,
                   _("Not enough visible paths for a merge. "
                     "There must be at least two."));
      return NULL;
    }
}
static GimpLayer *
gimp_image_merge_layers (GimpImage     *image,
                         GimpContainer *container,
                         GSList        *merge_list,
                         GimpContext   *context,
                         GimpMergeType  merge_type)
{
  GList            *list;
  GSList           *reverse_list = NULL;
  GSList           *layers;
  GimpLayer        *merge_layer;
  GimpLayer        *layer;
  GimpLayer        *bottom_layer;
  GimpParasiteList *parasites;
  gint              count;
  gint              x1, y1, x2, y2;
  gint              off_x, off_y;
  gint              position;
  gchar            *name;
  GimpLayer        *parent;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);

  layer        = NULL;
  x1 = y1      = 0;
  x2 = y2      = 0;
  bottom_layer = NULL;

  parent = gimp_layer_get_parent (merge_list->data);

  /*  Get the layer extents  */
  count = 0;
  while (merge_list)
    {
      layer = merge_list->data;

      gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);

      switch (merge_type)
        {
        case GIMP_EXPAND_AS_NECESSARY:
        case GIMP_CLIP_TO_IMAGE:
          if (! count)
            {
              x1 = off_x;
              y1 = off_y;
              x2 = off_x + gimp_item_get_width  (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer));
            }
          else
            {
              if (off_x < x1)
                x1 = off_x;
              if (off_y < y1)
                y1 = off_y;
              if ((off_x + gimp_item_get_width (GIMP_ITEM (layer))) > x2)
                x2 = (off_x + gimp_item_get_width (GIMP_ITEM (layer)));
              if ((off_y + gimp_item_get_height (GIMP_ITEM (layer))) > y2)
                y2 = (off_y + gimp_item_get_height (GIMP_ITEM (layer)));
            }

          if (merge_type == GIMP_CLIP_TO_IMAGE)
            {
              x1 = CLAMP (x1, 0, gimp_image_get_width  (image));
              y1 = CLAMP (y1, 0, gimp_image_get_height (image));
              x2 = CLAMP (x2, 0, gimp_image_get_width  (image));
              y2 = CLAMP (y2, 0, gimp_image_get_height (image));
            }
          break;

        case GIMP_CLIP_TO_BOTTOM_LAYER:
          if (merge_list->next == NULL)
            {
              x1 = off_x;
              y1 = off_y;
              x2 = off_x + gimp_item_get_width  (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer));
            }
          break;

        case GIMP_FLATTEN_IMAGE:
          if (merge_list->next == NULL)
            {
              x1 = 0;
              y1 = 0;
              x2 = gimp_image_get_width  (image);
              y2 = gimp_image_get_height (image);
            }
          break;
        }

      count ++;
      reverse_list = g_slist_prepend (reverse_list, layer);
      merge_list = g_slist_next (merge_list);
    }

  if ((x2 - x1) == 0 || (y2 - y1) == 0)
    return NULL;

  /*  Start a merge undo group. */

  name = g_strdup (gimp_object_get_name (layer));

  if (merge_type == GIMP_FLATTEN_IMAGE ||
      (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)) &&
       ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))))
    {
      GeglColor *color;
      GimpRGB    bg;

      merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1),
                                    gimp_image_get_layer_format (image, FALSE),
                                    gimp_object_get_name (layer),
                                    GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);
      if (! merge_layer)
        {
          g_warning ("%s: could not allocate merge layer.", G_STRFUNC);
          return NULL;
        }

      gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1);

      /*  get the background for compositing  */
      gimp_context_get_background (context, &bg);

      color = gimp_gegl_color_new (&bg);
      gegl_buffer_set_color (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)),
                             GEGL_RECTANGLE(0,0,x2-x1,y2-y1), color);
      g_object_unref (color);

      position = 0;
    }
  else
    {
      /*  The final merged layer inherits the name of the bottom most layer
       *  and the resulting layer has an alpha channel whether or not the
       *  original did. Opacity is set to 100% and the MODE is set to normal.
       */

      merge_layer =
        gimp_layer_new (image, (x2 - x1), (y2 - y1),
                        gimp_drawable_get_format_with_alpha (GIMP_DRAWABLE (layer)),
                        "merged layer",
                        GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);

      if (!merge_layer)
        {
          g_warning ("%s: could not allocate merge layer", G_STRFUNC);
          return NULL;
        }

      gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1);

      /*  clear the layer  */
      gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)),
                         NULL);

      /*  Find the index in the layer list of the bottom layer--we need this
       *  in order to add the final, merged layer to the layer list correctly
       */
      layer = reverse_list->data;
      position =
        gimp_container_get_n_children (container) -
        gimp_container_get_child_index (container, GIMP_OBJECT (layer));
    }

  bottom_layer = layer;

  /* Copy the tattoo and parasites of the bottom layer to the new layer */
  gimp_item_set_tattoo (GIMP_ITEM (merge_layer),
                        gimp_item_get_tattoo (GIMP_ITEM (bottom_layer)));

  parasites = gimp_item_get_parasites (GIMP_ITEM (bottom_layer));
  parasites = gimp_parasite_list_copy (parasites);
  gimp_item_set_parasites (GIMP_ITEM (merge_layer), parasites);
  g_object_unref (parasites);

  for (layers = reverse_list; layers; layers = g_slist_next (layers))
    {
      GeglBuffer           *merge_buffer;
      GeglBuffer           *layer_buffer;
      GimpApplicator       *applicator;
      GimpLayerModeEffects  mode;

      layer = layers->data;

      gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);

      /* DISSOLVE_MODE is special since it is the only mode that does not
       *  work on the projection with the lower layer, but only locally on
       *  the layers alpha channel.
       */
      mode = gimp_layer_get_mode (layer);
      if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE)
        mode = GIMP_NORMAL_MODE;

      merge_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer));
      layer_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));

      applicator =
        gimp_applicator_new (NULL,
                             gimp_drawable_get_linear (GIMP_DRAWABLE (layer)),
                             FALSE, FALSE);

      if (gimp_layer_get_mask (layer) &&
          gimp_layer_get_apply_mask (layer))
        {
          GeglBuffer *mask_buffer;

          mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer->mask));

          gimp_applicator_set_mask_buffer (applicator, mask_buffer);
          gimp_applicator_set_mask_offset (applicator,
                                           - (x1 - off_x),
                                           - (y1 - off_y));
        }

      gimp_applicator_set_src_buffer (applicator, merge_buffer);
      gimp_applicator_set_dest_buffer (applicator, merge_buffer);

      gimp_applicator_set_apply_buffer (applicator, layer_buffer);
      gimp_applicator_set_apply_offset (applicator,
                                        - (x1 - off_x),
                                        - (y1 - off_y));

      gimp_applicator_set_mode (applicator,
                                gimp_layer_get_opacity (layer),
                                mode);

      gimp_applicator_blit (applicator,
                            GEGL_RECTANGLE (0, 0,
                                            gegl_buffer_get_width  (merge_buffer),
                                            gegl_buffer_get_height (merge_buffer)));

      g_object_unref (applicator);

      gimp_image_remove_layer (image, layer, TRUE, NULL);
    }

  g_slist_free (reverse_list);

  gimp_object_take_name (GIMP_OBJECT (merge_layer), name);
  gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, FALSE);

  /*  if the type is flatten, remove all the remaining layers  */
  if (merge_type == GIMP_FLATTEN_IMAGE)
    {
      list = gimp_image_get_layer_iter (image);
      while (list)
        {
          layer = list->data;

          list = g_list_next (list);
          gimp_image_remove_layer (image, layer, TRUE, NULL);
        }

      gimp_image_add_layer (image, merge_layer, parent,
                            position, TRUE);
    }
  else
    {
      /*  Add the layer to the image  */

      gimp_image_add_layer (image, merge_layer, parent,
                            gimp_container_get_n_children (container) -
                            position + 1,
                            TRUE);
    }

  gimp_drawable_update (GIMP_DRAWABLE (merge_layer),
                        0, 0,
                        gimp_item_get_width  (GIMP_ITEM (merge_layer)),
                        gimp_item_get_height (GIMP_ITEM (merge_layer)));

  return merge_layer;
}
GimpVectors *
gimp_image_merge_visible_vectors (GimpImage  *image,
                                  GError    **error)
{
  GList       *list;
  GList       *merge_list = NULL;
  GimpVectors *vectors;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  for (list = gimp_image_get_vectors_iter (image);
       list;
       list = g_list_next (list))
    {
      vectors = list->data;

      if (gimp_item_get_visible (GIMP_ITEM (vectors)))
        merge_list = g_list_prepend (merge_list, vectors);
    }

  merge_list = g_list_reverse (merge_list);

  if (merge_list && merge_list->next)
    {
      GimpVectors *target_vectors;
      gchar       *name;
      gint         pos;

      gimp_set_busy (image->gimp);

      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_VECTORS_MERGE,
                                   C_("undo-type", "Merge Visible Paths"));

      vectors = GIMP_VECTORS (merge_list->data);

      name = g_strdup (gimp_object_get_name (vectors));
      pos = gimp_item_get_index (GIMP_ITEM (vectors));

      target_vectors = GIMP_VECTORS (gimp_item_duplicate (GIMP_ITEM (vectors),
                                                          GIMP_TYPE_VECTORS));
      gimp_image_remove_vectors (image, vectors, TRUE, NULL);

      for (list = g_list_next (merge_list);
           list;
           list = g_list_next (list))
        {
          vectors = list->data;

          gimp_vectors_add_strokes (vectors, target_vectors);
          gimp_image_remove_vectors (image, vectors, TRUE, NULL);
        }

      gimp_object_take_name (GIMP_OBJECT (target_vectors), name);

      g_list_free (merge_list);

      /* FIXME tree */
      gimp_image_add_vectors (image, target_vectors, NULL, pos, TRUE);
      gimp_unset_busy (image->gimp);

      gimp_image_undo_group_end (image);

      return target_vectors;
    }
  else
    {
      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
			   _("Not enough visible paths for a merge. "
			     "There must be at least two."));
      return NULL;
    }
}
Beispiel #15
0
GList *
gimp_palette_load (GimpContext   *context,
                   GFile         *file,
                   GInputStream  *input,
                   GError       **error)
{
  GimpPalette      *palette = NULL;
  GimpPaletteEntry *entry;
  GDataInputStream *data_input;
  gchar            *str;
  gsize             str_len;
  gchar            *tok;
  gint              r, g, b;
  gint              linenum;

  g_return_val_if_fail (G_IS_FILE (file), NULL);
  g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  data_input = g_data_input_stream_new (input);

  r = g = b = 0;

  linenum = 1;
  str_len = 1024;
  str = gimp_data_input_stream_read_line_always (data_input, &str_len,
                                                 NULL, error);
  if (! str)
    goto failed;

  if (! g_str_has_prefix (str, "GIMP Palette"))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Missing magic header."));
      g_free (str);
      goto failed;
    }

  g_free (str);

  palette = g_object_new (GIMP_TYPE_PALETTE,
                          "mime-type", "application/x-gimp-palette",
                          NULL);

  linenum++;
  str_len = 1024;
  str = gimp_data_input_stream_read_line_always (data_input, &str_len,
                                                 NULL, error);
  if (! str)
    goto failed;

  if (g_str_has_prefix (str, "Name: "))
    {
      gchar *utf8;

      utf8 = gimp_any_to_utf8 (g_strstrip (str + strlen ("Name: ")), -1,
                               _("Invalid UTF-8 string in palette file '%s'"),
                               gimp_file_get_utf8_name (file));
      gimp_object_take_name (GIMP_OBJECT (palette), utf8);
      g_free (str);

      linenum++;
      str_len = 1024;
      str = gimp_data_input_stream_read_line_always (data_input, &str_len,
                                                     NULL, error);
      if (! str)
        goto failed;

      if (g_str_has_prefix (str, "Columns: "))
        {
          gint columns;

          if (! gimp_ascii_strtoi (g_strstrip (str + strlen ("Columns: ")),
                                   NULL, 10, &columns))
            {
              g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                           _("Invalid column count."));
              g_free (str);
              goto failed;
            }

          if (columns < 0 || columns > 256)
            {
              g_message (_("Reading palette file '%s': "
                           "Invalid number of columns in line %d. "
                           "Using default value."),
                         gimp_file_get_utf8_name (file), linenum);
              columns = 0;
            }

          gimp_palette_set_columns (palette, columns);
          g_free (str);

          linenum++;
          str_len = 1024;
          str = gimp_data_input_stream_read_line_always (data_input, &str_len,
                                                         NULL, error);
          if (! str)
            goto failed;
        }
    }
  else /* old palette format */
    {
      gimp_object_take_name (GIMP_OBJECT (palette),
                             g_path_get_basename (gimp_file_get_utf8_name (file)));
    }

  while (str)
    {
      GError *my_error = NULL;

      if (str[0] != '#' && str[0] != '\0')
        {
          tok = strtok (str, " \t");
          if (tok)
            r = atoi (tok);
          else
            g_message (_("Reading palette file '%s': "
                         "Missing RED component in line %d."),
                       gimp_file_get_utf8_name (file), linenum);

          tok = strtok (NULL, " \t");
          if (tok)
            g = atoi (tok);
          else
            g_message (_("Reading palette file '%s': "
                         "Missing GREEN component in line %d."),
                       gimp_file_get_utf8_name (file), linenum);

          tok = strtok (NULL, " \t");
          if (tok)
            b = atoi (tok);
          else
            g_message (_("Reading palette file '%s': "
                         "Missing BLUE component in line %d."),
                       gimp_file_get_utf8_name (file), linenum);

          /* optional name */
          tok = strtok (NULL, "\n");

          if (r < 0 || r > 255 ||
              g < 0 || g > 255 ||
              b < 0 || b > 255)
            g_message (_("Reading palette file '%s': "
                         "RGB value out of range in line %d."),
                       gimp_file_get_utf8_name (file), linenum);

          /* don't call gimp_palette_add_entry here, it's rather inefficient */
          entry = g_slice_new0 (GimpPaletteEntry);

          gimp_rgba_set_uchar (&entry->color,
                               (guchar) r,
                               (guchar) g,
                               (guchar) b,
                               255);

          entry->name     = g_strdup (tok ? tok : _("Untitled"));
          entry->position = gimp_palette_get_n_colors (palette);

          palette->colors = g_list_prepend (palette->colors, entry);
          palette->n_colors++;
        }

      g_free (str);

      linenum++;
      str_len = 1024;
      str = g_data_input_stream_read_line (data_input, &str_len,
                                           NULL, &my_error);
      if (! str && my_error)
        {
          g_message (_("Reading palette file '%s': "
                       "Read %d colors from truncated file: %s"),
                     gimp_file_get_utf8_name (file),
                     g_list_length (palette->colors),
                     my_error->message);
          g_clear_error (&my_error);
        }
    }

  palette->colors = g_list_reverse (palette->colors);

  g_object_unref (data_input);

  return g_list_prepend (NULL, palette);

 failed:

  g_object_unref (data_input);

  if (palette)
    g_object_unref (palette);

  g_prefix_error (error, _("In line %d of palette file: "), linenum);

  return NULL;
}
Beispiel #16
0
static gboolean
gimp_text_layer_render (GimpTextLayer *layer)
{
  GimpDrawable   *drawable;
  GimpItem       *item;
  GimpImage      *image;
  GimpTextLayout *layout;
  gdouble         xres;
  gdouble         yres;
  gint            width;
  gint            height;

  if (! layer->text)
    return FALSE;

  drawable = GIMP_DRAWABLE (layer);
  item     = GIMP_ITEM (layer);
  image    = gimp_item_get_image (item);

  if (gimp_container_is_empty (image->gimp->fonts))
    {
      gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR,
			    _("Due to lack of any fonts, "
			      "text functionality is not available."));
      return FALSE;
    }

  gimp_image_get_resolution (image, &xres, &yres);

  layout = gimp_text_layout_new (layer->text, xres, yres);

  g_object_freeze_notify (G_OBJECT (drawable));

  if (gimp_text_layout_get_size (layout, &width, &height) &&
      (width  != gimp_item_get_width  (item) ||
       height != gimp_item_get_height (item)))
    {
      GeglBuffer *new_buffer;

      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                                    gimp_drawable_get_format (drawable));
      gimp_drawable_set_buffer (drawable, FALSE, NULL, new_buffer);
      g_object_unref (new_buffer);

      if (gimp_layer_get_mask (GIMP_LAYER (layer)))
        {
          GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));

          static GimpContext *unused_eek = NULL;

          if (! unused_eek)
            unused_eek = gimp_context_new (image->gimp, "eek", NULL);

          gimp_item_resize (GIMP_ITEM (mask), unused_eek, width, height, 0, 0);
        }
    }

  if (layer->auto_rename)
    {
      GimpItem *item = GIMP_ITEM (layer);
      gchar    *name = NULL;

      if (layer->text->text)
        {
          name = gimp_utf8_strtrim (layer->text->text, 30);
        }
      else if (layer->text->markup)
        {
          gchar *tmp = gimp_markup_extract_text (layer->text->markup);
          name = gimp_utf8_strtrim (tmp, 30);
          g_free (tmp);
        }

      if (! name)
        name = g_strdup (_("Empty Text Layer"));

      if (gimp_item_is_attached (item))
        {
          gimp_item_tree_rename_item (gimp_item_get_tree (item), item,
                                      name, FALSE, NULL);
          g_free (name);
        }
      else
        {
          gimp_object_take_name (GIMP_OBJECT (layer), name);
        }
    }

  gimp_text_layer_render_layout (layer, layout);

  g_object_unref (layout);

  g_object_thaw_notify (G_OBJECT (drawable));

  return (width > 0 && height > 0);
}
static void
gimp_plug_in_handle_proc_install (GimpPlugIn    *plug_in,
                                  GPProcInstall *proc_install)
{
  GimpPlugInProcedure *proc       = NULL;
  GimpProcedure       *procedure  = NULL;
  gchar               *canonical;
  gboolean             null_name  = FALSE;
  gboolean             valid_utf8 = FALSE;
  gint                 i;

  g_return_if_fail (proc_install != NULL);
  g_return_if_fail (proc_install->name != NULL);

  canonical = gimp_canonicalize_identifier (proc_install->name);

  /*  Sanity check for array arguments  */

  for (i = 1; i < proc_install->nparams; i++)
    {
      if ((proc_install->params[i].type == GIMP_PDB_INT32ARRAY ||
           proc_install->params[i].type == GIMP_PDB_INT8ARRAY  ||
           proc_install->params[i].type == GIMP_PDB_FLOATARRAY ||
           proc_install->params[i].type == GIMP_PDB_STRINGARRAY ||
           proc_install->params[i].type == GIMP_PDB_COLORARRAY)
          &&
          proc_install->params[i - 1].type != GIMP_PDB_INT32)
        {
          gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                        "Plug-In \"%s\"\n(%s)\n\n"
                        "attempted to install procedure \"%s\" "
                        "which fails to comply with the array parameter "
                        "passing standard.  Argument %d is noncompliant.",
                        gimp_object_get_name (plug_in),
                        gimp_file_get_utf8_name (plug_in->file),
                        canonical, i);
          g_free (canonical);
          return;
        }
    }

  /*  Sanity check strings for UTF-8 validity  */

#define VALIDATE(str)         (g_utf8_validate ((str), -1, NULL))
#define VALIDATE_OR_NULL(str) ((str) == NULL || g_utf8_validate ((str), -1, NULL))

  if (VALIDATE_OR_NULL (proc_install->menu_path) &&
      VALIDATE         (canonical)               &&
      VALIDATE_OR_NULL (proc_install->blurb)     &&
      VALIDATE_OR_NULL (proc_install->help)      &&
      VALIDATE_OR_NULL (proc_install->author)    &&
      VALIDATE_OR_NULL (proc_install->copyright) &&
      VALIDATE_OR_NULL (proc_install->date))
    {
      null_name  = FALSE;
      valid_utf8 = TRUE;

      for (i = 0; i < proc_install->nparams && valid_utf8 && !null_name; i++)
        {
          if (! proc_install->params[i].name)
            {
              null_name = TRUE;
            }
          else if (! (VALIDATE         (proc_install->params[i].name) &&
                      VALIDATE_OR_NULL (proc_install->params[i].description)))
            {
              valid_utf8 = FALSE;
            }
        }

      for (i = 0; i < proc_install->nreturn_vals && valid_utf8 && !null_name; i++)
        {
          if (! proc_install->return_vals[i].name)
            {
              null_name = TRUE;
            }
          else if (! (VALIDATE         (proc_install->return_vals[i].name) &&
                      VALIDATE_OR_NULL (proc_install->return_vals[i].description)))
            {
              valid_utf8 = FALSE;
            }
        }
    }

#undef VALIDATE
#undef VALIDATE_OR_NULL

  if (null_name)
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "attempted to install a procedure NULL parameter name.",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file));
      g_free (canonical);
      return;
    }

  if (! valid_utf8)
    {
      gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                    "Plug-In \"%s\"\n(%s)\n\n"
                    "attempted to install a procedure with invalid UTF-8 strings.",
                    gimp_object_get_name (plug_in),
                    gimp_file_get_utf8_name (plug_in->file));
      g_free (canonical);
      return;
    }

  /*  Create the procedure object  */

  switch (proc_install->type)
    {
    case GIMP_PLUGIN:
    case GIMP_EXTENSION:
      procedure = gimp_plug_in_procedure_new (proc_install->type,
                                              plug_in->file);
      break;

    case GIMP_TEMPORARY:
      procedure = gimp_temporary_procedure_new (plug_in);
      break;
    }

  proc = GIMP_PLUG_IN_PROCEDURE (procedure);

  proc->mtime                 = time (NULL);
  proc->installed_during_init = (plug_in->call_mode == GIMP_PLUG_IN_CALL_INIT);

  gimp_object_take_name (GIMP_OBJECT (procedure), canonical);
  gimp_procedure_set_strings (procedure,
                              proc_install->name,
                              proc_install->blurb,
                              proc_install->help,
                              proc_install->author,
                              proc_install->copyright,
                              proc_install->date,
                              NULL);

  gimp_plug_in_procedure_set_image_types (proc, proc_install->image_types);

  for (i = 0; i < proc_install->nparams; i++)
    {
      GParamSpec *pspec =
        gimp_pdb_compat_param_spec (plug_in->manager->gimp,
                                    proc_install->params[i].type,
                                    proc_install->params[i].name,
                                    proc_install->params[i].description);

      gimp_procedure_add_argument (procedure, pspec);
    }

  for (i = 0; i < proc_install->nreturn_vals; i++)
    {
      GParamSpec *pspec =
        gimp_pdb_compat_param_spec (plug_in->manager->gimp,
                                    proc_install->return_vals[i].type,
                                    proc_install->return_vals[i].name,
                                    proc_install->return_vals[i].description);

      gimp_procedure_add_return_value (procedure, pspec);
    }

  /*  Sanity check menu path  */

  if (proc_install->menu_path && strlen (proc_install->menu_path))
    {
      if (proc_install->menu_path[0] == '<')
        {
          GError *error = NULL;

          if (! gimp_plug_in_procedure_add_menu_path (proc,
                                                      proc_install->menu_path,
                                                      &error))
            {
              gimp_message_literal (plug_in->manager->gimp,
                                    NULL, GIMP_MESSAGE_WARNING,
                                    error->message);
              g_clear_error (&error);
            }
        }
      else
        {
          proc->menu_label = g_strdup (proc_install->menu_path);
        }
    }

  /*  Install the procedure  */

  switch (proc_install->type)
    {
    case GIMP_PLUGIN:
    case GIMP_EXTENSION:
      gimp_plug_in_def_add_procedure (plug_in->plug_in_def, proc);
      break;

    case GIMP_TEMPORARY:
      gimp_plug_in_add_temp_proc (plug_in, GIMP_TEMPORARY_PROCEDURE (proc));
      break;
    }

  g_object_unref (proc);
}
Beispiel #18
0
GList *
gimp_palette_load (const gchar  *filename,
                   GError      **error)
{
  GimpPalette      *palette;
  GimpPaletteEntry *entry;
  gchar             str[1024];
  gchar            *tok;
  FILE             *file;
  gint              r, g, b;
  gint              linenum;

  g_return_val_if_fail (filename != NULL, NULL);
  g_return_val_if_fail (g_path_is_absolute (filename), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  r = g = b = 0;

  file = g_fopen (filename, "rb");

  if (! file)
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN,
                   _("Could not open '%s' for reading: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return NULL;
    }

  linenum = 1;
  if (! fgets (str, sizeof (str), file))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in palette file '%s': "
                     "Read error in line %d."),
                   gimp_filename_to_utf8 (filename), linenum);
      fclose (file);
      return NULL;
    }

  if (! g_str_has_prefix (str, "GIMP Palette"))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in palette file '%s': "
                     "Missing magic header."),
                   gimp_filename_to_utf8 (filename));
      fclose (file);
      return NULL;
    }

  palette = g_object_new (GIMP_TYPE_PALETTE,
                          "mime-type", "application/x-gimp-palette",
                          NULL);

  linenum++;
  if (! fgets (str, sizeof (str), file))
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Fatal parse error in palette file '%s': "
                     "Read error in line %d."),
                   gimp_filename_to_utf8 (filename), linenum);
      fclose (file);
      g_object_unref (palette);
      return NULL;
    }

  if (g_str_has_prefix (str, "Name: "))
    {
      gchar *utf8;

      utf8 = gimp_any_to_utf8 (g_strstrip (str + strlen ("Name: ")), -1,
                               _("Invalid UTF-8 string in palette file '%s'"),
                               gimp_filename_to_utf8 (filename));
      gimp_object_take_name (GIMP_OBJECT (palette), utf8);

      linenum++;
      if (! fgets (str, sizeof (str), file))
        {
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                       _("Fatal parse error in palette file '%s': "
                         "Read error in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);
          fclose (file);
          g_object_unref (palette);
          return NULL;
        }

      if (g_str_has_prefix (str, "Columns: "))
        {
          gint columns;

          columns = atoi (g_strstrip (str + strlen ("Columns: ")));

          if (columns < 0 || columns > 256)
            {
              g_message (_("Reading palette file '%s': "
                           "Invalid number of columns in line %d. "
                           "Using default value."),
                         gimp_filename_to_utf8 (filename), linenum);
              columns = 0;
            }

          palette->n_columns = columns;

          linenum++;
          if (! fgets (str, sizeof (str), file))
            {
              g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                           _("Fatal parse error in palette file '%s': "
                             "Read error in line %d."),
                           gimp_filename_to_utf8 (filename), linenum);
              fclose (file);
              g_object_unref (palette);
              return NULL;
            }
        }
    }
  else /* old palette format */
    {
      gimp_object_take_name (GIMP_OBJECT (palette),
                             g_filename_display_basename (filename));
    }

  while (! feof (file))
    {
      if (str[0] != '#' && str[0] != '\n')
        {
          tok = strtok (str, " \t");
          if (tok)
            r = atoi (tok);
          else
            g_message (_("Reading palette file '%s': "
                         "Missing RED component in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);

          tok = strtok (NULL, " \t");
          if (tok)
            g = atoi (tok);
          else
            g_message (_("Reading palette file '%s': "
                         "Missing GREEN component in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);

          tok = strtok (NULL, " \t");
          if (tok)
            b = atoi (tok);
          else
            g_message (_("Reading palette file '%s': "
                         "Missing BLUE component in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);

          /* optional name */
          tok = strtok (NULL, "\n");

          if (r < 0 || r > 255 ||
              g < 0 || g > 255 ||
              b < 0 || b > 255)
            g_message (_("Reading palette file '%s': "
                         "RGB value out of range in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);

          /* don't call gimp_palette_add_entry here, it's rather inefficient */
          entry = g_slice_new0 (GimpPaletteEntry);

          gimp_rgba_set_uchar (&entry->color,
                               (guchar) r,
                               (guchar) g,
                               (guchar) b,
                               255);

          entry->name     = g_strdup (tok ? tok : _("Untitled"));
          entry->position = palette->n_colors;

          palette->colors = g_list_prepend (palette->colors, entry);
          palette->n_colors++;
        }

      linenum++;
      if (! fgets (str, sizeof (str), file))
        {
          if (feof (file))
            break;

          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                       _("Fatal parse error in palette file '%s': "
                         "Read error in line %d."),
                       gimp_filename_to_utf8 (filename), linenum);
          fclose (file);
          g_object_unref (palette);
          return NULL;
        }
    }

  fclose (file);

  palette->colors = g_list_reverse (palette->colors);

  return g_list_prepend (NULL, palette);
}
Beispiel #19
0
static void
gimp_item_prop_undo_pop (GimpUndo            *undo,
                         GimpUndoMode         undo_mode,
                         GimpUndoAccumulator *accum)
{
  GimpItemPropUndo *item_prop_undo = GIMP_ITEM_PROP_UNDO (undo);
  GimpItem         *item           = GIMP_ITEM_UNDO (undo)->item;

  GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);

  switch (undo->undo_type)
    {
    case GIMP_UNDO_ITEM_RENAME:
      {
        gchar *name;

        name = g_strdup (gimp_object_get_name (GIMP_OBJECT (item)));
        gimp_object_take_name (GIMP_OBJECT (item), item_prop_undo->name);
        item_prop_undo->name = name;
      }
      break;

    case GIMP_UNDO_ITEM_DISPLACE:
      {
        gint offset_x;
        gint offset_y;

        gimp_item_offsets (item, &offset_x, &offset_y);

        gimp_item_translate (item,
                             item_prop_undo->offset_x - offset_x,
                             item_prop_undo->offset_y - offset_y,
                             FALSE);

        item_prop_undo->offset_x = offset_x;
        item_prop_undo->offset_y = offset_y;
      }
      break;

    case GIMP_UNDO_ITEM_VISIBILITY:
      {
        gboolean visible;

        visible = gimp_item_get_visible (item);
        gimp_item_set_visible (item, item_prop_undo->visible, FALSE);
        item_prop_undo->visible = visible;
      }
      break;

    case GIMP_UNDO_ITEM_LINKED:
      {
        gboolean linked;

        linked = gimp_item_get_linked (item);
        gimp_item_set_linked (item, item_prop_undo->linked, FALSE);
        item_prop_undo->linked = linked;
      }
      break;

    case GIMP_UNDO_PARASITE_ATTACH:
    case GIMP_UNDO_PARASITE_REMOVE:
      {
        GimpParasite *parasite;

        parasite = item_prop_undo->parasite;

        item_prop_undo->parasite = gimp_parasite_copy
          (gimp_item_parasite_find (item, item_prop_undo->parasite_name));

        if (parasite)
          gimp_parasite_list_add (item->parasites, parasite);
        else
          gimp_parasite_list_remove (item->parasites,
                                     item_prop_undo->parasite_name);

        if (parasite)
          gimp_parasite_free (parasite);
      }
      break;

    default:
      g_assert_not_reached ();
    }
}
Beispiel #20
0
static void
gimp_list_uniquefy_name (GimpList   *gimp_list,
                         GimpObject *object)
{
  GList *list;
  GList *list2;
  gint   unique_ext = 0;
  gchar *new_name   = NULL;
  gchar *ext;

  g_return_if_fail (GIMP_IS_LIST (gimp_list));
  g_return_if_fail (GIMP_IS_OBJECT (object));

  for (list = gimp_list->list; list; list = g_list_next (list))
    {
      GimpObject *object2 = GIMP_OBJECT (list->data);

      if (object != object2 &&
          strcmp (gimp_object_get_name (GIMP_OBJECT (object)),
                  gimp_object_get_name (GIMP_OBJECT (object2))) == 0)
        {
          ext = strrchr (object->name, '#');

          if (ext)
            {
              gchar *ext_str;

              unique_ext = atoi (ext + 1);

              ext_str = g_strdup_printf ("%d", unique_ext);

              /*  check if the extension really is of the form "#<n>"  */
              if (! strcmp (ext_str, ext + 1))
                {
                  *ext = '\0';
                }
              else
                {
                  unique_ext = 0;
                }

              g_free (ext_str);
            }
          else
            {
              unique_ext = 0;
            }

          do
            {
              unique_ext++;

              g_free (new_name);

              new_name = g_strdup_printf ("%s#%d", object->name, unique_ext);

              for (list2 = gimp_list->list; list2; list2 = g_list_next (list2))
                {
                  object2 = GIMP_OBJECT (list2->data);

                  if (object == object2)
                    continue;

                  if (! strcmp (object2->name, new_name))
                    break;
                }
            }
          while (list2);

          gimp_object_take_name (object, new_name);
          break;
        }
    }
}
Beispiel #21
0
static void
tool_manager_preset_changed (GimpContext     *user_context,
                             GimpToolPreset  *preset,
                             GimpToolManager *tool_manager)
{
  GimpToolInfo *preset_tool;
  gchar        *options_name;
  gboolean      tool_change = FALSE;

  if (! preset || user_context->gimp->busy)
    return;

  preset_tool = gimp_context_get_tool (GIMP_CONTEXT (preset->tool_options));

  if (preset_tool != gimp_context_get_tool (user_context))
    tool_change = TRUE;

  if (! tool_change)
    tool_manager_disconnect_options (tool_manager, user_context, preset_tool);

  /*  save the name, we don't want to overwrite it  */
  options_name = g_strdup (gimp_object_get_name (preset_tool->tool_options));

  gimp_config_copy (GIMP_CONFIG (preset->tool_options),
                    GIMP_CONFIG (preset_tool->tool_options), 0);

  /*  restore the saved name  */
  gimp_object_take_name (GIMP_OBJECT (preset_tool->tool_options), options_name);

  if (tool_change)
    gimp_context_set_tool (user_context, preset_tool);
  else
    tool_manager_connect_options (tool_manager, user_context, preset_tool);

  gimp_context_copy_properties (GIMP_CONTEXT (preset->tool_options),
                                user_context,
                                gimp_tool_preset_get_prop_mask (preset));

  if (GIMP_IS_PAINT_OPTIONS (preset->tool_options))
    {
      GimpCoreConfig  *config = user_context->gimp->config;
      GimpToolOptions *src    = preset->tool_options;
      GimpToolOptions *dest   = tool_manager->active_tool->tool_info->tool_options;

      /* if connect_options() did overwrite the brush options and the
       * preset contains a brush, use the brush options from the
       * preset
       */
      if (config->global_brush && preset->use_brush)
        gimp_paint_options_copy_brush_props (GIMP_PAINT_OPTIONS (src),
                                             GIMP_PAINT_OPTIONS (dest));

      if (config->global_dynamics && preset->use_dynamics)
        gimp_paint_options_copy_dynamics_props (GIMP_PAINT_OPTIONS (src),
                                                GIMP_PAINT_OPTIONS (dest));

      if (config->global_gradient && preset->use_gradient)
        gimp_paint_options_copy_gradient_props (GIMP_PAINT_OPTIONS (src),
                                                GIMP_PAINT_OPTIONS (dest));
    }
}
Beispiel #22
0
static void
gimp_warp_tool_animate (GimpWarpTool *wt)
{
  GimpTool        *tool    = GIMP_TOOL (wt);
  GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
  GimpImage       *orig_image;
  GimpImage       *image;
  GimpLayer       *layer;
  GimpLayer       *first_layer;
  GeglNode        *scale_node;
  GimpProgress    *progress;
  GtkWidget       *widget;
  gint             i;

  if (! gimp_warp_tool_get_undo_desc (tool, tool->display))
    {
      gimp_tool_message_literal (tool, tool->display,
                                 _("Please add some warp strokes first."));
      return;
    }

  /*  get rid of the image map so we can use wt->graph  */
  if (wt->image_map)
    {
      gimp_image_map_abort (wt->image_map);
      g_object_unref (wt->image_map);
      wt->image_map = NULL;
    }

  gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
                       _("Rendering Frame %d"), 1);

  orig_image = gimp_item_get_image (GIMP_ITEM (tool->drawable));

  image = gimp_create_image (orig_image->gimp,
                             gimp_item_get_width  (GIMP_ITEM (tool->drawable)),
                             gimp_item_get_height (GIMP_ITEM (tool->drawable)),
                             gimp_drawable_get_base_type (tool->drawable),
                             gimp_drawable_get_precision (tool->drawable),
                             TRUE);

  /*  the first frame is always the unwarped image  */
  layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (tool->drawable), image,
                                         GIMP_TYPE_LAYER));
  gimp_object_take_name (GIMP_OBJECT (layer),
                         g_strdup_printf (_("Frame %d"), 1));

  gimp_item_set_offset (GIMP_ITEM (layer), 0, 0);
  gimp_item_set_visible (GIMP_ITEM (layer), TRUE, FALSE);
  gimp_layer_set_mode (layer, GIMP_NORMAL_MODE, FALSE);
  gimp_layer_set_opacity (layer, GIMP_OPACITY_OPAQUE, FALSE);
  gimp_image_add_layer (image, layer, NULL, 0, FALSE);

  first_layer = layer;

  scale_node = gegl_node_new_child (NULL,
                                    "operation",    "gimp:scalar-multiply",
                                    "n-components", 2,
                                    NULL);
  gimp_warp_tool_add_op (wt, scale_node);

  progress = gimp_sub_progress_new (GIMP_PROGRESS (tool));

  for (i = 1; i < options->n_animation_frames; i++)
    {
      gimp_progress_set_text (GIMP_PROGRESS (tool),
                              _("Rendering Frame %d"), i + 1);

      gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (progress),
                                  i, options->n_animation_frames);

      layer = GIMP_LAYER (gimp_item_duplicate (GIMP_ITEM (first_layer),
                                               GIMP_TYPE_LAYER));
      gimp_object_take_name (GIMP_OBJECT (layer),
                             g_strdup_printf (_("Frame %d"), i + 1));

      gegl_node_set (scale_node,
                     "factor", (gdouble) i /
                               (gdouble) (options->n_animation_frames - 1),
                     NULL);

      gimp_gegl_apply_operation (gimp_drawable_get_buffer (GIMP_DRAWABLE (first_layer)),
                                 progress,
                                 _("Frame"),
                                 wt->graph,
                                 gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
                                 NULL);

      gimp_image_add_layer (image, layer, NULL, 0, FALSE);
    }

  g_object_unref (progress);

  gimp_warp_tool_remove_op (wt, scale_node);

  gimp_progress_end (GIMP_PROGRESS (tool));

  /*  recreate the image map  */
  gimp_warp_tool_create_image_map (wt, tool->drawable);
  gimp_image_map_apply (wt->image_map, NULL);

  widget = GTK_WIDGET (gimp_display_get_shell (tool->display));
  gimp_create_display (orig_image->gimp, image, GIMP_UNIT_PIXEL, 1.0,
                       G_OBJECT (gtk_widget_get_screen (widget)),
                       gimp_widget_get_monitor (widget));
  g_object_unref (image);
}