gimp/plug-ins/gap/gap_exchange_image.c
Sven Neumann 243c5f4929 app/channel_cmds.c app/layer_cmds.c libgimp/gimpchannel_pdb.c
2000-12-28  Sven Neumann  <sven@gimp.org>

	* app/channel_cmds.c
	* app/layer_cmds.c
	* libgimp/gimpchannel_pdb.c
	* libgimp/gimplayer_pdb.c
	* plug-ins/common/warp.c
	* plug-ins/gap/gap_exchange_image.c
	* plug-ins/gap/gap_range_ops.c
	* plug-ins/perl/examples/bricks
	* plug-ins/perl/examples/glowing_steel
	* tools/pdbgen/pdb/channel.pdb
	* tools/pdbgen/pdb/layer.pdb:

	Two of the gimp-perl scripts used to call gimp_layer_delete() after
	gimp_image_remove_layer(). This will fail since the layer is already
	scheduled for destruction by removing it from the associated image or
	by deleting that image. It is thus dangerous and superfluous to export
	this feature through the PDB. The gimp_layer_delete() is hereby
	obsolete and does nothing any longer. I have removed the code calling
	it from all over the place (it was commented out in almost all places).

	The PDB help for gimp_channel_delete() now explicetly tells the user
	about the proper usage of the procedure.
2000-12-27 23:49:17 +00:00

531 lines
18 KiB
C

/* gap_exchange_image.c
* by hof (Wolfgang Hofer)
*
* GAP ... Gimp Animation Plugins
*
* basic anim functions:
* This Plugin drops the content of the destination
* image (all layers,channels, paths, parasites & guides)
* and then moves (steal) the content of a source image to dst. image
*
*/
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* revision history:
* 1.1.20a 2000/04/29 hof: bugfix in p_steal_content: we must copy cmap before removing layers
* from src_image to avoid crash on indexed frames.
* 1.1.16a 2000/02/05 hof: handle path lockedstaus and image unit
* 1.1.15b 2000/01/30 hof: handle image specific parasites
* 1.1.15a 2000/01/25 hof: stopped gimp 1.0.x support (removed p_copy_content)
* handle pathes
* 0.98.00; 1998/11/30 hof: 1.st release
* (substitute for the procedure "gimp_duplicate_into"
* that was never part of the GIMP core)
*/
/* SYTEM (UNIX) includes */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <errno.h>
/* GIMP includes */
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* GAP includes */
#include "gap_layer_copy.h"
#include "gap_pdb_calls.h"
#include "gap_exchange_image.h"
#include "gap_lib.h"
extern int gap_debug; /* ==0 ... dont print debug infos */
/* ============================================================================
* p_steal_content
*
* steal or copy all elements
* - layers,
* - channels, selections,
* - pathes,
* - guides,
* - colormap
* from src_image and add them to dst_image.
* ============================================================================
*/
static int
p_steal_content(gint32 dst_image_id, gint32 src_image_id)
{
int l_rc;
int l_idx;
gint l_nlayers;
gint l_nchannels;
gint32 *l_layers_list;
gint32 *l_channels_list;
gint32 l_layer_id;
gint32 l_channel_id;
gint32 l_new_channel_id;
gint32 l_layer_mask_id;
gint32 l_guide_id;
gint32 l_src_fsel_id; /* floating selection (in the src_image) */
gint32 l_src_fsel_attached_to_id; /* the drawable where floating selection is attached to (in the src_image) */
gint32 l_fsel_attached_to_id; /* the drawable id where to attach the floating selection (dst) */
gint32 l_fsel_id; /* the drawable id of the floating selection itself (dst) */
gint32 l_active_layer_id;
gint32 l_active_channel_id;
gint32 l_x1, l_x2, l_y1, l_y2;
guchar *l_cmap;
gint l_ncolors;
gchar **l_path_names;
gchar *l_current_pathname;
gint32 l_num_paths;
gdouble *l_path_points;
gint32 l_path_type;
gint32 l_path_closed;
gint32 l_num_points;
GimpParasite *l_parasite;
gchar **l_parasite_names = NULL;
gint32 l_num_parasites = 0;
l_rc = -1; /* init retcode to Errorstate */
l_layers_list = NULL;
l_channels_list = NULL;
l_active_layer_id = -1;
l_active_channel_id = -1;
l_fsel_attached_to_id = -1; /* -1 assume fsel is not available (and not attached to any drawable) */
l_fsel_id = -1; /* -1 assume there is no floating selection */
if(gap_debug) printf("GAP-DEBUG: START p_steal_content dst_id=%d src_id=%d\n", (int)dst_image_id, (int)src_image_id);
/* gimp_image_undo_disable (src_image_id); */ /* does not work !! if active we can not steal layers */
/* Copy the colormap if necessary */
if(gimp_image_base_type(src_image_id) == GIMP_INDEXED)
{
l_cmap = gimp_image_get_cmap (src_image_id, &l_ncolors);
if(gap_debug) printf("GAP-DEBUG: copy colormap ncolors %d\n", (int)l_ncolors);
gimp_image_set_cmap(dst_image_id, l_cmap, l_ncolors);
}
/* check for floating selection */
l_src_fsel_attached_to_id = -1;
l_src_fsel_id = gimp_image_floating_selection(src_image_id);
if(l_src_fsel_id >= 0)
{
if(gap_debug) printf("GAP-DEBUG: call floating_sel_relax fsel_id=%d\n",
(int)l_src_fsel_id);
p_gimp_floating_sel_relax (l_src_fsel_id, FALSE);
l_src_fsel_attached_to_id = p_gimp_image_floating_sel_attached_to(src_image_id);
}
/* steal all layers */
l_layers_list = gimp_image_get_layers(src_image_id, &l_nlayers);
/* foreach layer do */
for(l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
{
l_layer_id = l_layers_list[l_idx];
if(gap_debug) printf("GAP-DEBUG: START p_steal_content layer_id[%d]=%d\n", (int)l_idx, (int)l_layer_id);
if(l_layer_id == gimp_image_get_active_layer(src_image_id))
{
l_active_layer_id = l_layer_id;
}
l_layer_mask_id = gimp_layer_get_mask_id(l_layer_id);
if(l_layer_mask_id >= 0)
{
/* layer has layermask */
if(gap_debug) printf("GAP-DEBUG: START p_steal_content layer_mask_id=%d\n", (int)l_layer_mask_id);
/* check for floating selection */
if(l_layer_mask_id == l_src_fsel_attached_to_id)
{
l_fsel_attached_to_id = l_layer_mask_id; /* the floating selection is attached to this layer_mask */
}
p_gimp_drawable_set_image(l_layer_mask_id, dst_image_id);
}
/* remove layer from source */
gimp_image_remove_layer(src_image_id, l_layer_id);
/* and set the dst_image as it's new Master */
p_gimp_drawable_set_image(l_layer_id, dst_image_id);
if(l_layer_id == l_src_fsel_id)
{
l_fsel_id = l_layer_id; /* this layer is the floating selection */
}
else
{
if(gap_debug) printf("GAP-DEBUG: START p_steal_content add_layer_id=%d\n", (int)l_layer_id);
/* add the layer on top of the images layerstak */
gimp_image_add_layer (dst_image_id, l_layer_id, 0);
if(l_layer_id == l_src_fsel_attached_to_id)
{
l_fsel_attached_to_id = l_layer_id; /* the floating selection is attached to this layer */
}
}
} /* end foreach layer */
/* steal all channels */
l_channels_list = gimp_image_get_channels(src_image_id, &l_nchannels);
/* foreach channel do */
for(l_idx = l_nchannels -1; l_idx >= 0; l_idx--)
{
l_channel_id = l_channels_list[l_idx];
if(gap_debug) printf("GAP-DEBUG: START p_steal_content channel_id=%d\n", (int)l_channel_id);
l_new_channel_id = p_my_channel_copy(dst_image_id, l_channel_id);
if (l_new_channel_id < 0) { goto cleanup; }
/* add channel on top of the channelstack */
gimp_image_add_channel (dst_image_id, l_new_channel_id, 0);
/* adjust channelproperties */
gimp_channel_set_visible (l_new_channel_id, gimp_channel_get_visible(l_channel_id));
gimp_channel_set_show_masked (l_new_channel_id, gimp_channel_get_show_masked(l_channel_id));
if(l_channel_id == l_src_fsel_attached_to_id)
{
l_fsel_attached_to_id = l_channel_id; /* the floating_selection is attached to this channel */
}
if(l_channel_id == gimp_image_get_active_channel(src_image_id))
{
l_active_channel_id = l_channel_id;
}
/* remove channel from source */
gimp_image_remove_channel(src_image_id, l_channel_id);
/* and set the dst_image as it's new Master */
p_gimp_drawable_set_image(l_channel_id, dst_image_id);
} /* end foreach channel */
/* check and see if we have to copy the selection */
l_channel_id = gimp_image_get_selection(src_image_id);
if((p_get_gimp_selection_bounds(src_image_id, &l_x1, &l_y1, &l_x2, &l_y2))
&& (l_channel_id >= 0))
{
if(gap_debug) printf("GAP-DEBUG: START p_steal_content selection_channel_id=%d\n", (int)l_channel_id);
p_gimp_drawable_set_image(l_channel_id, dst_image_id);
p_gimp_selection_load (l_channel_id);
}
/* attach the floating selection... */
if((l_fsel_id >= 0) && (l_fsel_attached_to_id >= 0))
{
if(gap_debug) printf("GAP-DEBUG: attaching floating_selection id=%d to id %d\n",
(int)l_fsel_id, (int)l_fsel_attached_to_id);
if(p_gimp_floating_sel_attach (l_fsel_id, l_fsel_attached_to_id) < 0)
{
/* in case of error add floating_selection like an ordinary layer
* (if patches are not installed you'll get the error for sure)
*/
printf("GAP: floating_selection is added as top-layer (attach failed)\n");
gimp_image_add_layer (dst_image_id, l_fsel_id, 0);
}
}
/* set active layer/channel */
if(l_active_channel_id >= 0)
{
if(gap_debug) printf("GAP-DEBUG: SET active channel %d\n", (int)l_active_channel_id);
gimp_image_set_active_channel(dst_image_id, l_active_channel_id);
}
if(l_active_layer_id >= 0)
{
if(gap_debug) printf("GAP-DEBUG: SET active layer %d\n", (int)l_active_layer_id);
gimp_image_set_active_layer(dst_image_id, l_active_layer_id);
}
/* copy guides */
l_guide_id = p_gimp_image_findnext_guide(src_image_id, 0); /* get 1.st guide */
while(l_guide_id > 0)
{
/* get position and orientation for the current guide ID */
p_gimp_image_add_guide(dst_image_id,
p_gimp_image_get_guide_position(src_image_id, l_guide_id),
p_gimp_image_get_guide_orientation(src_image_id, l_guide_id)
);
l_guide_id = p_gimp_image_findnext_guide(src_image_id, l_guide_id);
}
/* copy paths */
l_path_names = p_gimp_path_list(src_image_id, &l_num_paths);
if((l_path_names != NULL) && (l_num_paths > 0))
{
l_current_pathname = p_gimp_path_get_current(src_image_id);
for(l_idx=l_num_paths-1; l_idx >= 0; l_idx--)
{
l_path_points = p_gimp_path_get_points(src_image_id, l_path_names[l_idx],
&l_path_type, &l_path_closed, &l_num_points);
if((l_path_points != NULL) && (l_num_points > 0))
{
p_gimp_path_set_points(dst_image_id, l_path_names[l_idx],
l_path_type, l_num_points, l_path_points);
p_gimp_path_set_locked(dst_image_id, l_path_names[l_idx],
p_gimp_path_get_locked(src_image_id, l_path_names[l_idx]));
}
if(l_path_points) g_free(l_path_points);
g_free(l_path_names[l_idx]);
}
if(l_current_pathname)
{
p_gimp_path_set_current(dst_image_id, l_current_pathname);
g_free(l_current_pathname);
}
}
if(l_path_names) g_free(l_path_names);
/* copy image specific parasites
* (drawable specific parasites are handled implicite
* by stealing layers and channels)
*/
l_parasite_names = p_gimp_image_parasite_list (src_image_id, &l_num_parasites);
for(l_idx = 0; l_idx < l_num_parasites; l_idx++)
{
l_parasite = gimp_image_parasite_find(src_image_id, l_parasite_names[l_idx]);
if(l_parasite)
{
if(gap_debug) printf("copy image_parasite NAME:%s:\n", l_parasite_names[l_idx]);
gimp_image_attach_new_parasite(dst_image_id,
l_parasite->name,
l_parasite->flags,
l_parasite->size,
l_parasite->data);
if(l_parasite->data) g_free(l_parasite->data);
if(l_parasite->name) g_free(l_parasite->name);
g_free(l_parasite);
}
g_free(l_parasite_names[l_idx]);
}
g_free(l_parasite_names);
/* copy the image unit */
gimp_image_set_unit(dst_image_id,
gimp_image_get_unit(src_image_id));
l_rc = 0;
cleanup:
if(l_layers_list) g_free (l_layers_list);
if(l_channels_list) g_free (l_channels_list);
if(gap_debug) printf("GAP-DEBUG: END p_steal_content dst_id=%d src_id=%d rc=%d\n",
(int)dst_image_id, (int)src_image_id, l_rc);
return (l_rc); /* 0 .. OK, or -1 on error */
} /* end p_steal_content */
/* ============================================================================
* p_replace_img
*
* This procedure replaces the content of image_id
* with the content from src_image_id.
* By stealing all its layers and channels.
* ============================================================================
*/
static int
p_replace_img(gint32 image_id, gint32 src_image_id)
{
int l_rc;
int l_idx;
gint l_nlayers;
gint l_nchannels;
gint32 *l_layers_list;
gint32 *l_channels_list;
gint32 l_layer_id;
gint32 l_channel_id;
gint32 l_guide_id;
gint32 l_old_bg_layer_id;
gchar **l_path_names;
gint32 l_num_paths;
gchar **l_parasite_names = NULL;
gint32 l_num_parasites = 0;
if(gap_debug) printf("\nGAP-DEBUG: START p_replace_img img_id=%d \n", (int)image_id);
l_old_bg_layer_id = -1;
gimp_image_undo_disable (image_id);
/* remove selection (if there is any) */
p_gimp_selection_none(image_id);
l_channels_list = gimp_image_get_channels(image_id, &l_nchannels);
/* foreach channel do */
for(l_idx = 0; l_idx < l_nchannels; l_idx++)
{
l_channel_id = l_channels_list[l_idx];
gimp_image_remove_channel(image_id, l_channel_id);
}
if(l_channels_list) { g_free (l_channels_list); }
/* delete guides */
l_guide_id = p_gimp_image_findnext_guide(image_id, 0); /* get 1.st guide */
while(l_guide_id > 0)
{
/* delete guide ID */
p_gimp_image_delete_guide(image_id, l_guide_id);
/* get 1.st (of the remaining) guides */
l_guide_id = p_gimp_image_findnext_guide(image_id, 0);
}
/* delete paths */
l_path_names = p_gimp_path_list(image_id, &l_num_paths);
if((l_path_names != NULL) && (l_num_paths > 0))
{
for(l_idx=0; l_idx < l_num_paths; l_idx++)
{
p_gimp_path_delete(image_id, l_path_names[l_idx]);
g_free(l_path_names[l_idx]);
}
}
if(l_path_names) g_free(l_path_names);
/* remove image specific parasites */
l_parasite_names = p_gimp_image_parasite_list (image_id, &l_num_parasites);
if(l_parasite_names)
{
for(l_idx = 0; l_idx < l_num_parasites; l_idx++)
{
if(gap_debug) printf("detach image_parasite NAME:%s:\n", l_parasite_names[l_idx]);
gimp_image_parasite_detach(image_id, l_parasite_names[l_idx]);
g_free(l_parasite_names[l_idx]);
}
g_free(l_parasite_names);
}
/* get list of all (old) dst_layers to delete */
l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
/* foreach (old) layer of the do */
for(l_idx = 0; l_idx < l_nlayers; l_idx++)
{
l_layer_id = l_layers_list[l_idx];
if(l_idx == l_nlayers -1)
{
/* the background layer is renamed
* (if not GIMP 1.1 will rename the new imported
* Background Layer as "background#2")
* and deleted later.
* Important: the dst_image_id should not be completely empty.
* anytime it may happen, that its display(s) is (are) updated
* and this may crash on empty images.
*/
gimp_layer_set_name(l_layer_id, "--old-bg-layer-will-die-soon");
l_old_bg_layer_id = l_layer_id;
}
else
{
if(gap_debug) printf("GAP-DEBUG: p_replace_img del layer_id=%d \n", (int)l_layer_id);
gimp_image_remove_layer(image_id, l_layer_id);
}
}
/* steal all layers, channels and guides from src_image */
l_rc = p_steal_content(image_id, src_image_id);
if(l_old_bg_layer_id >= 0)
{
/* now delete the (old) background layer */
if(gap_debug) printf("GAP-DEBUG: p_replace_img del (old bg) layer_id=%d \n", (int)l_old_bg_layer_id);
gimp_image_remove_layer(image_id, l_old_bg_layer_id);
}
if (l_layers_list) { g_free (l_layers_list); }
gimp_image_undo_enable (image_id);
if(gap_debug) printf("GAP-DEBUG: END p_replace_img img_id=%d rc=%d\n", (int)image_id, l_rc);
return l_rc; /* OK */
} /* end p_replace_img */
/* ============================================================================
* p_exchange_image
*
*
* ============================================================================
*/
int p_exchange_image(gint32 dst_image_id, gint32 src_image_id)
{
int l_rc;
/* check for equal image type */
if(gimp_image_base_type(src_image_id) != gimp_image_base_type(dst_image_id))
{
printf("GAP: p_exchange_image Image Types are not equal\n");
return -1;
}
/* check for equal width/height */
if((gimp_image_height(src_image_id) != gimp_image_height(dst_image_id))
|| (gimp_image_width(src_image_id) != gimp_image_width(dst_image_id)))
{
printf("GAP: p_exchange_image Image Size is not equal\n");
return -1;
}
/* Now we drop content and copy (or steal) from src_image
* step by step, using many other PDB-Interfaces.
*/
l_rc = p_replace_img(dst_image_id, src_image_id);
return (l_rc);
} /* end p_exchange_image */