diff --git a/ChangeLog b/ChangeLog index 64db2444f0..041dc8d4e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,86 @@ +2001-11-28 Michael Natterer + + * app/base/base-types.h: include the new + "paint-funcs/paint-funcs-types.h". + + * app/paint-funcs/Makefile.am + * app/paint-funcs/paint-funcs-types.h: new file. Includes + "base/base-types.h". + + * app/paint-funcs/paint-funcs.[ch]: removed the enums here, + include "paint-funcs-types.h". + + * app/widgets/widgets-types.h: include "display/display-types.h" + + * app/display/display-types.h: include "widgets/widgets-types.h". + + * app/tools/tools-types.h: include "display/display-types.h" + + * app/gui/gui-types.h: include "tools/tools-types.h". + + The order of namespaces/dependencies should be (but is not): + + (base, paint-funcs) -> (core, file, xcf, pdb) -> + (widgets, display) -> tools -> gui + + * app/path.c: include "tools/tools-types.h". + + * app/core/Makefile.am + * app/core/gimpimage-guides.[ch] + * app/core/gimpimage-merge.[ch] + * app/core/gimpimage-resize.[ch] + * app/core/gimpimage-scale.[ch]: new files. + + * app/core/gimpimage.[ch]: removed the stuff which is in the new + files. Reordered all functions in both the .h and .c files, + commented the groups of functions. + + * app/core/gimpcontainer.c: create the handler_id using a counter, + not the address of a pointer, because the address *may* be the + same twice, added debugging output. + + * app/core/gimpviewable.[ch]: added primitive support for getting + a preview GdkPixbuf. + + * app/nav_window.c + * app/undo.c + * app/undo_history.c + * app/core/gimpimage-duplicate.c + * app/core/gimpimage-mask.[ch] + * app/display/gimpdisplay.c + * app/display/gimpdisplayshell-callbacks.c + * app/display/gimpdisplayshell-dnd.c + * app/display/gimpdisplayshell-render.c + * app/display/gimpdisplayshell-scale.c + * app/display/gimpdisplayshell-scroll.c + * app/gui/image-commands.c + * app/gui/info-window.c + * app/gui/layers-commands.c + * app/gui/palette-import-dialog.c + * app/tools/gimpbycolorselecttool.c + * app/tools/gimpeditselectiontool.c + * app/tools/gimpmeasuretool.c + * app/tools/gimpmovetool.c + * app/widgets/gimpcontainerview-utils.c + * app/xcf/xcf-load.c: changed accordingly, some cleanup. + + * tools/pdbgen/pdb/guides.pdb + * tools/pdbgen/pdb/image.pdb: changed accordingly, reordered functions. + + * app/plug_in.c: set the labels of the "Repeat" and "Re-Show" menu + items to the name of the last plug-in (Fixes #50986). + + * app/display/gimpdisplayshell.[ch]: set the labels of "Undo" and + "Redo" to the resp. undo names. Much simplified the WM icon stuff + by removing most code and using gimp_viewable_get_new_preview_pixbuf(). + + * app/widgets/gimpbrushfactoryview.c: forgot to assign the GQuark + returned by gimp_container_add_handler(). + + * app/pdb/guides_cmds.c + * app/pdb/image_cmds.c + * libgimp/gimpimage_pdb.[ch]: regenerated. + 2001-11-28 Kelly Martin * app/undo.c: Fixed evil double casting of enum to glong to @@ -17,7 +100,7 @@ names to be consistent. * app/core/gimpimage.[ch]: removed the projection stuff - here. Removed the gimp_image_composite_blah() functions becauee + here. Removed the gimp_image_composite_blah() functions because they were just calling the resp. gimp_image_projection ones. * app/core/gimpimage-contiguous-region.c diff --git a/app/actions/image-commands.c b/app/actions/image-commands.c index d2f6b4fa3d..6c07c7632f 100644 --- a/app/actions/image-commands.c +++ b/app/actions/image-commands.c @@ -31,6 +31,8 @@ #include "core/gimpdrawable-equalize.h" #include "core/gimpimage.h" #include "core/gimpimage-duplicate.h" +#include "core/gimpimage-resize.h" +#include "core/gimpimage-scale.h" #include "pdb/procedural_db.h" diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c index ff50ec7b73..8ca4d9a538 100644 --- a/app/actions/layers-commands.c +++ b/app/actions/layers-commands.c @@ -33,6 +33,7 @@ #include "core/gimp.h" #include "core/gimpimage.h" #include "core/gimpimage-mask.h" +#include "core/gimpimage-merge.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" #include "core/gimplist.h" diff --git a/app/actions/plug-in-commands.c b/app/actions/plug-in-commands.c index b5a352ecaa..e85060d12b 100644 --- a/app/actions/plug-in-commands.c +++ b/app/actions/plug-in-commands.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/base/base-types.h b/app/base/base-types.h index bacc3b4da6..181f73f232 100644 --- a/app/base/base-types.h +++ b/app/base/base-types.h @@ -20,6 +20,9 @@ #define __BASE_TYPES_H__ +#include "paint-funcs/paint-funcs-types.h" + + /* magic constants */ #define MAX_CHANNELS 4 diff --git a/app/core/Makefile.am b/app/core/Makefile.am index efb60b2f49..0398972261 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -85,14 +85,22 @@ libappcore_a_sources = @STRIP_BEGIN@ \ gimpimage-crop.h \ gimpimage-duplicate.c \ gimpimage-duplicate.h \ + gimpimage-guides.c \ + gimpimage-guides.h \ gimpimage-mask.c \ gimpimage-mask.h \ gimpimage-mask-select.c \ gimpimage-mask-select.h \ + gimpimage-merge.c \ + gimpimage-merge.h \ gimpimage-new.c \ gimpimage-new.h \ gimpimage-projection.c \ gimpimage-projection.h \ + gimpimage-resize.c \ + gimpimage-resize.h \ + gimpimage-scale.c \ + gimpimage-scale.h \ gimpimage-undo.c \ gimpimage-undo.h \ gimpimagefile.c \ diff --git a/app/core/gimpcontainer.c b/app/core/gimpcontainer.c index 7cf684cf9c..c4273e5901 100644 --- a/app/core/gimpcontainer.c +++ b/app/core/gimpcontainer.c @@ -623,6 +623,8 @@ gimp_container_add_handler (GimpContainer *container, GimpContainerHandler *handler; gchar *key; + static gint handler_id = 0; + g_return_val_if_fail (GIMP_IS_CONTAINER (container), 0); g_return_val_if_fail (signame != NULL, 0); @@ -632,13 +634,15 @@ gimp_container_add_handler (GimpContainer *container, handler = g_new0 (GimpContainerHandler, 1); /* create a unique key for this handler */ - key = g_strdup_printf ("%s-%p", signame, handler); + key = g_strdup_printf ("%s-%d", signame, handler_id++); handler->signame = g_strdup (signame); handler->callback = callback; handler->callback_data = callback_data; handler->quark = g_quark_from_string (key); + g_print ("%s: key = %s, id = %d\n", G_GNUC_FUNCTION, key, handler->quark); + g_free (key); container->handlers = g_list_prepend (container->handlers, handler); @@ -688,10 +692,13 @@ gimp_container_remove_handler (GimpContainer *container, if (! list) { - g_warning ("tried to disconnect handler which is not connected"); + g_warning ("%s: tried to unhandler which id %d", + G_STRLOC, id); return; } + g_print ("%s: id = %d\n", G_GNUC_FUNCTION, handler->quark); + gimp_container_foreach (container, (GFunc) gimp_container_remove_handler_foreach_func, handler); diff --git a/app/core/gimpimage-duplicate.c b/app/core/gimpimage-duplicate.c index f18c732ce7..e387131c6a 100644 --- a/app/core/gimpimage-duplicate.c +++ b/app/core/gimpimage-duplicate.c @@ -36,6 +36,7 @@ #include "gimpcontext.h" #include "gimpimage.h" #include "gimpimage-duplicate.h" +#include "gimpimage-guides.h" #include "gimpimage-new.h" #include "gimplayer.h" #include "gimplist.h" diff --git a/app/core/gimpimage-guides.c b/app/core/gimpimage-guides.c index cd786391e4..000ca86a86 100644 --- a/app/core/gimpimage-guides.c +++ b/app/core/gimpimage-guides.c @@ -18,1489 +18,21 @@ #include "config.h" -#include - #include -#include "libgimpcolor/gimpcolor.h" -#include "libgimpmath/gimpmath.h" -#include "libgimpbase/gimpbase.h" - #include "core-types.h" -#include "base/pixel-region.h" -#include "base/temp-buf.h" -#include "base/tile-manager.h" - -#include "paint-funcs/paint-funcs.h" - #include "gimp.h" -#include "gimpcontext.h" -#include "gimpcoreconfig.h" #include "gimpimage.h" -#include "gimpimage-colorhash.h" -#include "gimpimage-mask.h" -#include "gimpimage-projection.h" -#include "gimpimage-undo.h" -#include "gimplayer.h" -#include "gimplayermask.h" -#include "gimplist.h" -#include "gimpmarshal.h" -#include "gimpparasite.h" -#include "gimpparasitelist.h" -#include "gimpundostack.h" +#include "gimpimage-guides.h" -#include "floating_sel.h" -#include "path.h" #include "undo.h" -#include "libgimp/gimpintl.h" - - -#ifdef DEBUG -#define TRC(x) printf x -#else -#define TRC(x) -#endif #define GUIDE_EPSILON 5 -enum -{ - MODE_CHANGED, - ALPHA_CHANGED, - FLOATING_SELECTION_CHANGED, - ACTIVE_LAYER_CHANGED, - ACTIVE_CHANNEL_CHANGED, - COMPONENT_VISIBILITY_CHANGED, - COMPONENT_ACTIVE_CHANGED, - MASK_CHANGED, - RESOLUTION_CHANGED, - UNIT_CHANGED, - QMASK_CHANGED, - SELECTION_CONTROL, - - CLEAN, - DIRTY, - UPDATE, - UPDATE_GUIDE, - COLORMAP_CHANGED, - UNDO_EVENT, - LAST_SIGNAL -}; - - -/* local function prototypes */ - -static void gimp_image_class_init (GimpImageClass *klass); -static void gimp_image_init (GimpImage *gimage); - -static void gimp_image_dispose (GObject *object); -static void gimp_image_finalize (GObject *object); - -static void gimp_image_name_changed (GimpObject *object); -static void gimp_image_invalidate_preview (GimpViewable *viewable); -static void gimp_image_size_changed (GimpViewable *viewable); -static void gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol); -static TempBuf *gimp_image_get_preview (GimpViewable *gimage, - gint width, - gint height); -static TempBuf *gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height); -static void gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); - -/* - * Static variables - */ -static gint valid_combinations[][MAX_CHANNELS + 1] = -{ - /* RGB GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A }, - /* RGBA GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A }, - /* GRAY GIMAGE */ - { -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A, -1, -1 }, - /* GRAYA GIMAGE */ - { -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A, -1, -1 }, - /* INDEXED GIMAGE */ - { -1, COMBINE_INDEXED_INDEXED, COMBINE_INDEXED_INDEXED_A, -1, -1 }, - /* INDEXEDA GIMAGE */ - { -1, -1, COMBINE_INDEXED_A_INDEXED_A, -1, -1 }, -}; - -static guint gimp_image_signals[LAST_SIGNAL] = { 0 }; - -static GimpViewableClass *parent_class = NULL; - - -GType -gimp_image_get_type (void) -{ - static GType image_type = 0; - - if (! image_type) - { - static const GTypeInfo image_info = - { - sizeof (GimpImageClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gimp_image_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GimpImage), - 0, /* n_preallocs */ - (GInstanceInitFunc) gimp_image_init, - }; - - image_type = g_type_register_static (GIMP_TYPE_VIEWABLE, - "GimpImage", - &image_info, 0); - } - - return image_type; -} - -static void -gimp_image_class_init (GimpImageClass *klass) -{ - GObjectClass *object_class; - GimpObjectClass *gimp_object_class; - GimpViewableClass *viewable_class; - - object_class = G_OBJECT_CLASS (klass); - gimp_object_class = GIMP_OBJECT_CLASS (klass); - viewable_class = GIMP_VIEWABLE_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gimp_image_signals[MODE_CHANGED] = - g_signal_new ("mode_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mode_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ALPHA_CHANGED] = - g_signal_new ("alpha_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, alpha_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[FLOATING_SELECTION_CHANGED] = - g_signal_new ("floating_selection_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, floating_selection_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_LAYER_CHANGED] = - g_signal_new ("active_layer_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_layer_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_CHANNEL_CHANGED] = - g_signal_new ("active_channel_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_channel_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] = - g_signal_new ("component_visibility_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_visibility_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[COMPONENT_ACTIVE_CHANGED] = - g_signal_new ("component_active_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_active_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[MASK_CHANGED] = - g_signal_new ("mask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[RESOLUTION_CHANGED] = - g_signal_new ("resolution_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, resolution_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UNIT_CHANGED] = - g_signal_new ("unit_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, unit_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[QMASK_CHANGED] = - g_signal_new ("qmask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, qmask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[SELECTION_CONTROL] = - g_signal_new ("selection_control", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, selection_control), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[CLEAN] = - g_signal_new ("clean", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, clean), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[DIRTY] = - g_signal_new ("dirty", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, dirty), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UPDATE] = - g_signal_new ("update", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update), - NULL, NULL, - gimp_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT); - - gimp_image_signals[UPDATE_GUIDE] = - g_signal_new ("update_guide", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update_guide), - NULL, NULL, - gimp_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - gimp_image_signals[COLORMAP_CHANGED] = - g_signal_new ("colormap_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, colormap_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[UNDO_EVENT] = - g_signal_new ("undo_event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, undo_event), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - object_class->dispose = gimp_image_dispose; - object_class->finalize = gimp_image_finalize; - - gimp_object_class->name_changed = gimp_image_name_changed; - - viewable_class->invalidate_preview = gimp_image_invalidate_preview; - viewable_class->size_changed = gimp_image_size_changed; - viewable_class->get_preview = gimp_image_get_preview; - viewable_class->get_new_preview = gimp_image_get_new_preview; - - klass->mode_changed = NULL; - klass->alpha_changed = NULL; - klass->floating_selection_changed = NULL; - klass->active_layer_changed = NULL; - klass->active_channel_changed = NULL; - klass->component_visibility_changed = NULL; - klass->component_active_changed = NULL; - klass->mask_changed = NULL; - - klass->clean = NULL; - klass->dirty = NULL; - klass->update = NULL; - klass->update_guide = NULL; - klass->colormap_changed = gimp_image_real_colormap_changed; - klass->undo_event = NULL; - klass->undo = gimp_image_undo; - klass->redo = gimp_image_redo; - - gimp_image_color_hash_init (); -} - - -/* static functions */ - -static void -gimp_image_init (GimpImage *gimage) -{ - gimage->ID = 0; - - gimage->save_proc = NULL; - - gimage->width = 0; - gimage->height = 0; - gimage->xresolution = 1.0; - gimage->yresolution = 1.0; - gimage->unit = GIMP_UNIT_INCH; - gimage->base_type = RGB; - - gimage->cmap = NULL; - gimage->num_cols = 0; - - gimage->dirty = 1; - gimage->undo_on = TRUE; - - gimage->instance_count = 0; - gimage->disp_count = 0; - - gimage->tattoo_state = 0; - - gimage->shadow = NULL; - - gimage->construct_flag = FALSE; - gimage->proj_type = RGBA_GIMAGE; - gimage->projection = NULL; - - gimage->guides = NULL; - - gimage->layers = gimp_list_new (GIMP_TYPE_LAYER, - GIMP_CONTAINER_POLICY_STRONG); - gimage->channels = gimp_list_new (GIMP_TYPE_CHANNEL, - GIMP_CONTAINER_POLICY_STRONG); - gimage->layer_stack = NULL; - - gimage->active_layer = NULL; - gimage->active_channel = NULL; - gimage->floating_sel = NULL; - gimage->selection_mask = NULL; - - gimage->parasites = gimp_parasite_list_new (); - - gimage->paths = NULL; - - gimage->qmask_state = FALSE; - gimage->qmask_color.r = 1.0; - gimage->qmask_color.g = 0.0; - gimage->qmask_color.b = 0.0; - gimage->qmask_color.a = 0.5; - - gimage->undo_stack = NULL; - gimage->redo_stack = NULL; - gimage->undo_bytes = 0; - gimage->undo_levels = 0; - gimage->group_count = 0; - gimage->pushing_undo_group = UNDO_NULL; - - gimage->new_undo_stack = gimp_undo_stack_new (gimage); - gimage->new_redo_stack = gimp_undo_stack_new (gimage); - - gimage->comp_preview = NULL; - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_dispose (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - undo_free (gimage); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gimp_image_finalize (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - if (gimage->gimp && gimage->gimp->image_table) - { - g_hash_table_remove (gimage->gimp->image_table, - GINT_TO_POINTER (gimage->ID)); - gimage->gimp = NULL; - } - - if (gimage->projection) - gimp_image_projection_free (gimage); - - if (gimage->shadow) - gimp_image_free_shadow (gimage); - - if (gimage->cmap) - { - g_free (gimage->cmap); - gimage->cmap = NULL; - } - - if (gimage->layers) - { - g_object_unref (G_OBJECT (gimage->layers)); - gimage->layers = NULL; - } - if (gimage->channels) - { - g_object_unref (G_OBJECT (gimage->channels)); - gimage->channels = NULL; - } - if (gimage->layer_stack) - { - g_slist_free (gimage->layer_stack); - gimage->layer_stack = NULL; - } - - if (gimage->selection_mask) - { - g_object_unref (G_OBJECT (gimage->selection_mask)); - gimage->selection_mask = NULL; - } - - if (gimage->comp_preview) - { - temp_buf_free (gimage->comp_preview); - gimage->comp_preview = NULL; - } - - if (gimage->parasites) - { - g_object_unref (G_OBJECT (gimage->parasites)); - gimage->parasites = NULL; - } - - if (gimage->guides) - { - g_list_foreach (gimage->guides, (GFunc) g_free, NULL); - g_list_free (gimage->guides); - gimage->guides = NULL; - } - - if (gimage->new_undo_stack) - { - g_object_unref (G_OBJECT (gimage->new_undo_stack)); - gimage->new_undo_stack = NULL; - } - if (gimage->new_redo_stack) - { - g_object_unref (G_OBJECT (gimage->new_redo_stack)); - gimage->new_redo_stack = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gimp_image_name_changed (GimpObject *object) -{ - GimpImage *gimage; - const gchar *name; - - if (GIMP_OBJECT_CLASS (parent_class)->name_changed) - GIMP_OBJECT_CLASS (parent_class)->name_changed (object); - - gimage = GIMP_IMAGE (object); - name = gimp_object_get_name (object); - - if (! (name && strlen (name))) - { - g_free (object->name); - object->name = NULL; - } -} - -static void -gimp_image_invalidate_preview (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview) - GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_size_changed (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed) - GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimp_image_invalidate_layer_previews (gimage); - gimp_image_invalidate_channel_previews (gimage); -} - -static void -gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol) -{ - if (gimp_image_base_type (gimage) == INDEXED) - gimp_image_color_hash_invalidate (gimage, ncol); -} - -static void -gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - /* allocate the new projection */ - gimage->shadow = tile_manager_new (width, height, bpp); -} - - -/* function definitions */ - -GimpImage * -gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type) -{ - GimpImage *gimage; - gint i; - - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - gimage = GIMP_IMAGE (g_object_new (GIMP_TYPE_IMAGE, NULL)); - - gimage->gimp = gimp; - gimage->ID = gimp->next_image_ID++; - - g_hash_table_insert (gimp->image_table, - GINT_TO_POINTER (gimage->ID), - (gpointer) gimage); - - gimage->width = width; - gimage->height = height; - gimage->base_type = base_type; - - gimage->xresolution = gimp->config->default_xresolution; - gimage->yresolution = gimp->config->default_yresolution; - gimage->unit = gimp->config->default_units; - - switch (base_type) - { - case RGB: - case GRAY: - break; - case INDEXED: - /* always allocate 256 colors for the colormap */ - gimage->num_cols = 0; - gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE); - break; - default: - break; - } - - /* set all color channels visible and active */ - for (i = 0; i < MAX_CHANNELS; i++) - { - gimage->visible[i] = TRUE; - gimage->active[i] = TRUE; - } - - /* create the selection mask */ - gimage->selection_mask = gimp_channel_new_mask (gimage, - gimage->width, - gimage->height); - - - return gimage; -} - -gint -gimp_image_get_ID (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->ID; -} - -GimpImage * -gimp_image_get_by_ID (Gimp *gimp, - gint image_id) -{ - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - if (gimp->image_table == NULL) - return NULL; - - return (GimpImage *) g_hash_table_lookup (gimp->image_table, - GINT_TO_POINTER (image_id)); -} - -void -gimp_image_set_filename (GimpImage *gimage, - const gchar *filename) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_object_set_name (GIMP_OBJECT (gimage), filename); -} - -void -gimp_image_set_resolution (GimpImage *gimage, - gdouble xresolution, - gdouble yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* don't allow to set the resolution out of bounds */ - if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION || - yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION) - return; - - if ((ABS (gimage->xresolution - xresolution) >= 1e-5) || - (ABS (gimage->yresolution - yresolution) >= 1e-5)) - { - undo_push_resolution (gimage); - - gimage->xresolution = xresolution; - gimage->yresolution = yresolution; - - gimp_image_resolution_changed (gimage); - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - } -} - -void -gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (xresolution && yresolution); - - *xresolution = gimage->xresolution; - *yresolution = gimage->yresolution; -} - -void -gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->unit != unit) - { - undo_push_resolution (gimage); - - gimage->unit = unit; - - gimp_image_unit_changed (gimage); - } -} - -GimpUnit -gimp_image_get_unit (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_UNIT_INCH); - - return gimage->unit; -} - -void -gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (qmask_state != gimage->qmask_state) - { - gimage->qmask_state = qmask_state ? TRUE : FALSE; - - gimp_image_qmask_changed (gimage); - } -} - -gboolean -gimp_image_get_qmask_state (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->qmask_state; -} - -void -gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->save_proc = proc; -} - -PlugInProcDef * -gimp_image_get_save_proc (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->save_proc; -} - -gint -gimp_image_get_width (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->width; -} - -gint -gimp_image_get_height (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->height; -} - -void -gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GList *guide_list; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_RESIZE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - gimage->width = new_width; - gimage->height = new_height; - - /* Resize all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y); - } - - /* Reposition or remove any guides */ - guide_list = gimage->guides; - while (guide_list) - { - GimpGuide *guide; - - guide = (GimpGuide *) guide_list->data; - guide_list = g_list_next (guide_list); - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position += offset_y; - if (guide->position < 0 || guide->position > new_height) - gimp_image_delete_guide (gimage, guide); - break; - - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position += offset_x; - if (guide->position < 0 || guide->position > new_width) - gimp_image_delete_guide (gimage, guide); - break; - - default: - g_error ("Unknown guide orientation\n"); - } - } - - /* Don't forget the selection mask! */ - gimp_channel_resize (gimage->selection_mask, - new_width, new_height, offset_x, offset_y); - gimage_mask_invalidate (gimage); - - /* Reposition all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - gimp_layer_translate (layer, offset_x, offset_y); - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -void -gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GSList *remove = NULL; - GSList *slist; - GimpGuide *guide; - gint old_width; - gint old_height; - gdouble img_scale_w = 1.0; - gdouble img_scale_h = 1.0; - gint num_channels; - gint num_layers; - gint progress_current = 1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - num_channels = gimage->channels->num_children; - num_layers = gimage->layers->num_children; - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_SCALE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - - old_width = gimage->width; - old_height = gimage->height; - gimage->width = new_width; - gimage->height = new_height; - img_scale_w = (gdouble) new_width / (gdouble) old_width; - img_scale_h = (gdouble) new_height / (gdouble) old_height; - - /* Scale all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_scale (channel, new_width, new_height); - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* Don't forget the selection mask! */ - /* if (channel_is_empty(gimage->selection_mask)) - gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0) - else - */ - - gimp_channel_scale (gimage->selection_mask, new_width, new_height); - gimage_mask_invalidate (gimage); - - /* Scale all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h)) - { - /* Since 0 < img_scale_w, img_scale_h, failure due to one or more - * vanishing scaled layer dimensions. Implicit delete implemented - * here. Upstream warning implemented in resize_check_layer_scaling() - * [resize.c line 1295], which offers the user the chance to bail out. - */ - remove = g_slist_append (remove, layer); - } - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* We defer removing layers lost to scaling until now so as not to mix - * the operations of iterating over and removal from gimage->layers. - */ - for (slist = remove; slist; slist = g_slist_next (slist)) - { - layer = slist->data; - gimp_image_remove_layer (gimage, layer); - } - g_slist_free (remove); - - /* Scale any Guides */ - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_height) / old_height; - break; - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_width) / old_width; - break; - default: - g_error("Unknown guide orientation II.\n"); - } - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -/** - * gimp_image_check_scaling: - * @gimage: A #GimpImage. - * @new_width: The new width. - * @new_height: The new height. - * - * Inventory the layer list in gimage and return #TRUE if, after - * scaling, they all retain positive x and y pixel dimensions. - * - * Return value: #TRUE if scaling the image will shrink none of it's - * layers completely away. - **/ -gboolean -gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height) -{ - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpLayer *layer; - - layer = (GimpLayer *) list->data; - - if (! gimp_layer_check_scaling (layer, new_width, new_height)) - return FALSE; - } - - return TRUE; -} - -TileManager * -gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (gimage->shadow && - ((width != tile_manager_width (gimage->shadow)) || - (height != tile_manager_height (gimage->shadow)) || - (bpp != tile_manager_bpp (gimage->shadow)))) - gimp_image_free_shadow (gimage); - else if (gimage->shadow) - return gimage->shadow; - - gimp_image_allocate_shadow (gimage, width, height, bpp); - - return gimage->shadow; -} - -void -gimp_image_free_shadow (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->shadow) - { - tile_manager_destroy (gimage->shadow); - gimage->shadow = NULL; - } -} - -void -gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - /* alternative to using drawable tiles as src1: */ - TileManager *src1_tiles, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR, maskPR; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations[gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - if (src1_tiles) - pixel_region_init (&src1PR, src1_tiles, - x1, y1, (x2 - x1), (y2 - y1), FALSE); - else - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - gint mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL, - opacity, mode, active, operation); - } - else - { - combine_regions (&src1PR, src2PR, &destPR, NULL, NULL, - opacity, mode, active, operation); - } -} - -/* Similar to gimp_image_apply_image but works in "replace" mode (i.e. - transparent pixels in src2 make the result transparent rather - than opaque. - - Takes an additional mask pixel region as well. -*/ -void -gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR; - PixelRegion mask2PR, tempPR; - guchar *temp_data; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations [gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - gimp_drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - int mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&mask2PR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - - tempPR.bytes = 1; - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.rowstride = tempPR.w * tempPR.bytes; - temp_data = g_malloc (tempPR.h * tempPR.rowstride); - tempPR.data = temp_data; - - copy_region (&mask2PR, &tempPR); - - /* apparently, region operations can mutate some PR data. */ - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); - - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, - opacity, active, operation); - - g_free (temp_data); - } - else - { - combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL, - opacity, active, operation); - } -} - -/* Get rid of these! A "foreground" is an UI concept.. */ - -void -gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg) -{ - GimpRGB color; - guchar pfg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (fg != NULL); - - gimp_context_get_foreground (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]); - - gimp_image_transform_color (gimage, drawable, pfg, fg, RGB); -} - -void -gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg) -{ - GimpRGB color; - guchar pbg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (bg != NULL); - - gimp_context_get_background (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]); - - gimp_image_transform_color (gimage, drawable, pbg, bg, RGB); -} - -void -gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - map_to_color (0, NULL, src, rgb); - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - map_to_color (1, NULL, src, rgb); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - map_to_color (2, gimage->cmap, src, rgb); - break; - } -} - -void -gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type) -{ - GimpImageType d_type; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - d_type = (drawable != NULL) ? gimp_drawable_type (drawable) : - gimp_image_base_type_with_alpha (gimage); - - switch (type) - { - case RGB: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Straight copy */ - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* NTSC conversion */ - *dest = INTENSITY (src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - } - break; - case GRAY: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Gray to RG&B */ - *dest++ = *src; - *dest++ = *src; - *dest++ = *src; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* Straight copy */ - *dest = *src; - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[GRAY_PIX], - src[GRAY_PIX], - src[GRAY_PIX]); - break; - } - break; - default: - break; - } -} +/* public functions */ GimpGuide * gimp_image_add_hguide (GimpImage *gimage) @@ -1575,8 +107,8 @@ gimp_image_delete_guide (GimpImage *gimage, GimpGuide * gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y) + gdouble x, + gdouble y) { GList *list; GimpGuide *guide; @@ -1618,8 +150,8 @@ gimp_image_find_guide (GimpImage *gimage, gboolean gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, + gdouble x, + gdouble y, gint *tx, gint *ty) { @@ -1683,10 +215,10 @@ gimp_image_snap_point (GimpImage *gimage, gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, gint *tx1, gint *ty1) { @@ -1719,2149 +251,3 @@ gimp_image_snap_rectangle (GimpImage *gimage, return snap1 || snap2; } - -GimpParasite * -gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimp_parasite_list_find (gimage->parasites, name); -} - -static void -list_func (gchar *key, - GimpParasite *p, - gchar ***cur) -{ - *(*cur)++ = (gchar *) g_strdup (key); -} - -gchar ** -gimp_image_parasite_list (const GimpImage *gimage, - gint *count) -{ - gchar **list; - gchar **cur; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - *count = gimp_parasite_list_length (gimage->parasites); - cur = list = g_new (gchar*, *count); - - gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur); - - return list; -} - -void -gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL); - - /* only set the dirty bit manually if we can be saved and the new - parasite differs from the current one and we aren't undoable */ - if (gimp_parasite_is_undoable (parasite)) - undo_push_image_parasite (gimage, parasite); - - /* We used to push an cantundo on te stack here. This made the undo stack - unusable (NULL on the stack) and prevented people from undoing after a - save (since most save plug-ins attach an undoable comment parasite). - Now we simply attach the parasite without pushing an undo. That way it's - undoable but does not block the undo system. --Sven - */ - - gimp_parasite_list_add (gimage->parasites, parasite); - - if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT)) - { - gimp_parasite_shift_parent (parasite); - gimp_parasite_attach (gimage->gimp, parasite); - } -} - -void -gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite) -{ - GimpParasite *p; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (parasite != NULL); - - if (!(p = gimp_parasite_list_find (gimage->parasites, parasite))) - return; - - if (gimp_parasite_is_undoable (p)) - undo_push_image_parasite_remove (gimage, gimp_parasite_name (p)); - - gimp_parasite_list_remove (gimage->parasites, parasite); -} - -GimpTattoo -gimp_image_get_new_tattoo (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - gimage->tattoo_state++; - - if (gimage->tattoo_state <= 0) - g_warning ("%s: Tattoo state corrupted " - "(integer overflow).", G_GNUC_PRETTY_FUNCTION); - - return gimage->tattoo_state; -} - -GimpTattoo -gimp_image_get_tattoo_state (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->tattoo_state; -} - -gboolean -gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val) -{ - GList *list; - gboolean retval = TRUE; - GimpChannel *channel; - GimpTattoo maxval = 0; - Path *pptr = NULL; - PathList *plist; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ltattoo; - - ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data)); - if (ltattoo > maxval) - maxval = ltattoo; - if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in channel */ - } - - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Now check that the paths channel tattoos don't overlap */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ctattoo; - - channel = (GimpChannel *) list->data; - - ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)); - if (ctattoo > maxval) - maxval = ctattoo; - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ctattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Find the max tatto value in the paths */ - plist = gimage->paths; - - if (plist && plist->bz_paths) - { - GimpTattoo ptattoo; - GSList *pl; - - for (pl = plist->bz_paths; pl; pl = g_slist_next (pl)) - { - pptr = pl->data; - - ptattoo = path_get_tattoo (pptr); - - if (ptattoo > maxval) - maxval = ptattoo; - } - } - - if (val < maxval) - retval = FALSE; - /* Must check the state is valid */ - if (retval == TRUE) - gimage->tattoo_state = val; - - return retval; -} - -void -gimp_image_set_paths (GimpImage *gimage, - PathList *paths) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->paths = paths; -} - -PathList * -gimp_image_get_paths (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->paths; -} - -void -gimp_image_colormap_changed (GimpImage *gimage, - gint col) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (col < gimage->num_cols); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[COLORMAP_CHANGED], 0, - col); -} - -void -gimp_image_mode_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MODE_CHANGED], 0); -} - -void -gimp_image_mask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MASK_CHANGED], 0); -} - -void -gimp_image_resolution_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[RESOLUTION_CHANGED], 0); -} - -void -gimp_image_unit_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNIT_CHANGED], 0); -} - -void -gimp_image_qmask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[QMASK_CHANGED], 0); -} - -void -gimp_image_alpha_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED], 0); -} - -void -gimp_image_floating_selection_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[FLOATING_SELECTION_CHANGED], 0); -} - -void -gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE], 0, - x, y, width, height); -} - -void -gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (guide != NULL); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE_GUIDE], 0, - guide); -} - -void -gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[SELECTION_CONTROL], 0, - control); -} - -void -gimp_image_invalidate_layer_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->layers, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -void -gimp_image_invalidate_channel_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->channels, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -GimpContainer * -gimp_image_get_layers (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->layers; -} - -GimpContainer * -gimp_image_get_channels (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->channels; -} - -gint -gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_LAYER (layer), -1); - - return gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); -} - -gint -gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1); - - return gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); -} - -GimpLayer * -gimp_image_get_active_layer (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_layer; -} - -GimpChannel * -gimp_image_get_active_channel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_channel; -} - -GimpLayer * -gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo) - return layer; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name)) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_mask (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->selection_mask; -} - -void -gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && active != gimage->active[pixel]) - { - gimage->active[pixel] = active ? TRUE : FALSE; - - /* If there is an active channel and we mess with the components, - * the active channel gets unset... - */ - gimp_image_unset_active_channel (gimage); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, - type); - } -} - -gboolean -gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->active[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->active[ALPHA_PIX]; break; - case GRAY: return gimage->active[ALPHA_G_PIX]; break; - case INDEXED: return gimage->active[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -void -gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active) -{ - GimpLayer *layer; - gint i; - - /* first, blindly copy the gimage active channels */ - for (i = 0; i < MAX_CHANNELS; i++) - active[i] = gimage->active[i]; - - /* If the drawable is a channel (a saved selection, etc.) - * make sure that the alpha channel is not valid - */ - if (GIMP_IS_CHANNEL (drawable)) - { - active[ALPHA_G_PIX] = 0; /* no alpha values in channels */ - } - else - { - /* otherwise, check whether preserve transparency is - * enabled in the layer and if the layer has alpha - */ - if (GIMP_IS_LAYER (drawable)) - { - layer = GIMP_LAYER (drawable); - if (gimp_layer_has_alpha (layer) && layer->preserve_trans) - active[gimp_drawable_bytes (drawable) - 1] = 0; - } - } -} - -void -gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && visible != gimage->visible[pixel]) - { - gimage->visible[pixel] = visible ? TRUE : FALSE; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED], 0, - type); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - } -} - -gboolean -gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->visible[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->visible[ALPHA_PIX]; break; - case GRAY: return gimage->visible[ALPHA_G_PIX]; break; - case INDEXED: return gimage->visible[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -gboolean -gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs) -{ - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (segs != NULL, FALSE); - g_return_val_if_fail (n_segs != NULL, FALSE); - - /* The second boundary corresponds to the active layer's - * perimeter... - */ - layer = gimp_image_get_active_layer (gimage); - - if (layer) - { - *segs = gimp_layer_boundary (layer, n_segs); - return TRUE; - } - else - { - *segs = NULL; - *n_segs = 0; - return FALSE; - } -} - -GimpLayer * -gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); - - /* First, find the layer in the gimage - * If it isn't valid, find the first layer that is - */ - if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0); - - if (layer) - { - /* Configure the layer stack to reflect this change */ - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer); - - /* invalidate the selection boundary because of a layer modification */ - gimp_layer_invalidate_boundary (layer); - } - - if (layer != gimage->active_layer) - { - gimage->active_layer = layer; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - - if (gimage->active_channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - } - } - - /* return the layer */ - return layer; -} - -GimpChannel * -gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* Not if there is a floating selection */ - if (gimp_image_floating_sel (gimage)) - return NULL; - - /* First, find the channel - * If it doesn't exist, find the first channel that does - */ - if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0); - - if (channel != gimage->active_channel) - { - gimage->active_channel = channel; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->active_layer) - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* return the channel */ - return channel; -} - -GimpChannel * -gimp_image_unset_active_channel (GimpImage *gimage) -{ - GimpChannel *channel; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - channel = gimp_image_get_active_channel (gimage); - - if (channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->layer_stack) - { - GimpLayer *layer; - - layer = (GimpLayer *) gimage->layer_stack->data; - - gimp_image_set_active_layer (gimage, layer); - } - } - - return channel; -} - -GimpLayer * -gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_layer_pick_correlate (layer, x, y)) - return layer; - } - - return NULL; -} - -gboolean -gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the top layer already? */ - if (curpos == 0) - { - g_message (_("Layer cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE); -} - -gboolean -gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the bottom layer already? */ - length = gimp_container_num_children (gimage->layers); - if (curpos >= length - 1) - { - g_message (_("Layer cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE); -} - -gboolean -gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - if (curpos == 0) - { - g_message (_("Layer is already on top.")); - return FALSE; - } - - if (! gimp_layer_has_alpha (layer)) - { - g_message (_("Cannot raise a layer without alpha.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, 0, TRUE); -} - -gboolean -gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - length = gimp_container_num_children (gimage->layers); - - if (curpos >= length - 1) - { - g_message (_("Layer is already on the bottom.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, length - 1, TRUE); -} - -gboolean -gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo) -{ - gint off_x, off_y; - gint index; - gint num_layers; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - index = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - if (index < 0) - return FALSE; - - num_layers = gimp_container_num_children (gimage->layers); - - if (new_index < 0) - new_index = 0; - - if (new_index >= num_layers) - new_index = num_layers - 1; - - if (new_index == index) - return TRUE; - - /* check if we want to move it below a bottom layer without alpha */ - if (new_index == num_layers - 1) - { - GimpLayer *tmp; - - tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, - num_layers - 1); - - if (new_index == num_layers - 1 && - ! gimp_layer_has_alpha (tmp)) - { - g_message (_("Layer \"%s\" has no alpha.\nLayer was placed above it."), - GIMP_OBJECT (tmp)->name); - new_index--; - } - } - - if (push_undo) - undo_push_layer_reposition (gimage, layer); - - gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - gimp_image_update (gimage, - off_x, off_y, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); - - return TRUE; -} - -GimpLayer * -gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type) -{ - GList *list; - GSList *merge_list = NULL; - gboolean had_floating_sel = FALSE; - GimpLayer *layer = NULL; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - { - floating_sel_anchor (gimage->floating_sel); - had_floating_sel = TRUE; - } - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - if (merge_list && merge_list->next) - { - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_slist_free (merge_list); - - /* If there was a floating selection, we have done something. - No need to warn the user. Return the active layer instead */ - if (had_floating_sel) - return layer; - else - g_message (_("Not enough visible layers for a merge.\n" - "There must be at least two.")); - - return NULL; - } -} - -GimpLayer * -gimp_image_flatten (GimpImage *gimage) -{ - GList *list; - GSList *merge_list = NULL; - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - gimp_set_busy (gimage->gimp); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - floating_sel_anchor (gimage->floating_sel); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - layer = gimp_image_merge_layers (gimage, merge_list, FLATTEN_IMAGE); - g_slist_free (merge_list); - - gimp_image_alpha_changed (gimage); - - gimp_unset_busy (gimage->gimp); - - return layer; -} - -GimpLayer * -gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type) -{ - GimpLayer *layer; - GList *list; - GList *layer_list; - GSList *merge_list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list, layer_list = NULL; - list && !layer_list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (layer == current_layer) - break; - } - - for (layer_list = g_list_next (list), merge_list = NULL; - layer_list && !merge_list; - layer_list = g_list_next (layer_list)) - { - layer = (GimpLayer *) layer_list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (NULL, layer); - } - - if (merge_list) - { - merge_list = g_slist_prepend (merge_list, current_layer); - - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_message (_("There are not enough visible layers for a merge down.")); - return NULL; - } -} - -GimpLayer * -gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type) -{ - GList *list; - GSList *reverse_list = NULL; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - GimpLayer *merge_layer; - GimpLayer *layer; - GimpLayer *bottom_layer; - LayerModeEffects bottom_mode; - guchar bg[4] = {0, 0, 0, 0}; - GimpImageType type; - gint count; - gint x1, y1, x2, y2; - gint x3, y3, x4, y4; - gint operation; - gint position; - gint active[MAX_CHANNELS] = {1, 1, 1, 1}; - gint off_x, off_y; - gchar *name; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - layer = NULL; - type = RGBA_GIMAGE; - x1 = y1 = 0; - x2 = y2 = 0; - bottom_layer = NULL; - bottom_mode = NORMAL_MODE; - - /* Get the layer extents */ - count = 0; - while (merge_list) - { - layer = (GimpLayer *) merge_list->data; - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - switch (merge_type) - { - case EXPAND_AS_NECESSARY: - case CLIP_TO_IMAGE: - if (!count) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - else - { - if (off_x < x1) - x1 = off_x; - if (off_y < y1) - y1 = off_y; - if ((off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) > x2) - x2 = (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))); - if ((off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))) > y2) - y2 = (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))); - } - if (merge_type == CLIP_TO_IMAGE) - { - x1 = CLAMP (x1, 0, gimage->width); - y1 = CLAMP (y1, 0, gimage->height); - x2 = CLAMP (x2, 0, gimage->width); - y2 = CLAMP (y2, 0, gimage->height); - } - break; - - case CLIP_TO_BOTTOM_LAYER: - if (merge_list->next == NULL) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - break; - - case FLATTEN_IMAGE: - if (merge_list->next == NULL) - { - x1 = 0; - y1 = 0; - x2 = gimage->width; - y2 = gimage->height; - } - 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 */ - undo_push_group_start (gimage, LAYER_MERGE_UNDO); - - name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); - - if (merge_type == FLATTEN_IMAGE || - gimp_drawable_type (GIMP_DRAWABLE (layer)) == INDEXED_GIMAGE) - { - switch (gimp_image_base_type (gimage)) - { - case RGB: type = RGB_GIMAGE; break; - case GRAY: type = GRAY_GIMAGE; break; - case INDEXED: type = INDEXED_GIMAGE; break; - } - - merge_layer = gimp_layer_new (gimage, (x2 - x1), (y2 - y1), - type, - gimp_object_get_name (GIMP_OBJECT (layer)), - OPAQUE_OPACITY, NORMAL_MODE); - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* get the background for compositing */ - gimp_image_get_background (gimage, GIMP_DRAWABLE (merge_layer), bg); - - /* init the pixel region */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - gimage->width, gimage->height, - 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 (gimage, (x2 - x1), (y2 - y1), - gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), - "merged layer", - OPAQUE_OPACITY, NORMAL_MODE); - - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* Set the layer to transparent */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - (x2 - x1), (y2 - y1), - TRUE); - - /* set the region to 0's */ - color_region (&src1PR, bg); - - /* 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 = (GimpLayer *) reverse_list->data; - position = - gimp_container_num_children (gimage->layers) - - gimp_container_get_child_index (gimage->layers, GIMP_OBJECT (layer)); - - /* set the mode of the bottom layer to normal so that the contents - * aren't lost when merging with the all-alpha merge_layer - * Keep a pointer to it so that we can set the mode right after it's - * been merged so that undo works correctly. - */ - bottom_layer = layer; - bottom_mode = bottom_layer->mode; - - /* 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. - */ - if (bottom_layer->mode != DISSOLVE_MODE) - gimp_layer_set_mode (bottom_layer, NORMAL_MODE); - } - - /* Copy the tattoo and parasites of the bottom layer to the new layer */ - gimp_drawable_set_tattoo (GIMP_DRAWABLE (merge_layer), - gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer))); - GIMP_DRAWABLE (merge_layer)->parasites = - gimp_parasite_list_copy (GIMP_DRAWABLE (layer)->parasites); - - while (reverse_list) - { - layer = (GimpLayer *) reverse_list->data; - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = - valid_combinations[gimp_drawable_type (GIMP_DRAWABLE (merge_layer))][gimp_drawable_bytes (GIMP_DRAWABLE (layer))]; - - if (operation == -1) - { - g_warning ("%s: attempting to merge incompatible layers.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - x3 = CLAMP (off_x, x1, x2); - y3 = CLAMP (off_y, y1, y2); - x4 = CLAMP (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)), x1, x2); - y4 = CLAMP (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)), y1, y2); - - /* configure the pixel regions */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), - TRUE); - pixel_region_init (&src2PR, - gimp_drawable_data (GIMP_DRAWABLE (layer)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - - if (layer->mask && layer->mask->apply_mask) - { - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (layer->mask)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - mask = &maskPR; - } - else - { - mask = NULL; - } - - combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, - layer->opacity, layer->mode, active, operation); - - gimp_image_remove_layer (gimage, layer); - reverse_list = g_slist_next (reverse_list); - } - - /* Save old mode in undo */ - if (bottom_layer) - gimp_layer_set_mode (bottom_layer, bottom_mode); - - g_slist_free (reverse_list); - - /* if the type is flatten, remove all the remaining layers */ - if (merge_type == FLATTEN_IMAGE) - { - list = GIMP_LIST (gimage->layers)->list; - while (list) - { - layer = (GimpLayer *) list->data; - - list = g_list_next (list); - gimp_image_remove_layer (gimage, layer); - } - - gimp_image_add_layer (gimage, merge_layer, position); - } - else - { - /* Add the layer to the gimage */ - gimp_image_add_layer (gimage, merge_layer, - gimp_container_num_children (gimage->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_set_name (GIMP_OBJECT (merge_layer), name); - g_free (name); - - /* End the merge undo group */ - undo_push_group_end (gimage); - - gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE); - - gimp_drawable_update (GIMP_DRAWABLE (merge_layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (merge_layer)), - gimp_drawable_height (GIMP_DRAWABLE (merge_layer))); - - return merge_layer; -} - -gboolean -gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position) -{ - LayerUndo *lu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - if (GIMP_DRAWABLE (layer)->gimage != NULL && - GIMP_DRAWABLE (layer)->gimage != gimage) - { - g_warning ("%s: attempting to add layer to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - { - g_warning ("%s: trying to add layer to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Prepare a layer undo and push it */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = 0; - lu->prev_layer = gimp_image_get_active_layer (gimage); - undo_push_layer (gimage, LAYER_ADD_UNDO, lu); - - /* If the layer is a floating selection, set the ID */ - if (gimp_layer_is_floating_sel (layer)) - gimage->floating_sel = layer; - - /* let the layer know about the gimage */ - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage); - - /* If the layer has a mask, set the mask's gimage */ - if (layer->mask) - { - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage); - } - - /* add the layer to the list at the specified position */ - if (position == -1) - { - GimpLayer *active_layer; - - active_layer = gimp_image_get_active_layer (gimage); - - if (active_layer) - { - position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (active_layer)); - } - else - { - position = 0; - } - } - - /* If there is a floating selection (and this isn't it!), - * make sure the insert position is greater than 0 - */ - if (position == 0 && - gimp_image_floating_sel (gimage) && - (gimage->floating_sel != layer)) - { - position = 1; - } - - gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position); - g_object_unref (G_OBJECT (layer)); - - /* notify the layers dialog of the currently active layer */ - gimp_image_set_active_layer (gimage, layer); - - /* update the new layer's area */ - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - return TRUE; -} - -void -gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer) -{ - LayerUndo *lu; - gint x, y, w, h; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_LAYER (layer)); - - g_return_if_fail (gimp_container_have (gimage->layers, - GIMP_OBJECT (layer))); - - /* Push a layer undo */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - lu->prev_layer = layer; - - undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu); - - g_object_ref (G_OBJECT (layer)); - - gimp_container_remove (gimage->layers, GIMP_OBJECT (layer)); - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - - /* If this was the floating selection, reset the fs pointer */ - if (gimage->floating_sel == layer) - { - gimage->floating_sel = NULL; - - floating_sel_reset (layer); - } - - if (layer == gimp_image_get_active_layer (gimage)) - { - if (gimage->layer_stack) - { - gimp_image_set_active_layer (gimage, gimage->layer_stack->data); - } - else - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* Send out REMOVED signal from layer */ - gimp_drawable_removed (GIMP_DRAWABLE (layer)); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &x, &y); - w = gimp_drawable_width (GIMP_DRAWABLE (layer)); - h = gimp_drawable_height (GIMP_DRAWABLE (layer)); - - g_object_unref (G_OBJECT (layer)); - - gimp_image_update (gimage, x, y, w, h); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -gboolean -gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == 0) - { - g_message (_("Channel cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index - 1, TRUE); -} - -gboolean -gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == gimp_container_num_children (gimage->channels) - 1) - { - g_message (_("Channel cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index + 1, TRUE); -} - -gboolean -gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo /* FIXME unused */) -{ - gint index; - gint num_channels; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index < 0) - return FALSE; - - num_channels = gimp_container_num_children (gimage->channels); - - new_index = CLAMP (new_index, 0, num_channels - 1); - - if (new_index == index) - return TRUE; - - gimp_container_reorder (gimage->channels, - GIMP_OBJECT (channel), new_index); - - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -gboolean -gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position) -{ - ChannelUndo *cu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - if (GIMP_DRAWABLE (channel)->gimage != NULL && - GIMP_DRAWABLE (channel)->gimage != gimage) - { - g_warning ("%s: attempting to add channel to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - { - g_warning ("%s: trying to add channel to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Push a channel undo */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = 0; - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu); - - /* add the channel to the list */ - gimp_container_add (gimage->channels, GIMP_OBJECT (channel)); - g_object_unref (G_OBJECT (channel)); - - /* notify this gimage of the currently active channel */ - gimp_image_set_active_channel (gimage, channel); - - /* if channel is visible, update the image */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -void -gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel) -{ - ChannelUndo *cu; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_CHANNEL (channel)); - - g_return_if_fail (gimp_container_have (gimage->channels, - GIMP_OBJECT (channel))); - - /* Prepare a channel undo--push it below */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu); - - g_object_ref (G_OBJECT (channel)); - - gimp_container_remove (gimage->channels, GIMP_OBJECT (channel)); - - /* Send out REMOVED signal from channel */ - gimp_drawable_removed (GIMP_DRAWABLE (channel)); - - if (channel == gimp_image_get_active_channel (gimage)) - { - if (gimp_container_num_children (gimage->channels) > 0) - { - gimp_image_set_active_channel - (gimage, - GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels, - 0))); - } - else - { - gimp_image_unset_active_channel (gimage); - } - } - - g_object_unref (G_OBJECT (channel)); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -/************************************************************/ -/* Access functions */ -/************************************************************/ - -gboolean -gimp_image_is_empty (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE); - - return (gimp_container_num_children (gimage->layers) == 0); -} - -GimpDrawable * -gimp_image_active_drawable (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* If there is an active channel (a saved selection, etc.), - * we ignore the active layer - */ - if (gimage->active_channel) - { - return GIMP_DRAWABLE (gimage->active_channel); - } - else if (gimage->active_layer) - { - GimpLayer *layer; - - layer = gimage->active_layer; - - if (layer->mask && layer->mask->edit_mask) - return GIMP_DRAWABLE (layer->mask); - else - return GIMP_DRAWABLE (layer); - } - - return NULL; -} - -GimpImageBaseType -gimp_image_base_type (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->base_type; -} - -GimpImageType -gimp_image_base_type_with_alpha (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - switch (gimage->base_type) - { - case RGB: - return RGBA_GIMAGE; - case GRAY: - return GRAYA_GIMAGE; - case INDEXED: - return INDEXEDA_GIMAGE; - } - return RGB_GIMAGE; -} - -const gchar * -gimp_image_filename (const GimpImage *gimage) -{ - const gchar *filename; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - filename = gimp_object_get_name (GIMP_OBJECT (gimage)); - - return filename ? filename : _("Untitled"); -} - -gboolean -gimp_image_undo_is_enabled (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->undo_on; -} - -gboolean -gimp_image_undo_freeze (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = FALSE; - - return TRUE; -} - -gboolean -gimp_image_undo_thaw (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = TRUE; - - return TRUE; -} - -gboolean -gimp_image_undo_disable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimp_image_undo_freeze (gimage); -} - -gboolean -gimp_image_undo_enable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - /* Free all undo steps as they are now invalidated */ - undo_free (gimage); - - return gimp_image_undo_thaw (gimage); -} - -void -gimp_image_undo_event (GimpImage *gimage, - gint event) -{ - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], 0, - event); -} - - -/* NOTE about the gimage->dirty counter: - * If 0, then the image is clean (ie, copy on disk is the same as the one - * in memory). - * If positive, then that's the number of dirtying operations done - * on the image since the last save. - * If negative, then user has hit undo and gone back in time prior - * to the saved copy. Hitting redo will eventually come back to - * the saved copy. - * - * The image is dirty (ie, needs saving) if counter is non-zero. - * - * If the counter is around 10000, this is due to undo-ing back - * before a saved version, then mutating the image (thus destroying - * the redo stack). Once this has happened, it's impossible to get - * the image back to the state on disk, since the redo info has been - * freed. See undo.c for the gorey details. - */ - - -/* - * NEVER CALL gimp_image_dirty() directly! - * - * If your code has just dirtied the image, push an undo instead. - * Failing that, push the trivial undo which tells the user the - * command is not undoable: undo_push_cantundo() (But really, it would - * be best to push a proper undo). If you just dirty the image - * without pushing an undo then the dirty count is increased, but - * popping that many undo actions won't lead to a clean image. - */ - -gint -gimp_image_dirty (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty++; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[DIRTY], 0); - - TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty)); - - return gimage->dirty; -} - -gint -gimp_image_clean (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty--; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); - - TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty)); - - return gimage->dirty; -} - -void -gimp_image_clean_all (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->dirty = 0; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); -} - -GimpLayer * -gimp_image_floating_sel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - if (gimage->floating_sel == NULL) - return NULL; - else - return gimage->floating_sel; -} - -guchar * -gimp_image_cmap (const GimpImage *gimage) -{ - return gimp_drawable_cmap (gimp_image_active_drawable (gimage)); -} - -static TempBuf * -gimp_image_get_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (viewable); - - if (gimage->comp_preview_valid && - gimage->comp_preview->width == width && - gimage->comp_preview->height == height) - { - /* The easy way */ - return gimage->comp_preview; - } - else - { - /* The hard way */ - if (gimage->comp_preview) - temp_buf_free (gimage->comp_preview); - - /* Actually construct the composite preview from the layer previews! - * This might seem ridiculous, but it's actually the best way, given - * a number of unsavory alternatives. - */ - gimage->comp_preview = gimp_image_get_new_preview (viewable, - width, height); - - gimage->comp_preview_valid = TRUE; - - return gimage->comp_preview; - } -} - -static TempBuf * -gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - GimpLayer *layer; - GimpLayer *floating_sel; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - TempBuf *comp; - TempBuf *layer_buf; - TempBuf *mask_buf; - GList *list; - GSList *reverse_list = NULL; - gdouble ratio; - gint x, y, w, h; - gint x1, y1, x2, y2; - gint bytes; - gboolean construct_flag; - gint visible[MAX_CHANNELS] = { 1, 1, 1, 1 }; - gint off_x, off_y; - - gimage = GIMP_IMAGE (viewable); - - ratio = (gdouble) width / (gdouble) gimage->width; - - switch (gimp_image_base_type (gimage)) - { - case RGB: - case INDEXED: - bytes = 4; - break; - case GRAY: - bytes = 2; - break; - default: - bytes = 0; - break; - } - - /* The construction buffer */ - comp = temp_buf_new (width, height, bytes, 0, 0, NULL); - temp_buf_data_clear (comp); - - floating_sel = NULL; - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - /* only add layers that are visible to the list */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - { - /* floating selections are added right above the layer - * they are attached to - */ - if (gimp_layer_is_floating_sel (layer)) - { - floating_sel = layer; - } - else - { - if (floating_sel && - floating_sel->fs.drawable == GIMP_DRAWABLE (layer)) - { - reverse_list = g_slist_prepend (reverse_list, floating_sel); - } - - reverse_list = g_slist_prepend (reverse_list, layer); - } - } - } - - construct_flag = FALSE; - - for (; reverse_list; reverse_list = g_slist_next (reverse_list)) - { - layer = (GimpLayer *) reverse_list->data; - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - x = (gint) RINT (ratio * off_x); - y = (gint) RINT (ratio * off_y); - w = (gint) RINT (ratio * gimp_drawable_width (GIMP_DRAWABLE (layer))); - h = (gint) RINT (ratio * gimp_drawable_height (GIMP_DRAWABLE (layer))); - - if (w < 1 || h < 1) - continue; - - x1 = CLAMP (x, 0, width); - y1 = CLAMP (y, 0, height); - x2 = CLAMP (x + w, 0, width); - y2 = CLAMP (y + h, 0, height); - - src1PR.bytes = comp->bytes; - src1PR.x = x1; - src1PR.y = y1; - src1PR.w = (x2 - x1); - src1PR.h = (y2 - y1); - src1PR.rowstride = comp->width * src1PR.bytes; - src1PR.data = (temp_buf_data (comp) + - y1 * src1PR.rowstride + x1 * src1PR.bytes); - - layer_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h); - src2PR.bytes = layer_buf->bytes; - src2PR.w = src1PR.w; - src2PR.h = src1PR.h; - src2PR.x = src1PR.x; - src2PR.y = src1PR.y; - src2PR.rowstride = layer_buf->width * src2PR.bytes; - src2PR.data = (temp_buf_data (layer_buf) + - (y1 - y) * src2PR.rowstride + - (x1 - x) * src2PR.bytes); - - if (layer->mask && layer->mask->apply_mask) - { - mask_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer->mask), - w, h); - maskPR.bytes = mask_buf->bytes; - maskPR.rowstride = mask_buf->width; - maskPR.data = (mask_buf_data (mask_buf) + - (y1 - y) * maskPR.rowstride + - (x1 - x) * maskPR.bytes); - mask = &maskPR; - } - else - { - mask = NULL; - } - - /* Based on the type of the layer, project the layer onto the - * composite preview... - * Indexed images are actually already converted to RGB and RGBA, - * so just project them as if they were type "intensity" - * Send in all TRUE for visible since that info doesn't matter - * for previews - */ - switch (gimp_drawable_type (GIMP_DRAWABLE (layer))) - { - case RGB_GIMAGE: case GRAY_GIMAGE: case INDEXED_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN); - break; - - case RGBA_GIMAGE: case GRAYA_GIMAGE: case INDEXEDA_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY_ALPHA); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN_A); - break; - - default: - break; - } - - construct_flag = TRUE; - } - - g_slist_free (reverse_list); - - return comp; -} diff --git a/app/core/gimpimage-guides.h b/app/core/gimpimage-guides.h index be0b5eea83..5ece2438bd 100644 --- a/app/core/gimpimage-guides.h +++ b/app/core/gimpimage-guides.h @@ -16,425 +16,37 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __GIMP_IMAGE_H__ -#define __GIMP_IMAGE_H__ +#ifndef __GIMP_IMAGE_GUIDES_H__ +#define __GIMP_IMAGE_GUIDES_H__ -#include "gimpviewable.h" +GimpGuide * gimp_image_add_hguide (GimpImage *gimage); +GimpGuide * gimp_image_add_vguide (GimpImage *gimage); +void gimp_image_add_guide (GimpImage *gimage, + GimpGuide *guide); +void gimp_image_remove_guide (GimpImage *gimage, + GimpGuide *guide); -#define COLORMAP_SIZE 768 +void gimp_image_delete_guide (GimpImage *gimage, + GimpGuide *guide); -#define GIMP_IMAGE_TYPE_HAS_ALPHA(t) ((t) == RGBA_GIMAGE || \ - (t) == GRAYA_GIMAGE || \ - (t) == INDEXEDA_GIMAGE) +GimpGuide * gimp_image_find_guide (GimpImage *gimage, + gdouble x, + gdouble y); +gboolean gimp_image_snap_point (GimpImage *gimage, + gdouble x, + gdouble y, + gint *tx, + gint *ty); +gboolean gimp_image_snap_rectangle (GimpImage *gimage, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gint *tx1, + gint *ty1); -struct _GimpGuide -{ - gint ref_count; - gint position; - InternalOrientationType orientation; - guint32 guide_ID; -}; - -#define GIMP_TYPE_IMAGE (gimp_image_get_type ()) -#define GIMP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_IMAGE, GimpImage)) -#define GIMP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_IMAGE, GimpImageClass)) -#define GIMP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_IMAGE)) -#define GIMP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_IMAGE)) -#define GIMP_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_IMAGE, GimpImageClass)) - - -typedef struct _GimpImageClass GimpImageClass; - -struct _GimpImage -{ - GimpViewable parent_instance; - - Gimp *gimp; /* the GIMP the image belongs to*/ - - gint ID; /* provides a unique ID */ - - PlugInProcDef *save_proc; /* last PDB save proc used */ - - gint width, height; /* width and height attributes */ - gdouble xresolution; /* image x-res, in dpi */ - gdouble yresolution; /* image y-res, in dpi */ - GimpUnit unit; /* image unit */ - GimpImageBaseType base_type; /* base gimp_image type */ - - guchar *cmap; /* colormap--for indexed */ - gint num_cols; /* number of cols--for indexed */ - - gint dirty; /* dirty flag -- # of ops */ - gboolean undo_on; /* Is undo enabled? */ - - gint instance_count; /* number of instances */ - gint disp_count; /* number of displays */ - - GimpTattoo tattoo_state; /* the next unique tattoo to use*/ - - TileManager *shadow; /* shadow buffer tiles */ - - /* Projection attributes */ - gboolean construct_flag; /* flag for construction */ - GimpImageType proj_type; /* type of the projection image */ - gint proj_bytes; /* bpp in projection image */ - gint proj_level; /* projection level */ - TileManager *projection; /* The projection--layers & */ - /* channels */ - - GList *guides; /* guides */ - - /* Layer/Channel attributes */ - GimpContainer *layers; /* the list of layers */ - GimpContainer *channels; /* the list of masks */ - GSList *layer_stack; /* the layers in MRU order */ - - GimpLayer *active_layer; /* the active layer */ - GimpChannel *active_channel; /* the active channel */ - GimpLayer *floating_sel; /* the FS layer */ - GimpChannel *selection_mask; /* the selection mask channel */ - - GimpParasiteList *parasites; /* Plug-in parasite data */ - - PathList *paths; /* Paths data for this image */ - - gboolean visible[MAX_CHANNELS]; /* visible channels */ - gboolean active[MAX_CHANNELS]; /* active channels */ - - gboolean qmask_state; /* TRUE if qmask is on */ - GimpRGB qmask_color; /* rgba triplet of the color */ - - /* Old undo apparatus */ - GSList *undo_stack; /* stack for undo operations */ - GSList *redo_stack; /* stack for redo operations */ - gint undo_bytes; /* bytes in undo stack */ - gint undo_levels; /* levels in undo stack */ - gint group_count; /* nested undo groups */ - UndoType pushing_undo_group; /* undo group status flag */ - - /* New undo apparatus */ - GimpUndoStack *new_undo_stack; /* stack for undo operations */ - GimpUndoStack *new_redo_stack; /* stack for redo operations */ - - /* Composite preview */ - TempBuf *comp_preview; /* the composite preview */ - gboolean comp_preview_valid; /* preview valid-1/channel */ -}; - -struct _GimpImageClass -{ - GimpViewableClass parent_class; - - void (* mode_changed) (GimpImage *gimage); - void (* alpha_changed) (GimpImage *gimage); - void (* floating_selection_changed) (GimpImage *gimage); - void (* active_layer_changed) (GimpImage *gimage); - void (* active_channel_changed) (GimpImage *gimage); - void (* component_visibility_changed) (GimpImage *gimage, - ChannelType channel); - void (* component_active_changed) (GimpImage *gimage, - ChannelType channel); - void (* mask_changed) (GimpImage *gimage); - void (* resolution_changed) (GimpImage *gimage); - void (* unit_changed) (GimpImage *gimage); - void (* qmask_changed) (GimpImage *gimage); - void (* selection_control) (GimpImage *gimage, - GimpSelectionControl control); - - void (* clean) (GimpImage *gimage); - void (* dirty) (GimpImage *gimage); - void (* update) (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); - void (* update_guide) (GimpImage *gimage, - GimpGuide *guide); - void (* colormap_changed) (GimpImage *gimage, - gint color_index); - void (* undo_event) (GimpImage *gimage, - gint event); - - void (* undo) (GimpImage *gimage); - void (* redo) (GimpImage *gimage); -}; - - -/* function declarations */ - -GType gimp_image_get_type (void) G_GNUC_CONST; - -GimpImage * gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type); - -gint gimp_image_get_ID (GimpImage *gimage); -GimpImage * gimp_image_get_by_ID (Gimp *gimp, - gint id); - -void gimp_image_set_filename (GimpImage *gimage, - const gchar *filename); -void gimp_image_set_resolution (GimpImage *gimage, - gdouble xres, - gdouble yres); -void gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution); -void gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit); -GimpUnit gimp_image_get_unit (const GimpImage *gimage); - -void gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state); -gboolean gimp_image_get_qmask_state (const GimpImage *gimage); - -void gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc); -PlugInProcDef * gimp_image_get_save_proc (const GimpImage *gimage); - -gint gimp_image_get_width (const GimpImage *gimage); -gint gimp_image_get_height (const GimpImage *gimage); - -void gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y); -void gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data); -gboolean gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height); - -TileManager * gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); -void gimp_image_free_shadow (GimpImage *gimage); - -void gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - TileManager *src1_tiles, - gint x, - gint y); -void gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y); - -void gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg); -void gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg); -void gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src); -void gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type); - -GimpGuide * gimp_image_add_hguide (GimpImage *gimage); -GimpGuide * gimp_image_add_vguide (GimpImage *gimage); -void gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide); -GimpGuide * gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty); -gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1); - -GimpParasite * gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name); -gchar ** gimp_image_parasite_list (const GimpImage *gimage, - gint *count); -void gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite); -void gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite); - -GimpTattoo gimp_image_get_new_tattoo (GimpImage *gimage); -gboolean gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val); -GimpTattoo gimp_image_get_tattoo_state (GimpImage *gimage); - -void gimp_image_set_paths (GimpImage *gimage, - PathList *paths); -PathList * gimp_image_get_paths (const GimpImage *gimage); - -/* Temporary hack till colormap manipulation is encapsulated in functions. - * Call this whenever you modify an image's colormap. The col argument - * specifies which color has changed, or negative if there's a bigger change. - * Currently, use this also when the image's base type is changed to/from - * indexed. - */ -void gimp_image_colormap_changed (GimpImage *gimage, - gint col); - -void gimp_image_mode_changed (GimpImage *gimage); -void gimp_image_alpha_changed (GimpImage *gimage); -void gimp_image_floating_selection_changed (GimpImage *gimage); -void gimp_image_mask_changed (GimpImage *gimage); -void gimp_image_resolution_changed (GimpImage *gimage); -void gimp_image_unit_changed (GimpImage *gimage); -void gimp_image_qmask_changed (GimpImage *gimage); -void gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); -void gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control); - - -/* layer/channel functions */ - -GimpContainer * gimp_image_get_layers (const GimpImage *gimage); -GimpContainer * gimp_image_get_channels (const GimpImage *gimage); - -gint gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer); -gint gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel); -GimpLayer * gimp_image_get_active_layer (const GimpImage *gimage); -GimpChannel * gimp_image_get_active_channel (const GimpImage *gimage); -GimpLayer * gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name); -GimpChannel * gimp_image_get_mask (const GimpImage *gimage); - -void gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active); -gboolean gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type); -void gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active); - -void gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible); -gboolean gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type); - -gboolean gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs); -GimpLayer * gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer); -GimpChannel * gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel); -GimpChannel * gimp_image_unset_active_channel (GimpImage *gimage); -GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo); -GimpLayer * gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type); -GimpLayer * gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type); -GimpLayer * gimp_image_flatten (GimpImage *gimage); -GimpLayer * gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type); -gboolean gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position); -void gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo); -gboolean gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position); -void gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel); - -void gimp_image_invalidate_layer_previews (GimpImage *gimage); -void gimp_image_invalidate_channel_previews (GimpImage *gimage); - - -/* Access functions */ - -gboolean gimp_image_is_empty (const GimpImage *gimage); -GimpDrawable * gimp_image_active_drawable (const GimpImage *gimage); - -GimpImageBaseType gimp_image_base_type (const GimpImage *gimage); -GimpImageType gimp_image_base_type_with_alpha (const GimpImage *gimage); - -const gchar * gimp_image_filename (const GimpImage *gimage); -gboolean gimp_image_undo_is_enabled (const GimpImage *gimage); -gboolean gimp_image_undo_enable (GimpImage *gimage); -gboolean gimp_image_undo_disable (GimpImage *gimage); -gboolean gimp_image_undo_freeze (GimpImage *gimage); -gboolean gimp_image_undo_thaw (GimpImage *gimage); -void gimp_image_undo_event (GimpImage *gimage, - gint event); -gint gimp_image_dirty (GimpImage *gimage); -gint gimp_image_clean (GimpImage *gimage); -void gimp_image_clean_all (GimpImage *gimage); -GimpLayer * gimp_image_floating_sel (const GimpImage *gimage); -guchar * gimp_image_cmap (const GimpImage *gimage); - -gboolean gimp_image_preview_valid (const GimpImage *gimage); - - -#endif /* __GIMP_IMAGE_H__ */ +#endif /* __GIMP_IMAGE_GUIDES_H__ */ diff --git a/app/core/gimpimage-mask.c b/app/core/gimpimage-mask.c index d773351bbb..0633725040 100644 --- a/app/core/gimpimage-mask.c +++ b/app/core/gimpimage-mask.c @@ -20,8 +20,6 @@ #include -#include - #include "core-types.h" #include "pdb/pdb-types.h" @@ -31,6 +29,8 @@ #include "paint-funcs/paint-funcs.h" +#include "pdb/procedural_db.h" + #include "gimpchannel.h" #include "gimpcontext.h" #include "gimpimage.h" @@ -42,16 +42,16 @@ #include "floating_sel.h" #include "undo.h" -#include "pdb/procedural_db.h" - #include "libgimp/gimpintl.h" /* local variables */ + static gboolean gimage_mask_stroking = FALSE; -/* functions */ +/* public functions */ + gboolean gimage_mask_boundary (GimpImage *gimage, BoundSeg **segs_in, diff --git a/app/core/gimpimage-mask.h b/app/core/gimpimage-mask.h index 2ecac4cbde..022208eb73 100644 --- a/app/core/gimpimage-mask.h +++ b/app/core/gimpimage-mask.h @@ -16,83 +16,83 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __GIMAGE_MASK_H__ -#define __GIMAGE_MASK_H__ +#ifndef __GIMP_IMAGE_MASK_H__ +#define __GIMP_IMAGE_MASK_H__ -gboolean gimage_mask_boundary (GimpImage *gimage, - BoundSeg **segs_in, - BoundSeg **segs_out, - gint *num_segs_in, - gint *num_segs_out); +gboolean gimage_mask_boundary (GimpImage *gimage, + BoundSeg **segs_in, + BoundSeg **segs_out, + gint *num_segs_in, + gint *num_segs_out); -gboolean gimage_mask_bounds (GimpImage *gimage, - gint *x1, - gint *y1, - gint *x2, - gint *y2); +gboolean gimage_mask_bounds (GimpImage *gimage, + gint *x1, + gint *y1, + gint *x2, + gint *y2); -void gimage_mask_invalidate (GimpImage *gimage); +void gimage_mask_invalidate (GimpImage *gimage); -gint gimage_mask_value (GimpImage *gimage, - gint x, - gint y); +gint gimage_mask_value (GimpImage *gimage, + gint x, + gint y); -gboolean gimage_mask_is_empty (GimpImage *gimage); +gboolean gimage_mask_is_empty (GimpImage *gimage); -void gimage_mask_translate (GimpImage *gimage, - gint off_x, - gint off_y); +void gimage_mask_translate (GimpImage *gimage, + gint off_x, + gint off_y); -TileManager * gimage_mask_extract (GimpImage *gimage, - GimpDrawable *drawable, - gboolean cut_gimage, - gboolean keep_indexed, - gboolean add_alpha); +TileManager * gimage_mask_extract (GimpImage *gimage, + GimpDrawable *drawable, + gboolean cut_gimage, + gboolean keep_indexed, + gboolean add_alpha); -GimpLayer * gimage_mask_float (GimpImage *gimage, - GimpDrawable *drawable, - gint off_x, - gint off_y); +GimpLayer * gimage_mask_float (GimpImage *gimage, + GimpDrawable *drawable, + gint off_x, + gint off_y); -void gimage_mask_clear (GimpImage *gimage); -void gimage_mask_undo (GimpImage *gimage); -void gimage_mask_invert (GimpImage *gimage); -void gimage_mask_sharpen (GimpImage *gimage); -void gimage_mask_all (GimpImage *gimage); -void gimage_mask_none (GimpImage *gimage); +void gimage_mask_clear (GimpImage *gimage); +void gimage_mask_undo (GimpImage *gimage); +void gimage_mask_invert (GimpImage *gimage); +void gimage_mask_sharpen (GimpImage *gimage); +void gimage_mask_all (GimpImage *gimage); +void gimage_mask_none (GimpImage *gimage); -void gimage_mask_feather (GimpImage *gimage, - gdouble feather_radius_x, - gdouble feather_radius_y); +void gimage_mask_feather (GimpImage *gimage, + gdouble feather_radius_x, + gdouble feather_radius_y); -void gimage_mask_border (GimpImage *gimage, - gint border_radius_x, - gint border_radius_y); +void gimage_mask_border (GimpImage *gimage, + gint border_radius_x, + gint border_radius_y); -void gimage_mask_grow (GimpImage *gimage, - gint grow_pixels_x, - gint grow_pixels_y); +void gimage_mask_grow (GimpImage *gimage, + gint grow_pixels_x, + gint grow_pixels_y); -void gimage_mask_shrink (GimpImage *gimage, - gint shrink_pixels_x, - gint shrink_pixels_y, - gboolean edge_lock); +void gimage_mask_shrink (GimpImage *gimage, + gint shrink_pixels_x, + gint shrink_pixels_y, + gboolean edge_lock); -void gimage_mask_layer_alpha (GimpImage *gimage, - GimpLayer *layer); +void gimage_mask_layer_alpha (GimpImage *gimage, + GimpLayer *layer); -void gimage_mask_layer_mask (GimpImage *gimage, - GimpLayer *layer); +void gimage_mask_layer_mask (GimpImage *gimage, + GimpLayer *layer); -void gimage_mask_load (GimpImage *gimage, - GimpChannel *channel); +void gimage_mask_load (GimpImage *gimage, + GimpChannel *channel); -GimpChannel * gimage_mask_save (GimpImage *gimage); +GimpChannel * gimage_mask_save (GimpImage *gimage); -gboolean gimage_mask_stroke (GimpImage *gimage, - GimpDrawable *drawable, - GimpContext *context); +gboolean gimage_mask_stroke (GimpImage *gimage, + GimpDrawable *drawable, + GimpContext *context); -#endif /* __GIMAGE_MASK_H__ */ +#endif /* __GIMP_IMAGE_MASK_H__ */ diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c index cd786391e4..ee6775ea30 100644 --- a/app/core/gimpimage-merge.c +++ b/app/core/gimpimage-merge.c @@ -18,8 +18,6 @@ #include "config.h" -#include - #include #include "libgimpcolor/gimpcolor.h" @@ -35,11 +33,9 @@ #include "paint-funcs/paint-funcs.h" #include "gimp.h" -#include "gimpcontext.h" -#include "gimpcoreconfig.h" #include "gimpimage.h" #include "gimpimage-colorhash.h" -#include "gimpimage-mask.h" +#include "gimpimage-merge.h" #include "gimpimage-projection.h" #include "gimpimage-undo.h" #include "gimplayer.h" @@ -57,2610 +53,7 @@ #include "libgimp/gimpintl.h" -#ifdef DEBUG -#define TRC(x) printf x -#else -#define TRC(x) -#endif - -#define GUIDE_EPSILON 5 - - -enum -{ - MODE_CHANGED, - ALPHA_CHANGED, - FLOATING_SELECTION_CHANGED, - ACTIVE_LAYER_CHANGED, - ACTIVE_CHANNEL_CHANGED, - COMPONENT_VISIBILITY_CHANGED, - COMPONENT_ACTIVE_CHANGED, - MASK_CHANGED, - RESOLUTION_CHANGED, - UNIT_CHANGED, - QMASK_CHANGED, - SELECTION_CONTROL, - - CLEAN, - DIRTY, - UPDATE, - UPDATE_GUIDE, - COLORMAP_CHANGED, - UNDO_EVENT, - LAST_SIGNAL -}; - - -/* local function prototypes */ - -static void gimp_image_class_init (GimpImageClass *klass); -static void gimp_image_init (GimpImage *gimage); - -static void gimp_image_dispose (GObject *object); -static void gimp_image_finalize (GObject *object); - -static void gimp_image_name_changed (GimpObject *object); -static void gimp_image_invalidate_preview (GimpViewable *viewable); -static void gimp_image_size_changed (GimpViewable *viewable); -static void gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol); -static TempBuf *gimp_image_get_preview (GimpViewable *gimage, - gint width, - gint height); -static TempBuf *gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height); -static void gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); - -/* - * Static variables - */ -static gint valid_combinations[][MAX_CHANNELS + 1] = -{ - /* RGB GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A }, - /* RGBA GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A }, - /* GRAY GIMAGE */ - { -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A, -1, -1 }, - /* GRAYA GIMAGE */ - { -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A, -1, -1 }, - /* INDEXED GIMAGE */ - { -1, COMBINE_INDEXED_INDEXED, COMBINE_INDEXED_INDEXED_A, -1, -1 }, - /* INDEXEDA GIMAGE */ - { -1, -1, COMBINE_INDEXED_A_INDEXED_A, -1, -1 }, -}; - -static guint gimp_image_signals[LAST_SIGNAL] = { 0 }; - -static GimpViewableClass *parent_class = NULL; - - -GType -gimp_image_get_type (void) -{ - static GType image_type = 0; - - if (! image_type) - { - static const GTypeInfo image_info = - { - sizeof (GimpImageClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gimp_image_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GimpImage), - 0, /* n_preallocs */ - (GInstanceInitFunc) gimp_image_init, - }; - - image_type = g_type_register_static (GIMP_TYPE_VIEWABLE, - "GimpImage", - &image_info, 0); - } - - return image_type; -} - -static void -gimp_image_class_init (GimpImageClass *klass) -{ - GObjectClass *object_class; - GimpObjectClass *gimp_object_class; - GimpViewableClass *viewable_class; - - object_class = G_OBJECT_CLASS (klass); - gimp_object_class = GIMP_OBJECT_CLASS (klass); - viewable_class = GIMP_VIEWABLE_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gimp_image_signals[MODE_CHANGED] = - g_signal_new ("mode_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mode_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ALPHA_CHANGED] = - g_signal_new ("alpha_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, alpha_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[FLOATING_SELECTION_CHANGED] = - g_signal_new ("floating_selection_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, floating_selection_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_LAYER_CHANGED] = - g_signal_new ("active_layer_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_layer_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_CHANNEL_CHANGED] = - g_signal_new ("active_channel_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_channel_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] = - g_signal_new ("component_visibility_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_visibility_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[COMPONENT_ACTIVE_CHANGED] = - g_signal_new ("component_active_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_active_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[MASK_CHANGED] = - g_signal_new ("mask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[RESOLUTION_CHANGED] = - g_signal_new ("resolution_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, resolution_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UNIT_CHANGED] = - g_signal_new ("unit_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, unit_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[QMASK_CHANGED] = - g_signal_new ("qmask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, qmask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[SELECTION_CONTROL] = - g_signal_new ("selection_control", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, selection_control), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[CLEAN] = - g_signal_new ("clean", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, clean), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[DIRTY] = - g_signal_new ("dirty", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, dirty), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UPDATE] = - g_signal_new ("update", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update), - NULL, NULL, - gimp_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT); - - gimp_image_signals[UPDATE_GUIDE] = - g_signal_new ("update_guide", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update_guide), - NULL, NULL, - gimp_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - gimp_image_signals[COLORMAP_CHANGED] = - g_signal_new ("colormap_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, colormap_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[UNDO_EVENT] = - g_signal_new ("undo_event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, undo_event), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - object_class->dispose = gimp_image_dispose; - object_class->finalize = gimp_image_finalize; - - gimp_object_class->name_changed = gimp_image_name_changed; - - viewable_class->invalidate_preview = gimp_image_invalidate_preview; - viewable_class->size_changed = gimp_image_size_changed; - viewable_class->get_preview = gimp_image_get_preview; - viewable_class->get_new_preview = gimp_image_get_new_preview; - - klass->mode_changed = NULL; - klass->alpha_changed = NULL; - klass->floating_selection_changed = NULL; - klass->active_layer_changed = NULL; - klass->active_channel_changed = NULL; - klass->component_visibility_changed = NULL; - klass->component_active_changed = NULL; - klass->mask_changed = NULL; - - klass->clean = NULL; - klass->dirty = NULL; - klass->update = NULL; - klass->update_guide = NULL; - klass->colormap_changed = gimp_image_real_colormap_changed; - klass->undo_event = NULL; - klass->undo = gimp_image_undo; - klass->redo = gimp_image_redo; - - gimp_image_color_hash_init (); -} - - -/* static functions */ - -static void -gimp_image_init (GimpImage *gimage) -{ - gimage->ID = 0; - - gimage->save_proc = NULL; - - gimage->width = 0; - gimage->height = 0; - gimage->xresolution = 1.0; - gimage->yresolution = 1.0; - gimage->unit = GIMP_UNIT_INCH; - gimage->base_type = RGB; - - gimage->cmap = NULL; - gimage->num_cols = 0; - - gimage->dirty = 1; - gimage->undo_on = TRUE; - - gimage->instance_count = 0; - gimage->disp_count = 0; - - gimage->tattoo_state = 0; - - gimage->shadow = NULL; - - gimage->construct_flag = FALSE; - gimage->proj_type = RGBA_GIMAGE; - gimage->projection = NULL; - - gimage->guides = NULL; - - gimage->layers = gimp_list_new (GIMP_TYPE_LAYER, - GIMP_CONTAINER_POLICY_STRONG); - gimage->channels = gimp_list_new (GIMP_TYPE_CHANNEL, - GIMP_CONTAINER_POLICY_STRONG); - gimage->layer_stack = NULL; - - gimage->active_layer = NULL; - gimage->active_channel = NULL; - gimage->floating_sel = NULL; - gimage->selection_mask = NULL; - - gimage->parasites = gimp_parasite_list_new (); - - gimage->paths = NULL; - - gimage->qmask_state = FALSE; - gimage->qmask_color.r = 1.0; - gimage->qmask_color.g = 0.0; - gimage->qmask_color.b = 0.0; - gimage->qmask_color.a = 0.5; - - gimage->undo_stack = NULL; - gimage->redo_stack = NULL; - gimage->undo_bytes = 0; - gimage->undo_levels = 0; - gimage->group_count = 0; - gimage->pushing_undo_group = UNDO_NULL; - - gimage->new_undo_stack = gimp_undo_stack_new (gimage); - gimage->new_redo_stack = gimp_undo_stack_new (gimage); - - gimage->comp_preview = NULL; - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_dispose (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - undo_free (gimage); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gimp_image_finalize (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - if (gimage->gimp && gimage->gimp->image_table) - { - g_hash_table_remove (gimage->gimp->image_table, - GINT_TO_POINTER (gimage->ID)); - gimage->gimp = NULL; - } - - if (gimage->projection) - gimp_image_projection_free (gimage); - - if (gimage->shadow) - gimp_image_free_shadow (gimage); - - if (gimage->cmap) - { - g_free (gimage->cmap); - gimage->cmap = NULL; - } - - if (gimage->layers) - { - g_object_unref (G_OBJECT (gimage->layers)); - gimage->layers = NULL; - } - if (gimage->channels) - { - g_object_unref (G_OBJECT (gimage->channels)); - gimage->channels = NULL; - } - if (gimage->layer_stack) - { - g_slist_free (gimage->layer_stack); - gimage->layer_stack = NULL; - } - - if (gimage->selection_mask) - { - g_object_unref (G_OBJECT (gimage->selection_mask)); - gimage->selection_mask = NULL; - } - - if (gimage->comp_preview) - { - temp_buf_free (gimage->comp_preview); - gimage->comp_preview = NULL; - } - - if (gimage->parasites) - { - g_object_unref (G_OBJECT (gimage->parasites)); - gimage->parasites = NULL; - } - - if (gimage->guides) - { - g_list_foreach (gimage->guides, (GFunc) g_free, NULL); - g_list_free (gimage->guides); - gimage->guides = NULL; - } - - if (gimage->new_undo_stack) - { - g_object_unref (G_OBJECT (gimage->new_undo_stack)); - gimage->new_undo_stack = NULL; - } - if (gimage->new_redo_stack) - { - g_object_unref (G_OBJECT (gimage->new_redo_stack)); - gimage->new_redo_stack = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gimp_image_name_changed (GimpObject *object) -{ - GimpImage *gimage; - const gchar *name; - - if (GIMP_OBJECT_CLASS (parent_class)->name_changed) - GIMP_OBJECT_CLASS (parent_class)->name_changed (object); - - gimage = GIMP_IMAGE (object); - name = gimp_object_get_name (object); - - if (! (name && strlen (name))) - { - g_free (object->name); - object->name = NULL; - } -} - -static void -gimp_image_invalidate_preview (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview) - GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_size_changed (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed) - GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimp_image_invalidate_layer_previews (gimage); - gimp_image_invalidate_channel_previews (gimage); -} - -static void -gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol) -{ - if (gimp_image_base_type (gimage) == INDEXED) - gimp_image_color_hash_invalidate (gimage, ncol); -} - -static void -gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - /* allocate the new projection */ - gimage->shadow = tile_manager_new (width, height, bpp); -} - - -/* function definitions */ - -GimpImage * -gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type) -{ - GimpImage *gimage; - gint i; - - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - gimage = GIMP_IMAGE (g_object_new (GIMP_TYPE_IMAGE, NULL)); - - gimage->gimp = gimp; - gimage->ID = gimp->next_image_ID++; - - g_hash_table_insert (gimp->image_table, - GINT_TO_POINTER (gimage->ID), - (gpointer) gimage); - - gimage->width = width; - gimage->height = height; - gimage->base_type = base_type; - - gimage->xresolution = gimp->config->default_xresolution; - gimage->yresolution = gimp->config->default_yresolution; - gimage->unit = gimp->config->default_units; - - switch (base_type) - { - case RGB: - case GRAY: - break; - case INDEXED: - /* always allocate 256 colors for the colormap */ - gimage->num_cols = 0; - gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE); - break; - default: - break; - } - - /* set all color channels visible and active */ - for (i = 0; i < MAX_CHANNELS; i++) - { - gimage->visible[i] = TRUE; - gimage->active[i] = TRUE; - } - - /* create the selection mask */ - gimage->selection_mask = gimp_channel_new_mask (gimage, - gimage->width, - gimage->height); - - - return gimage; -} - -gint -gimp_image_get_ID (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->ID; -} - -GimpImage * -gimp_image_get_by_ID (Gimp *gimp, - gint image_id) -{ - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - if (gimp->image_table == NULL) - return NULL; - - return (GimpImage *) g_hash_table_lookup (gimp->image_table, - GINT_TO_POINTER (image_id)); -} - -void -gimp_image_set_filename (GimpImage *gimage, - const gchar *filename) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_object_set_name (GIMP_OBJECT (gimage), filename); -} - -void -gimp_image_set_resolution (GimpImage *gimage, - gdouble xresolution, - gdouble yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* don't allow to set the resolution out of bounds */ - if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION || - yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION) - return; - - if ((ABS (gimage->xresolution - xresolution) >= 1e-5) || - (ABS (gimage->yresolution - yresolution) >= 1e-5)) - { - undo_push_resolution (gimage); - - gimage->xresolution = xresolution; - gimage->yresolution = yresolution; - - gimp_image_resolution_changed (gimage); - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - } -} - -void -gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (xresolution && yresolution); - - *xresolution = gimage->xresolution; - *yresolution = gimage->yresolution; -} - -void -gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->unit != unit) - { - undo_push_resolution (gimage); - - gimage->unit = unit; - - gimp_image_unit_changed (gimage); - } -} - -GimpUnit -gimp_image_get_unit (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_UNIT_INCH); - - return gimage->unit; -} - -void -gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (qmask_state != gimage->qmask_state) - { - gimage->qmask_state = qmask_state ? TRUE : FALSE; - - gimp_image_qmask_changed (gimage); - } -} - -gboolean -gimp_image_get_qmask_state (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->qmask_state; -} - -void -gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->save_proc = proc; -} - -PlugInProcDef * -gimp_image_get_save_proc (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->save_proc; -} - -gint -gimp_image_get_width (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->width; -} - -gint -gimp_image_get_height (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->height; -} - -void -gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GList *guide_list; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_RESIZE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - gimage->width = new_width; - gimage->height = new_height; - - /* Resize all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y); - } - - /* Reposition or remove any guides */ - guide_list = gimage->guides; - while (guide_list) - { - GimpGuide *guide; - - guide = (GimpGuide *) guide_list->data; - guide_list = g_list_next (guide_list); - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position += offset_y; - if (guide->position < 0 || guide->position > new_height) - gimp_image_delete_guide (gimage, guide); - break; - - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position += offset_x; - if (guide->position < 0 || guide->position > new_width) - gimp_image_delete_guide (gimage, guide); - break; - - default: - g_error ("Unknown guide orientation\n"); - } - } - - /* Don't forget the selection mask! */ - gimp_channel_resize (gimage->selection_mask, - new_width, new_height, offset_x, offset_y); - gimage_mask_invalidate (gimage); - - /* Reposition all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - gimp_layer_translate (layer, offset_x, offset_y); - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -void -gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GSList *remove = NULL; - GSList *slist; - GimpGuide *guide; - gint old_width; - gint old_height; - gdouble img_scale_w = 1.0; - gdouble img_scale_h = 1.0; - gint num_channels; - gint num_layers; - gint progress_current = 1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - num_channels = gimage->channels->num_children; - num_layers = gimage->layers->num_children; - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_SCALE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - - old_width = gimage->width; - old_height = gimage->height; - gimage->width = new_width; - gimage->height = new_height; - img_scale_w = (gdouble) new_width / (gdouble) old_width; - img_scale_h = (gdouble) new_height / (gdouble) old_height; - - /* Scale all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_scale (channel, new_width, new_height); - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* Don't forget the selection mask! */ - /* if (channel_is_empty(gimage->selection_mask)) - gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0) - else - */ - - gimp_channel_scale (gimage->selection_mask, new_width, new_height); - gimage_mask_invalidate (gimage); - - /* Scale all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h)) - { - /* Since 0 < img_scale_w, img_scale_h, failure due to one or more - * vanishing scaled layer dimensions. Implicit delete implemented - * here. Upstream warning implemented in resize_check_layer_scaling() - * [resize.c line 1295], which offers the user the chance to bail out. - */ - remove = g_slist_append (remove, layer); - } - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* We defer removing layers lost to scaling until now so as not to mix - * the operations of iterating over and removal from gimage->layers. - */ - for (slist = remove; slist; slist = g_slist_next (slist)) - { - layer = slist->data; - gimp_image_remove_layer (gimage, layer); - } - g_slist_free (remove); - - /* Scale any Guides */ - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_height) / old_height; - break; - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_width) / old_width; - break; - default: - g_error("Unknown guide orientation II.\n"); - } - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -/** - * gimp_image_check_scaling: - * @gimage: A #GimpImage. - * @new_width: The new width. - * @new_height: The new height. - * - * Inventory the layer list in gimage and return #TRUE if, after - * scaling, they all retain positive x and y pixel dimensions. - * - * Return value: #TRUE if scaling the image will shrink none of it's - * layers completely away. - **/ -gboolean -gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height) -{ - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpLayer *layer; - - layer = (GimpLayer *) list->data; - - if (! gimp_layer_check_scaling (layer, new_width, new_height)) - return FALSE; - } - - return TRUE; -} - -TileManager * -gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (gimage->shadow && - ((width != tile_manager_width (gimage->shadow)) || - (height != tile_manager_height (gimage->shadow)) || - (bpp != tile_manager_bpp (gimage->shadow)))) - gimp_image_free_shadow (gimage); - else if (gimage->shadow) - return gimage->shadow; - - gimp_image_allocate_shadow (gimage, width, height, bpp); - - return gimage->shadow; -} - -void -gimp_image_free_shadow (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->shadow) - { - tile_manager_destroy (gimage->shadow); - gimage->shadow = NULL; - } -} - -void -gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - /* alternative to using drawable tiles as src1: */ - TileManager *src1_tiles, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR, maskPR; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations[gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - if (src1_tiles) - pixel_region_init (&src1PR, src1_tiles, - x1, y1, (x2 - x1), (y2 - y1), FALSE); - else - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - gint mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL, - opacity, mode, active, operation); - } - else - { - combine_regions (&src1PR, src2PR, &destPR, NULL, NULL, - opacity, mode, active, operation); - } -} - -/* Similar to gimp_image_apply_image but works in "replace" mode (i.e. - transparent pixels in src2 make the result transparent rather - than opaque. - - Takes an additional mask pixel region as well. -*/ -void -gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR; - PixelRegion mask2PR, tempPR; - guchar *temp_data; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations [gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - gimp_drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - int mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&mask2PR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - - tempPR.bytes = 1; - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.rowstride = tempPR.w * tempPR.bytes; - temp_data = g_malloc (tempPR.h * tempPR.rowstride); - tempPR.data = temp_data; - - copy_region (&mask2PR, &tempPR); - - /* apparently, region operations can mutate some PR data. */ - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); - - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, - opacity, active, operation); - - g_free (temp_data); - } - else - { - combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL, - opacity, active, operation); - } -} - -/* Get rid of these! A "foreground" is an UI concept.. */ - -void -gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg) -{ - GimpRGB color; - guchar pfg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (fg != NULL); - - gimp_context_get_foreground (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]); - - gimp_image_transform_color (gimage, drawable, pfg, fg, RGB); -} - -void -gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg) -{ - GimpRGB color; - guchar pbg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (bg != NULL); - - gimp_context_get_background (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]); - - gimp_image_transform_color (gimage, drawable, pbg, bg, RGB); -} - -void -gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - map_to_color (0, NULL, src, rgb); - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - map_to_color (1, NULL, src, rgb); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - map_to_color (2, gimage->cmap, src, rgb); - break; - } -} - -void -gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type) -{ - GimpImageType d_type; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - d_type = (drawable != NULL) ? gimp_drawable_type (drawable) : - gimp_image_base_type_with_alpha (gimage); - - switch (type) - { - case RGB: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Straight copy */ - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* NTSC conversion */ - *dest = INTENSITY (src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - } - break; - case GRAY: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Gray to RG&B */ - *dest++ = *src; - *dest++ = *src; - *dest++ = *src; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* Straight copy */ - *dest = *src; - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[GRAY_PIX], - src[GRAY_PIX], - src[GRAY_PIX]); - break; - } - break; - default: - break; - } -} - -GimpGuide * -gimp_image_add_hguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_HORIZONTAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -GimpGuide * -gimp_image_add_vguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_VERTICAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -void -gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_prepend (gimage->guides, guide); -} - -void -gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_remove (gimage->guides, guide); -} - -void -gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide) -{ - guide->position = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (guide->ref_count <= 0) - { - gimage->guides = g_list_remove (gimage->guides, guide); - g_free (guide); - } -} - -GimpGuide * -gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y) -{ - GList *list; - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return NULL; - } - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - if (ABS (guide->position - y) < GUIDE_EPSILON) - return guide; - break; - - case ORIENTATION_VERTICAL: - if (ABS (guide->position - x) < GUIDE_EPSILON) - return guide; - break; - - default: - break; - } - } - - return NULL; -} - -gboolean -gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty) -{ - GList *list; - GimpGuide *guide; - gint minxdist, minydist; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx != NULL, FALSE); - g_return_val_if_fail (ty != NULL, FALSE); - - *tx = x; - *ty = y; - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return FALSE; - } - - minxdist = G_MAXINT; - minydist = G_MAXINT; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - dist = ABS (guide->position - y); - - if (dist < MIN (GUIDE_EPSILON, minydist)) - { - minydist = dist; - *ty = guide->position; - snapped = TRUE; - } - break; - - case ORIENTATION_VERTICAL: - dist = ABS (guide->position - x); - - if (dist < MIN (GUIDE_EPSILON, minxdist)) - { - minxdist = dist; - *tx = guide->position; - snapped = TRUE; - } - break; - - default: - break; - } - } - - return snapped; -} - -gboolean -gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1) -{ - gint nx1, ny1; - gint nx2, ny2; - gboolean snap1, snap2; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx1 != NULL, FALSE); - g_return_val_if_fail (ty1 != NULL, FALSE); - - *tx1 = x1; - *ty1 = y1; - - snap1 = gimp_image_snap_point (gimage, x1, y1, &nx1, &ny1); - snap2 = gimp_image_snap_point (gimage, x2, y2, &nx2, &ny2); - - if (snap1 || snap2) - { - if (x1 != nx1) - *tx1 = nx1; - else if (x2 != nx2) - *tx1 = x1 + (nx2 - x2); - - if (y1 != ny1) - *ty1 = ny1; - else if (y2 != ny2) - *ty1 = y1 + (ny2 - y2); - } - - return snap1 || snap2; -} - -GimpParasite * -gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimp_parasite_list_find (gimage->parasites, name); -} - -static void -list_func (gchar *key, - GimpParasite *p, - gchar ***cur) -{ - *(*cur)++ = (gchar *) g_strdup (key); -} - -gchar ** -gimp_image_parasite_list (const GimpImage *gimage, - gint *count) -{ - gchar **list; - gchar **cur; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - *count = gimp_parasite_list_length (gimage->parasites); - cur = list = g_new (gchar*, *count); - - gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur); - - return list; -} - -void -gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL); - - /* only set the dirty bit manually if we can be saved and the new - parasite differs from the current one and we aren't undoable */ - if (gimp_parasite_is_undoable (parasite)) - undo_push_image_parasite (gimage, parasite); - - /* We used to push an cantundo on te stack here. This made the undo stack - unusable (NULL on the stack) and prevented people from undoing after a - save (since most save plug-ins attach an undoable comment parasite). - Now we simply attach the parasite without pushing an undo. That way it's - undoable but does not block the undo system. --Sven - */ - - gimp_parasite_list_add (gimage->parasites, parasite); - - if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT)) - { - gimp_parasite_shift_parent (parasite); - gimp_parasite_attach (gimage->gimp, parasite); - } -} - -void -gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite) -{ - GimpParasite *p; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (parasite != NULL); - - if (!(p = gimp_parasite_list_find (gimage->parasites, parasite))) - return; - - if (gimp_parasite_is_undoable (p)) - undo_push_image_parasite_remove (gimage, gimp_parasite_name (p)); - - gimp_parasite_list_remove (gimage->parasites, parasite); -} - -GimpTattoo -gimp_image_get_new_tattoo (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - gimage->tattoo_state++; - - if (gimage->tattoo_state <= 0) - g_warning ("%s: Tattoo state corrupted " - "(integer overflow).", G_GNUC_PRETTY_FUNCTION); - - return gimage->tattoo_state; -} - -GimpTattoo -gimp_image_get_tattoo_state (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->tattoo_state; -} - -gboolean -gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val) -{ - GList *list; - gboolean retval = TRUE; - GimpChannel *channel; - GimpTattoo maxval = 0; - Path *pptr = NULL; - PathList *plist; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ltattoo; - - ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data)); - if (ltattoo > maxval) - maxval = ltattoo; - if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in channel */ - } - - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Now check that the paths channel tattoos don't overlap */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ctattoo; - - channel = (GimpChannel *) list->data; - - ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)); - if (ctattoo > maxval) - maxval = ctattoo; - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ctattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Find the max tatto value in the paths */ - plist = gimage->paths; - - if (plist && plist->bz_paths) - { - GimpTattoo ptattoo; - GSList *pl; - - for (pl = plist->bz_paths; pl; pl = g_slist_next (pl)) - { - pptr = pl->data; - - ptattoo = path_get_tattoo (pptr); - - if (ptattoo > maxval) - maxval = ptattoo; - } - } - - if (val < maxval) - retval = FALSE; - /* Must check the state is valid */ - if (retval == TRUE) - gimage->tattoo_state = val; - - return retval; -} - -void -gimp_image_set_paths (GimpImage *gimage, - PathList *paths) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->paths = paths; -} - -PathList * -gimp_image_get_paths (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->paths; -} - -void -gimp_image_colormap_changed (GimpImage *gimage, - gint col) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (col < gimage->num_cols); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[COLORMAP_CHANGED], 0, - col); -} - -void -gimp_image_mode_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MODE_CHANGED], 0); -} - -void -gimp_image_mask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MASK_CHANGED], 0); -} - -void -gimp_image_resolution_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[RESOLUTION_CHANGED], 0); -} - -void -gimp_image_unit_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNIT_CHANGED], 0); -} - -void -gimp_image_qmask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[QMASK_CHANGED], 0); -} - -void -gimp_image_alpha_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED], 0); -} - -void -gimp_image_floating_selection_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[FLOATING_SELECTION_CHANGED], 0); -} - -void -gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE], 0, - x, y, width, height); -} - -void -gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (guide != NULL); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE_GUIDE], 0, - guide); -} - -void -gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[SELECTION_CONTROL], 0, - control); -} - -void -gimp_image_invalidate_layer_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->layers, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -void -gimp_image_invalidate_channel_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->channels, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -GimpContainer * -gimp_image_get_layers (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->layers; -} - -GimpContainer * -gimp_image_get_channels (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->channels; -} - -gint -gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_LAYER (layer), -1); - - return gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); -} - -gint -gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1); - - return gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); -} - -GimpLayer * -gimp_image_get_active_layer (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_layer; -} - -GimpChannel * -gimp_image_get_active_channel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_channel; -} - -GimpLayer * -gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo) - return layer; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name)) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_mask (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->selection_mask; -} - -void -gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && active != gimage->active[pixel]) - { - gimage->active[pixel] = active ? TRUE : FALSE; - - /* If there is an active channel and we mess with the components, - * the active channel gets unset... - */ - gimp_image_unset_active_channel (gimage); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, - type); - } -} - -gboolean -gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->active[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->active[ALPHA_PIX]; break; - case GRAY: return gimage->active[ALPHA_G_PIX]; break; - case INDEXED: return gimage->active[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -void -gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active) -{ - GimpLayer *layer; - gint i; - - /* first, blindly copy the gimage active channels */ - for (i = 0; i < MAX_CHANNELS; i++) - active[i] = gimage->active[i]; - - /* If the drawable is a channel (a saved selection, etc.) - * make sure that the alpha channel is not valid - */ - if (GIMP_IS_CHANNEL (drawable)) - { - active[ALPHA_G_PIX] = 0; /* no alpha values in channels */ - } - else - { - /* otherwise, check whether preserve transparency is - * enabled in the layer and if the layer has alpha - */ - if (GIMP_IS_LAYER (drawable)) - { - layer = GIMP_LAYER (drawable); - if (gimp_layer_has_alpha (layer) && layer->preserve_trans) - active[gimp_drawable_bytes (drawable) - 1] = 0; - } - } -} - -void -gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && visible != gimage->visible[pixel]) - { - gimage->visible[pixel] = visible ? TRUE : FALSE; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED], 0, - type); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - } -} - -gboolean -gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->visible[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->visible[ALPHA_PIX]; break; - case GRAY: return gimage->visible[ALPHA_G_PIX]; break; - case INDEXED: return gimage->visible[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -gboolean -gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs) -{ - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (segs != NULL, FALSE); - g_return_val_if_fail (n_segs != NULL, FALSE); - - /* The second boundary corresponds to the active layer's - * perimeter... - */ - layer = gimp_image_get_active_layer (gimage); - - if (layer) - { - *segs = gimp_layer_boundary (layer, n_segs); - return TRUE; - } - else - { - *segs = NULL; - *n_segs = 0; - return FALSE; - } -} - -GimpLayer * -gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); - - /* First, find the layer in the gimage - * If it isn't valid, find the first layer that is - */ - if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0); - - if (layer) - { - /* Configure the layer stack to reflect this change */ - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer); - - /* invalidate the selection boundary because of a layer modification */ - gimp_layer_invalidate_boundary (layer); - } - - if (layer != gimage->active_layer) - { - gimage->active_layer = layer; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - - if (gimage->active_channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - } - } - - /* return the layer */ - return layer; -} - -GimpChannel * -gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* Not if there is a floating selection */ - if (gimp_image_floating_sel (gimage)) - return NULL; - - /* First, find the channel - * If it doesn't exist, find the first channel that does - */ - if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0); - - if (channel != gimage->active_channel) - { - gimage->active_channel = channel; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->active_layer) - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* return the channel */ - return channel; -} - -GimpChannel * -gimp_image_unset_active_channel (GimpImage *gimage) -{ - GimpChannel *channel; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - channel = gimp_image_get_active_channel (gimage); - - if (channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->layer_stack) - { - GimpLayer *layer; - - layer = (GimpLayer *) gimage->layer_stack->data; - - gimp_image_set_active_layer (gimage, layer); - } - } - - return channel; -} - -GimpLayer * -gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_layer_pick_correlate (layer, x, y)) - return layer; - } - - return NULL; -} - -gboolean -gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the top layer already? */ - if (curpos == 0) - { - g_message (_("Layer cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE); -} - -gboolean -gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the bottom layer already? */ - length = gimp_container_num_children (gimage->layers); - if (curpos >= length - 1) - { - g_message (_("Layer cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE); -} - -gboolean -gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - if (curpos == 0) - { - g_message (_("Layer is already on top.")); - return FALSE; - } - - if (! gimp_layer_has_alpha (layer)) - { - g_message (_("Cannot raise a layer without alpha.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, 0, TRUE); -} - -gboolean -gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - length = gimp_container_num_children (gimage->layers); - - if (curpos >= length - 1) - { - g_message (_("Layer is already on the bottom.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, length - 1, TRUE); -} - -gboolean -gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo) -{ - gint off_x, off_y; - gint index; - gint num_layers; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - index = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - if (index < 0) - return FALSE; - - num_layers = gimp_container_num_children (gimage->layers); - - if (new_index < 0) - new_index = 0; - - if (new_index >= num_layers) - new_index = num_layers - 1; - - if (new_index == index) - return TRUE; - - /* check if we want to move it below a bottom layer without alpha */ - if (new_index == num_layers - 1) - { - GimpLayer *tmp; - - tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, - num_layers - 1); - - if (new_index == num_layers - 1 && - ! gimp_layer_has_alpha (tmp)) - { - g_message (_("Layer \"%s\" has no alpha.\nLayer was placed above it."), - GIMP_OBJECT (tmp)->name); - new_index--; - } - } - - if (push_undo) - undo_push_layer_reposition (gimage, layer); - - gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - gimp_image_update (gimage, - off_x, off_y, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); - - return TRUE; -} +/* public functions */ GimpLayer * gimp_image_merge_visible_layers (GimpImage *gimage, @@ -3019,8 +412,8 @@ gimp_image_merge_layers (GimpImage *gimage, /* determine what sort of operation is being attempted and * if it's actually legal... */ - operation = - valid_combinations[gimp_drawable_type (GIMP_DRAWABLE (merge_layer))][gimp_drawable_bytes (GIMP_DRAWABLE (layer))]; + operation = gimp_image_get_combination_mode (gimp_drawable_type (GIMP_DRAWABLE (merge_layer)), + gimp_drawable_bytes (GIMP_DRAWABLE (layer))); if (operation == -1) { @@ -3112,756 +505,3 @@ gimp_image_merge_layers (GimpImage *gimage, return merge_layer; } - -gboolean -gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position) -{ - LayerUndo *lu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - if (GIMP_DRAWABLE (layer)->gimage != NULL && - GIMP_DRAWABLE (layer)->gimage != gimage) - { - g_warning ("%s: attempting to add layer to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - { - g_warning ("%s: trying to add layer to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Prepare a layer undo and push it */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = 0; - lu->prev_layer = gimp_image_get_active_layer (gimage); - undo_push_layer (gimage, LAYER_ADD_UNDO, lu); - - /* If the layer is a floating selection, set the ID */ - if (gimp_layer_is_floating_sel (layer)) - gimage->floating_sel = layer; - - /* let the layer know about the gimage */ - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage); - - /* If the layer has a mask, set the mask's gimage */ - if (layer->mask) - { - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage); - } - - /* add the layer to the list at the specified position */ - if (position == -1) - { - GimpLayer *active_layer; - - active_layer = gimp_image_get_active_layer (gimage); - - if (active_layer) - { - position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (active_layer)); - } - else - { - position = 0; - } - } - - /* If there is a floating selection (and this isn't it!), - * make sure the insert position is greater than 0 - */ - if (position == 0 && - gimp_image_floating_sel (gimage) && - (gimage->floating_sel != layer)) - { - position = 1; - } - - gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position); - g_object_unref (G_OBJECT (layer)); - - /* notify the layers dialog of the currently active layer */ - gimp_image_set_active_layer (gimage, layer); - - /* update the new layer's area */ - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - return TRUE; -} - -void -gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer) -{ - LayerUndo *lu; - gint x, y, w, h; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_LAYER (layer)); - - g_return_if_fail (gimp_container_have (gimage->layers, - GIMP_OBJECT (layer))); - - /* Push a layer undo */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - lu->prev_layer = layer; - - undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu); - - g_object_ref (G_OBJECT (layer)); - - gimp_container_remove (gimage->layers, GIMP_OBJECT (layer)); - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - - /* If this was the floating selection, reset the fs pointer */ - if (gimage->floating_sel == layer) - { - gimage->floating_sel = NULL; - - floating_sel_reset (layer); - } - - if (layer == gimp_image_get_active_layer (gimage)) - { - if (gimage->layer_stack) - { - gimp_image_set_active_layer (gimage, gimage->layer_stack->data); - } - else - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* Send out REMOVED signal from layer */ - gimp_drawable_removed (GIMP_DRAWABLE (layer)); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &x, &y); - w = gimp_drawable_width (GIMP_DRAWABLE (layer)); - h = gimp_drawable_height (GIMP_DRAWABLE (layer)); - - g_object_unref (G_OBJECT (layer)); - - gimp_image_update (gimage, x, y, w, h); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -gboolean -gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == 0) - { - g_message (_("Channel cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index - 1, TRUE); -} - -gboolean -gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == gimp_container_num_children (gimage->channels) - 1) - { - g_message (_("Channel cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index + 1, TRUE); -} - -gboolean -gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo /* FIXME unused */) -{ - gint index; - gint num_channels; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index < 0) - return FALSE; - - num_channels = gimp_container_num_children (gimage->channels); - - new_index = CLAMP (new_index, 0, num_channels - 1); - - if (new_index == index) - return TRUE; - - gimp_container_reorder (gimage->channels, - GIMP_OBJECT (channel), new_index); - - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -gboolean -gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position) -{ - ChannelUndo *cu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - if (GIMP_DRAWABLE (channel)->gimage != NULL && - GIMP_DRAWABLE (channel)->gimage != gimage) - { - g_warning ("%s: attempting to add channel to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - { - g_warning ("%s: trying to add channel to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Push a channel undo */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = 0; - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu); - - /* add the channel to the list */ - gimp_container_add (gimage->channels, GIMP_OBJECT (channel)); - g_object_unref (G_OBJECT (channel)); - - /* notify this gimage of the currently active channel */ - gimp_image_set_active_channel (gimage, channel); - - /* if channel is visible, update the image */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -void -gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel) -{ - ChannelUndo *cu; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_CHANNEL (channel)); - - g_return_if_fail (gimp_container_have (gimage->channels, - GIMP_OBJECT (channel))); - - /* Prepare a channel undo--push it below */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu); - - g_object_ref (G_OBJECT (channel)); - - gimp_container_remove (gimage->channels, GIMP_OBJECT (channel)); - - /* Send out REMOVED signal from channel */ - gimp_drawable_removed (GIMP_DRAWABLE (channel)); - - if (channel == gimp_image_get_active_channel (gimage)) - { - if (gimp_container_num_children (gimage->channels) > 0) - { - gimp_image_set_active_channel - (gimage, - GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels, - 0))); - } - else - { - gimp_image_unset_active_channel (gimage); - } - } - - g_object_unref (G_OBJECT (channel)); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -/************************************************************/ -/* Access functions */ -/************************************************************/ - -gboolean -gimp_image_is_empty (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE); - - return (gimp_container_num_children (gimage->layers) == 0); -} - -GimpDrawable * -gimp_image_active_drawable (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* If there is an active channel (a saved selection, etc.), - * we ignore the active layer - */ - if (gimage->active_channel) - { - return GIMP_DRAWABLE (gimage->active_channel); - } - else if (gimage->active_layer) - { - GimpLayer *layer; - - layer = gimage->active_layer; - - if (layer->mask && layer->mask->edit_mask) - return GIMP_DRAWABLE (layer->mask); - else - return GIMP_DRAWABLE (layer); - } - - return NULL; -} - -GimpImageBaseType -gimp_image_base_type (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->base_type; -} - -GimpImageType -gimp_image_base_type_with_alpha (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - switch (gimage->base_type) - { - case RGB: - return RGBA_GIMAGE; - case GRAY: - return GRAYA_GIMAGE; - case INDEXED: - return INDEXEDA_GIMAGE; - } - return RGB_GIMAGE; -} - -const gchar * -gimp_image_filename (const GimpImage *gimage) -{ - const gchar *filename; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - filename = gimp_object_get_name (GIMP_OBJECT (gimage)); - - return filename ? filename : _("Untitled"); -} - -gboolean -gimp_image_undo_is_enabled (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->undo_on; -} - -gboolean -gimp_image_undo_freeze (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = FALSE; - - return TRUE; -} - -gboolean -gimp_image_undo_thaw (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = TRUE; - - return TRUE; -} - -gboolean -gimp_image_undo_disable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimp_image_undo_freeze (gimage); -} - -gboolean -gimp_image_undo_enable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - /* Free all undo steps as they are now invalidated */ - undo_free (gimage); - - return gimp_image_undo_thaw (gimage); -} - -void -gimp_image_undo_event (GimpImage *gimage, - gint event) -{ - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], 0, - event); -} - - -/* NOTE about the gimage->dirty counter: - * If 0, then the image is clean (ie, copy on disk is the same as the one - * in memory). - * If positive, then that's the number of dirtying operations done - * on the image since the last save. - * If negative, then user has hit undo and gone back in time prior - * to the saved copy. Hitting redo will eventually come back to - * the saved copy. - * - * The image is dirty (ie, needs saving) if counter is non-zero. - * - * If the counter is around 10000, this is due to undo-ing back - * before a saved version, then mutating the image (thus destroying - * the redo stack). Once this has happened, it's impossible to get - * the image back to the state on disk, since the redo info has been - * freed. See undo.c for the gorey details. - */ - - -/* - * NEVER CALL gimp_image_dirty() directly! - * - * If your code has just dirtied the image, push an undo instead. - * Failing that, push the trivial undo which tells the user the - * command is not undoable: undo_push_cantundo() (But really, it would - * be best to push a proper undo). If you just dirty the image - * without pushing an undo then the dirty count is increased, but - * popping that many undo actions won't lead to a clean image. - */ - -gint -gimp_image_dirty (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty++; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[DIRTY], 0); - - TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty)); - - return gimage->dirty; -} - -gint -gimp_image_clean (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty--; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); - - TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty)); - - return gimage->dirty; -} - -void -gimp_image_clean_all (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->dirty = 0; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); -} - -GimpLayer * -gimp_image_floating_sel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - if (gimage->floating_sel == NULL) - return NULL; - else - return gimage->floating_sel; -} - -guchar * -gimp_image_cmap (const GimpImage *gimage) -{ - return gimp_drawable_cmap (gimp_image_active_drawable (gimage)); -} - -static TempBuf * -gimp_image_get_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (viewable); - - if (gimage->comp_preview_valid && - gimage->comp_preview->width == width && - gimage->comp_preview->height == height) - { - /* The easy way */ - return gimage->comp_preview; - } - else - { - /* The hard way */ - if (gimage->comp_preview) - temp_buf_free (gimage->comp_preview); - - /* Actually construct the composite preview from the layer previews! - * This might seem ridiculous, but it's actually the best way, given - * a number of unsavory alternatives. - */ - gimage->comp_preview = gimp_image_get_new_preview (viewable, - width, height); - - gimage->comp_preview_valid = TRUE; - - return gimage->comp_preview; - } -} - -static TempBuf * -gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - GimpLayer *layer; - GimpLayer *floating_sel; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - TempBuf *comp; - TempBuf *layer_buf; - TempBuf *mask_buf; - GList *list; - GSList *reverse_list = NULL; - gdouble ratio; - gint x, y, w, h; - gint x1, y1, x2, y2; - gint bytes; - gboolean construct_flag; - gint visible[MAX_CHANNELS] = { 1, 1, 1, 1 }; - gint off_x, off_y; - - gimage = GIMP_IMAGE (viewable); - - ratio = (gdouble) width / (gdouble) gimage->width; - - switch (gimp_image_base_type (gimage)) - { - case RGB: - case INDEXED: - bytes = 4; - break; - case GRAY: - bytes = 2; - break; - default: - bytes = 0; - break; - } - - /* The construction buffer */ - comp = temp_buf_new (width, height, bytes, 0, 0, NULL); - temp_buf_data_clear (comp); - - floating_sel = NULL; - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - /* only add layers that are visible to the list */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - { - /* floating selections are added right above the layer - * they are attached to - */ - if (gimp_layer_is_floating_sel (layer)) - { - floating_sel = layer; - } - else - { - if (floating_sel && - floating_sel->fs.drawable == GIMP_DRAWABLE (layer)) - { - reverse_list = g_slist_prepend (reverse_list, floating_sel); - } - - reverse_list = g_slist_prepend (reverse_list, layer); - } - } - } - - construct_flag = FALSE; - - for (; reverse_list; reverse_list = g_slist_next (reverse_list)) - { - layer = (GimpLayer *) reverse_list->data; - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - x = (gint) RINT (ratio * off_x); - y = (gint) RINT (ratio * off_y); - w = (gint) RINT (ratio * gimp_drawable_width (GIMP_DRAWABLE (layer))); - h = (gint) RINT (ratio * gimp_drawable_height (GIMP_DRAWABLE (layer))); - - if (w < 1 || h < 1) - continue; - - x1 = CLAMP (x, 0, width); - y1 = CLAMP (y, 0, height); - x2 = CLAMP (x + w, 0, width); - y2 = CLAMP (y + h, 0, height); - - src1PR.bytes = comp->bytes; - src1PR.x = x1; - src1PR.y = y1; - src1PR.w = (x2 - x1); - src1PR.h = (y2 - y1); - src1PR.rowstride = comp->width * src1PR.bytes; - src1PR.data = (temp_buf_data (comp) + - y1 * src1PR.rowstride + x1 * src1PR.bytes); - - layer_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h); - src2PR.bytes = layer_buf->bytes; - src2PR.w = src1PR.w; - src2PR.h = src1PR.h; - src2PR.x = src1PR.x; - src2PR.y = src1PR.y; - src2PR.rowstride = layer_buf->width * src2PR.bytes; - src2PR.data = (temp_buf_data (layer_buf) + - (y1 - y) * src2PR.rowstride + - (x1 - x) * src2PR.bytes); - - if (layer->mask && layer->mask->apply_mask) - { - mask_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer->mask), - w, h); - maskPR.bytes = mask_buf->bytes; - maskPR.rowstride = mask_buf->width; - maskPR.data = (mask_buf_data (mask_buf) + - (y1 - y) * maskPR.rowstride + - (x1 - x) * maskPR.bytes); - mask = &maskPR; - } - else - { - mask = NULL; - } - - /* Based on the type of the layer, project the layer onto the - * composite preview... - * Indexed images are actually already converted to RGB and RGBA, - * so just project them as if they were type "intensity" - * Send in all TRUE for visible since that info doesn't matter - * for previews - */ - switch (gimp_drawable_type (GIMP_DRAWABLE (layer))) - { - case RGB_GIMAGE: case GRAY_GIMAGE: case INDEXED_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN); - break; - - case RGBA_GIMAGE: case GRAYA_GIMAGE: case INDEXEDA_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY_ALPHA); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN_A); - break; - - default: - break; - } - - construct_flag = TRUE; - } - - g_slist_free (reverse_list); - - return comp; -} diff --git a/app/core/gimpimage-merge.h b/app/core/gimpimage-merge.h index be0b5eea83..5ffbb47e5d 100644 --- a/app/core/gimpimage-merge.h +++ b/app/core/gimpimage-merge.h @@ -16,370 +16,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __GIMP_IMAGE_H__ -#define __GIMP_IMAGE_H__ +#ifndef __GIMP_IMAGE_MERGE_H__ +#define __GIMP_IMAGE_MERGE_H__ -#include "gimpviewable.h" - - -#define COLORMAP_SIZE 768 - -#define GIMP_IMAGE_TYPE_HAS_ALPHA(t) ((t) == RGBA_GIMAGE || \ - (t) == GRAYA_GIMAGE || \ - (t) == INDEXEDA_GIMAGE) - - -struct _GimpGuide -{ - gint ref_count; - gint position; - InternalOrientationType orientation; - guint32 guide_ID; -}; - - -#define GIMP_TYPE_IMAGE (gimp_image_get_type ()) -#define GIMP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_IMAGE, GimpImage)) -#define GIMP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_IMAGE, GimpImageClass)) -#define GIMP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_IMAGE)) -#define GIMP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_IMAGE)) -#define GIMP_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_IMAGE, GimpImageClass)) - - -typedef struct _GimpImageClass GimpImageClass; - -struct _GimpImage -{ - GimpViewable parent_instance; - - Gimp *gimp; /* the GIMP the image belongs to*/ - - gint ID; /* provides a unique ID */ - - PlugInProcDef *save_proc; /* last PDB save proc used */ - - gint width, height; /* width and height attributes */ - gdouble xresolution; /* image x-res, in dpi */ - gdouble yresolution; /* image y-res, in dpi */ - GimpUnit unit; /* image unit */ - GimpImageBaseType base_type; /* base gimp_image type */ - - guchar *cmap; /* colormap--for indexed */ - gint num_cols; /* number of cols--for indexed */ - - gint dirty; /* dirty flag -- # of ops */ - gboolean undo_on; /* Is undo enabled? */ - - gint instance_count; /* number of instances */ - gint disp_count; /* number of displays */ - - GimpTattoo tattoo_state; /* the next unique tattoo to use*/ - - TileManager *shadow; /* shadow buffer tiles */ - - /* Projection attributes */ - gboolean construct_flag; /* flag for construction */ - GimpImageType proj_type; /* type of the projection image */ - gint proj_bytes; /* bpp in projection image */ - gint proj_level; /* projection level */ - TileManager *projection; /* The projection--layers & */ - /* channels */ - - GList *guides; /* guides */ - - /* Layer/Channel attributes */ - GimpContainer *layers; /* the list of layers */ - GimpContainer *channels; /* the list of masks */ - GSList *layer_stack; /* the layers in MRU order */ - - GimpLayer *active_layer; /* the active layer */ - GimpChannel *active_channel; /* the active channel */ - GimpLayer *floating_sel; /* the FS layer */ - GimpChannel *selection_mask; /* the selection mask channel */ - - GimpParasiteList *parasites; /* Plug-in parasite data */ - - PathList *paths; /* Paths data for this image */ - - gboolean visible[MAX_CHANNELS]; /* visible channels */ - gboolean active[MAX_CHANNELS]; /* active channels */ - - gboolean qmask_state; /* TRUE if qmask is on */ - GimpRGB qmask_color; /* rgba triplet of the color */ - - /* Old undo apparatus */ - GSList *undo_stack; /* stack for undo operations */ - GSList *redo_stack; /* stack for redo operations */ - gint undo_bytes; /* bytes in undo stack */ - gint undo_levels; /* levels in undo stack */ - gint group_count; /* nested undo groups */ - UndoType pushing_undo_group; /* undo group status flag */ - - /* New undo apparatus */ - GimpUndoStack *new_undo_stack; /* stack for undo operations */ - GimpUndoStack *new_redo_stack; /* stack for redo operations */ - - /* Composite preview */ - TempBuf *comp_preview; /* the composite preview */ - gboolean comp_preview_valid; /* preview valid-1/channel */ -}; - -struct _GimpImageClass -{ - GimpViewableClass parent_class; - - void (* mode_changed) (GimpImage *gimage); - void (* alpha_changed) (GimpImage *gimage); - void (* floating_selection_changed) (GimpImage *gimage); - void (* active_layer_changed) (GimpImage *gimage); - void (* active_channel_changed) (GimpImage *gimage); - void (* component_visibility_changed) (GimpImage *gimage, - ChannelType channel); - void (* component_active_changed) (GimpImage *gimage, - ChannelType channel); - void (* mask_changed) (GimpImage *gimage); - void (* resolution_changed) (GimpImage *gimage); - void (* unit_changed) (GimpImage *gimage); - void (* qmask_changed) (GimpImage *gimage); - void (* selection_control) (GimpImage *gimage, - GimpSelectionControl control); - - void (* clean) (GimpImage *gimage); - void (* dirty) (GimpImage *gimage); - void (* update) (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); - void (* update_guide) (GimpImage *gimage, - GimpGuide *guide); - void (* colormap_changed) (GimpImage *gimage, - gint color_index); - void (* undo_event) (GimpImage *gimage, - gint event); - - void (* undo) (GimpImage *gimage); - void (* redo) (GimpImage *gimage); -}; - - -/* function declarations */ - -GType gimp_image_get_type (void) G_GNUC_CONST; - -GimpImage * gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type); - -gint gimp_image_get_ID (GimpImage *gimage); -GimpImage * gimp_image_get_by_ID (Gimp *gimp, - gint id); - -void gimp_image_set_filename (GimpImage *gimage, - const gchar *filename); -void gimp_image_set_resolution (GimpImage *gimage, - gdouble xres, - gdouble yres); -void gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution); -void gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit); -GimpUnit gimp_image_get_unit (const GimpImage *gimage); - -void gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state); -gboolean gimp_image_get_qmask_state (const GimpImage *gimage); - -void gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc); -PlugInProcDef * gimp_image_get_save_proc (const GimpImage *gimage); - -gint gimp_image_get_width (const GimpImage *gimage); -gint gimp_image_get_height (const GimpImage *gimage); - -void gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y); -void gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data); -gboolean gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height); - -TileManager * gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); -void gimp_image_free_shadow (GimpImage *gimage); - -void gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - TileManager *src1_tiles, - gint x, - gint y); -void gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y); - -void gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg); -void gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg); -void gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src); -void gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type); - -GimpGuide * gimp_image_add_hguide (GimpImage *gimage); -GimpGuide * gimp_image_add_vguide (GimpImage *gimage); -void gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide); -GimpGuide * gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty); -gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1); - -GimpParasite * gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name); -gchar ** gimp_image_parasite_list (const GimpImage *gimage, - gint *count); -void gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite); -void gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite); - -GimpTattoo gimp_image_get_new_tattoo (GimpImage *gimage); -gboolean gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val); -GimpTattoo gimp_image_get_tattoo_state (GimpImage *gimage); - -void gimp_image_set_paths (GimpImage *gimage, - PathList *paths); -PathList * gimp_image_get_paths (const GimpImage *gimage); - -/* Temporary hack till colormap manipulation is encapsulated in functions. - * Call this whenever you modify an image's colormap. The col argument - * specifies which color has changed, or negative if there's a bigger change. - * Currently, use this also when the image's base type is changed to/from - * indexed. - */ -void gimp_image_colormap_changed (GimpImage *gimage, - gint col); - -void gimp_image_mode_changed (GimpImage *gimage); -void gimp_image_alpha_changed (GimpImage *gimage); -void gimp_image_floating_selection_changed (GimpImage *gimage); -void gimp_image_mask_changed (GimpImage *gimage); -void gimp_image_resolution_changed (GimpImage *gimage); -void gimp_image_unit_changed (GimpImage *gimage); -void gimp_image_qmask_changed (GimpImage *gimage); -void gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); -void gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control); - - -/* layer/channel functions */ - -GimpContainer * gimp_image_get_layers (const GimpImage *gimage); -GimpContainer * gimp_image_get_channels (const GimpImage *gimage); - -gint gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer); -gint gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel); -GimpLayer * gimp_image_get_active_layer (const GimpImage *gimage); -GimpChannel * gimp_image_get_active_channel (const GimpImage *gimage); -GimpLayer * gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name); -GimpChannel * gimp_image_get_mask (const GimpImage *gimage); - -void gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active); -gboolean gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type); -void gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active); - -void gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible); -gboolean gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type); - -gboolean gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs); -GimpLayer * gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer); -GimpChannel * gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel); -GimpChannel * gimp_image_unset_active_channel (GimpImage *gimage); -GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo); GimpLayer * gimp_image_merge_visible_layers (GimpImage *gimage, MergeType merge_type); GimpLayer * gimp_image_merge_down (GimpImage *gimage, @@ -389,52 +29,6 @@ GimpLayer * gimp_image_flatten (GimpImage *gimage); GimpLayer * gimp_image_merge_layers (GimpImage *gimage, GSList *merge_list, MergeType merge_type); -gboolean gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position); -void gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo); -gboolean gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position); -void gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel); - -void gimp_image_invalidate_layer_previews (GimpImage *gimage); -void gimp_image_invalidate_channel_previews (GimpImage *gimage); -/* Access functions */ - -gboolean gimp_image_is_empty (const GimpImage *gimage); -GimpDrawable * gimp_image_active_drawable (const GimpImage *gimage); - -GimpImageBaseType gimp_image_base_type (const GimpImage *gimage); -GimpImageType gimp_image_base_type_with_alpha (const GimpImage *gimage); - -const gchar * gimp_image_filename (const GimpImage *gimage); -gboolean gimp_image_undo_is_enabled (const GimpImage *gimage); -gboolean gimp_image_undo_enable (GimpImage *gimage); -gboolean gimp_image_undo_disable (GimpImage *gimage); -gboolean gimp_image_undo_freeze (GimpImage *gimage); -gboolean gimp_image_undo_thaw (GimpImage *gimage); -void gimp_image_undo_event (GimpImage *gimage, - gint event); -gint gimp_image_dirty (GimpImage *gimage); -gint gimp_image_clean (GimpImage *gimage); -void gimp_image_clean_all (GimpImage *gimage); -GimpLayer * gimp_image_floating_sel (const GimpImage *gimage); -guchar * gimp_image_cmap (const GimpImage *gimage); - -gboolean gimp_image_preview_valid (const GimpImage *gimage); - - -#endif /* __GIMP_IMAGE_H__ */ +#endif /* __GIMP_IMAGE_MERGE_H__ */ diff --git a/app/core/gimpimage-resize.c b/app/core/gimpimage-resize.c index cd786391e4..f4af42f685 100644 --- a/app/core/gimpimage-resize.c +++ b/app/core/gimpimage-resize.c @@ -18,805 +18,23 @@ #include "config.h" -#include - #include -#include "libgimpcolor/gimpcolor.h" -#include "libgimpmath/gimpmath.h" -#include "libgimpbase/gimpbase.h" - #include "core-types.h" -#include "base/pixel-region.h" -#include "base/temp-buf.h" -#include "base/tile-manager.h" - -#include "paint-funcs/paint-funcs.h" - #include "gimp.h" -#include "gimpcontext.h" -#include "gimpcoreconfig.h" +#include "gimpchannel.h" #include "gimpimage.h" -#include "gimpimage-colorhash.h" +#include "gimpimage-guides.h" #include "gimpimage-mask.h" #include "gimpimage-projection.h" -#include "gimpimage-undo.h" +#include "gimpimage-resize.h" #include "gimplayer.h" -#include "gimplayermask.h" #include "gimplist.h" -#include "gimpmarshal.h" -#include "gimpparasite.h" -#include "gimpparasitelist.h" -#include "gimpundostack.h" #include "floating_sel.h" -#include "path.h" #include "undo.h" -#include "libgimp/gimpintl.h" - - -#ifdef DEBUG -#define TRC(x) printf x -#else -#define TRC(x) -#endif - -#define GUIDE_EPSILON 5 - - -enum -{ - MODE_CHANGED, - ALPHA_CHANGED, - FLOATING_SELECTION_CHANGED, - ACTIVE_LAYER_CHANGED, - ACTIVE_CHANNEL_CHANGED, - COMPONENT_VISIBILITY_CHANGED, - COMPONENT_ACTIVE_CHANGED, - MASK_CHANGED, - RESOLUTION_CHANGED, - UNIT_CHANGED, - QMASK_CHANGED, - SELECTION_CONTROL, - - CLEAN, - DIRTY, - UPDATE, - UPDATE_GUIDE, - COLORMAP_CHANGED, - UNDO_EVENT, - LAST_SIGNAL -}; - - -/* local function prototypes */ - -static void gimp_image_class_init (GimpImageClass *klass); -static void gimp_image_init (GimpImage *gimage); - -static void gimp_image_dispose (GObject *object); -static void gimp_image_finalize (GObject *object); - -static void gimp_image_name_changed (GimpObject *object); -static void gimp_image_invalidate_preview (GimpViewable *viewable); -static void gimp_image_size_changed (GimpViewable *viewable); -static void gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol); -static TempBuf *gimp_image_get_preview (GimpViewable *gimage, - gint width, - gint height); -static TempBuf *gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height); -static void gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); - -/* - * Static variables - */ -static gint valid_combinations[][MAX_CHANNELS + 1] = -{ - /* RGB GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A }, - /* RGBA GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A }, - /* GRAY GIMAGE */ - { -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A, -1, -1 }, - /* GRAYA GIMAGE */ - { -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A, -1, -1 }, - /* INDEXED GIMAGE */ - { -1, COMBINE_INDEXED_INDEXED, COMBINE_INDEXED_INDEXED_A, -1, -1 }, - /* INDEXEDA GIMAGE */ - { -1, -1, COMBINE_INDEXED_A_INDEXED_A, -1, -1 }, -}; - -static guint gimp_image_signals[LAST_SIGNAL] = { 0 }; - -static GimpViewableClass *parent_class = NULL; - - -GType -gimp_image_get_type (void) -{ - static GType image_type = 0; - - if (! image_type) - { - static const GTypeInfo image_info = - { - sizeof (GimpImageClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gimp_image_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GimpImage), - 0, /* n_preallocs */ - (GInstanceInitFunc) gimp_image_init, - }; - - image_type = g_type_register_static (GIMP_TYPE_VIEWABLE, - "GimpImage", - &image_info, 0); - } - - return image_type; -} - -static void -gimp_image_class_init (GimpImageClass *klass) -{ - GObjectClass *object_class; - GimpObjectClass *gimp_object_class; - GimpViewableClass *viewable_class; - - object_class = G_OBJECT_CLASS (klass); - gimp_object_class = GIMP_OBJECT_CLASS (klass); - viewable_class = GIMP_VIEWABLE_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gimp_image_signals[MODE_CHANGED] = - g_signal_new ("mode_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mode_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ALPHA_CHANGED] = - g_signal_new ("alpha_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, alpha_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[FLOATING_SELECTION_CHANGED] = - g_signal_new ("floating_selection_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, floating_selection_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_LAYER_CHANGED] = - g_signal_new ("active_layer_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_layer_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_CHANNEL_CHANGED] = - g_signal_new ("active_channel_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_channel_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] = - g_signal_new ("component_visibility_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_visibility_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[COMPONENT_ACTIVE_CHANGED] = - g_signal_new ("component_active_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_active_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[MASK_CHANGED] = - g_signal_new ("mask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[RESOLUTION_CHANGED] = - g_signal_new ("resolution_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, resolution_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UNIT_CHANGED] = - g_signal_new ("unit_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, unit_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[QMASK_CHANGED] = - g_signal_new ("qmask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, qmask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[SELECTION_CONTROL] = - g_signal_new ("selection_control", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, selection_control), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[CLEAN] = - g_signal_new ("clean", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, clean), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[DIRTY] = - g_signal_new ("dirty", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, dirty), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UPDATE] = - g_signal_new ("update", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update), - NULL, NULL, - gimp_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT); - - gimp_image_signals[UPDATE_GUIDE] = - g_signal_new ("update_guide", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update_guide), - NULL, NULL, - gimp_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - gimp_image_signals[COLORMAP_CHANGED] = - g_signal_new ("colormap_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, colormap_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[UNDO_EVENT] = - g_signal_new ("undo_event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, undo_event), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - object_class->dispose = gimp_image_dispose; - object_class->finalize = gimp_image_finalize; - - gimp_object_class->name_changed = gimp_image_name_changed; - - viewable_class->invalidate_preview = gimp_image_invalidate_preview; - viewable_class->size_changed = gimp_image_size_changed; - viewable_class->get_preview = gimp_image_get_preview; - viewable_class->get_new_preview = gimp_image_get_new_preview; - - klass->mode_changed = NULL; - klass->alpha_changed = NULL; - klass->floating_selection_changed = NULL; - klass->active_layer_changed = NULL; - klass->active_channel_changed = NULL; - klass->component_visibility_changed = NULL; - klass->component_active_changed = NULL; - klass->mask_changed = NULL; - - klass->clean = NULL; - klass->dirty = NULL; - klass->update = NULL; - klass->update_guide = NULL; - klass->colormap_changed = gimp_image_real_colormap_changed; - klass->undo_event = NULL; - klass->undo = gimp_image_undo; - klass->redo = gimp_image_redo; - - gimp_image_color_hash_init (); -} - - -/* static functions */ - -static void -gimp_image_init (GimpImage *gimage) -{ - gimage->ID = 0; - - gimage->save_proc = NULL; - - gimage->width = 0; - gimage->height = 0; - gimage->xresolution = 1.0; - gimage->yresolution = 1.0; - gimage->unit = GIMP_UNIT_INCH; - gimage->base_type = RGB; - - gimage->cmap = NULL; - gimage->num_cols = 0; - - gimage->dirty = 1; - gimage->undo_on = TRUE; - - gimage->instance_count = 0; - gimage->disp_count = 0; - - gimage->tattoo_state = 0; - - gimage->shadow = NULL; - - gimage->construct_flag = FALSE; - gimage->proj_type = RGBA_GIMAGE; - gimage->projection = NULL; - - gimage->guides = NULL; - - gimage->layers = gimp_list_new (GIMP_TYPE_LAYER, - GIMP_CONTAINER_POLICY_STRONG); - gimage->channels = gimp_list_new (GIMP_TYPE_CHANNEL, - GIMP_CONTAINER_POLICY_STRONG); - gimage->layer_stack = NULL; - - gimage->active_layer = NULL; - gimage->active_channel = NULL; - gimage->floating_sel = NULL; - gimage->selection_mask = NULL; - - gimage->parasites = gimp_parasite_list_new (); - - gimage->paths = NULL; - - gimage->qmask_state = FALSE; - gimage->qmask_color.r = 1.0; - gimage->qmask_color.g = 0.0; - gimage->qmask_color.b = 0.0; - gimage->qmask_color.a = 0.5; - - gimage->undo_stack = NULL; - gimage->redo_stack = NULL; - gimage->undo_bytes = 0; - gimage->undo_levels = 0; - gimage->group_count = 0; - gimage->pushing_undo_group = UNDO_NULL; - - gimage->new_undo_stack = gimp_undo_stack_new (gimage); - gimage->new_redo_stack = gimp_undo_stack_new (gimage); - - gimage->comp_preview = NULL; - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_dispose (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - undo_free (gimage); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gimp_image_finalize (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - if (gimage->gimp && gimage->gimp->image_table) - { - g_hash_table_remove (gimage->gimp->image_table, - GINT_TO_POINTER (gimage->ID)); - gimage->gimp = NULL; - } - - if (gimage->projection) - gimp_image_projection_free (gimage); - - if (gimage->shadow) - gimp_image_free_shadow (gimage); - - if (gimage->cmap) - { - g_free (gimage->cmap); - gimage->cmap = NULL; - } - - if (gimage->layers) - { - g_object_unref (G_OBJECT (gimage->layers)); - gimage->layers = NULL; - } - if (gimage->channels) - { - g_object_unref (G_OBJECT (gimage->channels)); - gimage->channels = NULL; - } - if (gimage->layer_stack) - { - g_slist_free (gimage->layer_stack); - gimage->layer_stack = NULL; - } - - if (gimage->selection_mask) - { - g_object_unref (G_OBJECT (gimage->selection_mask)); - gimage->selection_mask = NULL; - } - - if (gimage->comp_preview) - { - temp_buf_free (gimage->comp_preview); - gimage->comp_preview = NULL; - } - - if (gimage->parasites) - { - g_object_unref (G_OBJECT (gimage->parasites)); - gimage->parasites = NULL; - } - - if (gimage->guides) - { - g_list_foreach (gimage->guides, (GFunc) g_free, NULL); - g_list_free (gimage->guides); - gimage->guides = NULL; - } - - if (gimage->new_undo_stack) - { - g_object_unref (G_OBJECT (gimage->new_undo_stack)); - gimage->new_undo_stack = NULL; - } - if (gimage->new_redo_stack) - { - g_object_unref (G_OBJECT (gimage->new_redo_stack)); - gimage->new_redo_stack = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gimp_image_name_changed (GimpObject *object) -{ - GimpImage *gimage; - const gchar *name; - - if (GIMP_OBJECT_CLASS (parent_class)->name_changed) - GIMP_OBJECT_CLASS (parent_class)->name_changed (object); - - gimage = GIMP_IMAGE (object); - name = gimp_object_get_name (object); - - if (! (name && strlen (name))) - { - g_free (object->name); - object->name = NULL; - } -} - -static void -gimp_image_invalidate_preview (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview) - GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_size_changed (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed) - GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimp_image_invalidate_layer_previews (gimage); - gimp_image_invalidate_channel_previews (gimage); -} - -static void -gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol) -{ - if (gimp_image_base_type (gimage) == INDEXED) - gimp_image_color_hash_invalidate (gimage, ncol); -} - -static void -gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - /* allocate the new projection */ - gimage->shadow = tile_manager_new (width, height, bpp); -} - - -/* function definitions */ - -GimpImage * -gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type) -{ - GimpImage *gimage; - gint i; - - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - gimage = GIMP_IMAGE (g_object_new (GIMP_TYPE_IMAGE, NULL)); - - gimage->gimp = gimp; - gimage->ID = gimp->next_image_ID++; - - g_hash_table_insert (gimp->image_table, - GINT_TO_POINTER (gimage->ID), - (gpointer) gimage); - - gimage->width = width; - gimage->height = height; - gimage->base_type = base_type; - - gimage->xresolution = gimp->config->default_xresolution; - gimage->yresolution = gimp->config->default_yresolution; - gimage->unit = gimp->config->default_units; - - switch (base_type) - { - case RGB: - case GRAY: - break; - case INDEXED: - /* always allocate 256 colors for the colormap */ - gimage->num_cols = 0; - gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE); - break; - default: - break; - } - - /* set all color channels visible and active */ - for (i = 0; i < MAX_CHANNELS; i++) - { - gimage->visible[i] = TRUE; - gimage->active[i] = TRUE; - } - - /* create the selection mask */ - gimage->selection_mask = gimp_channel_new_mask (gimage, - gimage->width, - gimage->height); - - - return gimage; -} - -gint -gimp_image_get_ID (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->ID; -} - -GimpImage * -gimp_image_get_by_ID (Gimp *gimp, - gint image_id) -{ - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - if (gimp->image_table == NULL) - return NULL; - - return (GimpImage *) g_hash_table_lookup (gimp->image_table, - GINT_TO_POINTER (image_id)); -} - -void -gimp_image_set_filename (GimpImage *gimage, - const gchar *filename) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_object_set_name (GIMP_OBJECT (gimage), filename); -} - -void -gimp_image_set_resolution (GimpImage *gimage, - gdouble xresolution, - gdouble yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* don't allow to set the resolution out of bounds */ - if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION || - yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION) - return; - - if ((ABS (gimage->xresolution - xresolution) >= 1e-5) || - (ABS (gimage->yresolution - yresolution) >= 1e-5)) - { - undo_push_resolution (gimage); - - gimage->xresolution = xresolution; - gimage->yresolution = yresolution; - - gimp_image_resolution_changed (gimage); - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - } -} - -void -gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (xresolution && yresolution); - - *xresolution = gimage->xresolution; - *yresolution = gimage->yresolution; -} - -void -gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->unit != unit) - { - undo_push_resolution (gimage); - - gimage->unit = unit; - - gimp_image_unit_changed (gimage); - } -} - -GimpUnit -gimp_image_get_unit (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_UNIT_INCH); - - return gimage->unit; -} - -void -gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (qmask_state != gimage->qmask_state) - { - gimage->qmask_state = qmask_state ? TRUE : FALSE; - - gimp_image_qmask_changed (gimage); - } -} - -gboolean -gimp_image_get_qmask_state (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->qmask_state; -} - -void -gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->save_proc = proc; -} - -PlugInProcDef * -gimp_image_get_save_proc (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->save_proc; -} - -gint -gimp_image_get_width (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->width; -} - -gint -gimp_image_get_height (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->height; -} void gimp_image_resize (GimpImage *gimage, @@ -920,2948 +138,3 @@ gimp_image_resize (GimpImage *gimage, gimp_unset_busy (gimage->gimp); } - -void -gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GSList *remove = NULL; - GSList *slist; - GimpGuide *guide; - gint old_width; - gint old_height; - gdouble img_scale_w = 1.0; - gdouble img_scale_h = 1.0; - gint num_channels; - gint num_layers; - gint progress_current = 1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - num_channels = gimage->channels->num_children; - num_layers = gimage->layers->num_children; - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_SCALE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - - old_width = gimage->width; - old_height = gimage->height; - gimage->width = new_width; - gimage->height = new_height; - img_scale_w = (gdouble) new_width / (gdouble) old_width; - img_scale_h = (gdouble) new_height / (gdouble) old_height; - - /* Scale all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_scale (channel, new_width, new_height); - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* Don't forget the selection mask! */ - /* if (channel_is_empty(gimage->selection_mask)) - gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0) - else - */ - - gimp_channel_scale (gimage->selection_mask, new_width, new_height); - gimage_mask_invalidate (gimage); - - /* Scale all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h)) - { - /* Since 0 < img_scale_w, img_scale_h, failure due to one or more - * vanishing scaled layer dimensions. Implicit delete implemented - * here. Upstream warning implemented in resize_check_layer_scaling() - * [resize.c line 1295], which offers the user the chance to bail out. - */ - remove = g_slist_append (remove, layer); - } - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* We defer removing layers lost to scaling until now so as not to mix - * the operations of iterating over and removal from gimage->layers. - */ - for (slist = remove; slist; slist = g_slist_next (slist)) - { - layer = slist->data; - gimp_image_remove_layer (gimage, layer); - } - g_slist_free (remove); - - /* Scale any Guides */ - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_height) / old_height; - break; - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_width) / old_width; - break; - default: - g_error("Unknown guide orientation II.\n"); - } - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -/** - * gimp_image_check_scaling: - * @gimage: A #GimpImage. - * @new_width: The new width. - * @new_height: The new height. - * - * Inventory the layer list in gimage and return #TRUE if, after - * scaling, they all retain positive x and y pixel dimensions. - * - * Return value: #TRUE if scaling the image will shrink none of it's - * layers completely away. - **/ -gboolean -gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height) -{ - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpLayer *layer; - - layer = (GimpLayer *) list->data; - - if (! gimp_layer_check_scaling (layer, new_width, new_height)) - return FALSE; - } - - return TRUE; -} - -TileManager * -gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (gimage->shadow && - ((width != tile_manager_width (gimage->shadow)) || - (height != tile_manager_height (gimage->shadow)) || - (bpp != tile_manager_bpp (gimage->shadow)))) - gimp_image_free_shadow (gimage); - else if (gimage->shadow) - return gimage->shadow; - - gimp_image_allocate_shadow (gimage, width, height, bpp); - - return gimage->shadow; -} - -void -gimp_image_free_shadow (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->shadow) - { - tile_manager_destroy (gimage->shadow); - gimage->shadow = NULL; - } -} - -void -gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - /* alternative to using drawable tiles as src1: */ - TileManager *src1_tiles, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR, maskPR; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations[gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - if (src1_tiles) - pixel_region_init (&src1PR, src1_tiles, - x1, y1, (x2 - x1), (y2 - y1), FALSE); - else - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - gint mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL, - opacity, mode, active, operation); - } - else - { - combine_regions (&src1PR, src2PR, &destPR, NULL, NULL, - opacity, mode, active, operation); - } -} - -/* Similar to gimp_image_apply_image but works in "replace" mode (i.e. - transparent pixels in src2 make the result transparent rather - than opaque. - - Takes an additional mask pixel region as well. -*/ -void -gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR; - PixelRegion mask2PR, tempPR; - guchar *temp_data; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations [gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - gimp_drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - int mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&mask2PR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - - tempPR.bytes = 1; - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.rowstride = tempPR.w * tempPR.bytes; - temp_data = g_malloc (tempPR.h * tempPR.rowstride); - tempPR.data = temp_data; - - copy_region (&mask2PR, &tempPR); - - /* apparently, region operations can mutate some PR data. */ - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); - - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, - opacity, active, operation); - - g_free (temp_data); - } - else - { - combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL, - opacity, active, operation); - } -} - -/* Get rid of these! A "foreground" is an UI concept.. */ - -void -gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg) -{ - GimpRGB color; - guchar pfg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (fg != NULL); - - gimp_context_get_foreground (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]); - - gimp_image_transform_color (gimage, drawable, pfg, fg, RGB); -} - -void -gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg) -{ - GimpRGB color; - guchar pbg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (bg != NULL); - - gimp_context_get_background (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]); - - gimp_image_transform_color (gimage, drawable, pbg, bg, RGB); -} - -void -gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - map_to_color (0, NULL, src, rgb); - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - map_to_color (1, NULL, src, rgb); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - map_to_color (2, gimage->cmap, src, rgb); - break; - } -} - -void -gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type) -{ - GimpImageType d_type; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - d_type = (drawable != NULL) ? gimp_drawable_type (drawable) : - gimp_image_base_type_with_alpha (gimage); - - switch (type) - { - case RGB: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Straight copy */ - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* NTSC conversion */ - *dest = INTENSITY (src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - } - break; - case GRAY: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Gray to RG&B */ - *dest++ = *src; - *dest++ = *src; - *dest++ = *src; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* Straight copy */ - *dest = *src; - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[GRAY_PIX], - src[GRAY_PIX], - src[GRAY_PIX]); - break; - } - break; - default: - break; - } -} - -GimpGuide * -gimp_image_add_hguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_HORIZONTAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -GimpGuide * -gimp_image_add_vguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_VERTICAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -void -gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_prepend (gimage->guides, guide); -} - -void -gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_remove (gimage->guides, guide); -} - -void -gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide) -{ - guide->position = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (guide->ref_count <= 0) - { - gimage->guides = g_list_remove (gimage->guides, guide); - g_free (guide); - } -} - -GimpGuide * -gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y) -{ - GList *list; - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return NULL; - } - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - if (ABS (guide->position - y) < GUIDE_EPSILON) - return guide; - break; - - case ORIENTATION_VERTICAL: - if (ABS (guide->position - x) < GUIDE_EPSILON) - return guide; - break; - - default: - break; - } - } - - return NULL; -} - -gboolean -gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty) -{ - GList *list; - GimpGuide *guide; - gint minxdist, minydist; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx != NULL, FALSE); - g_return_val_if_fail (ty != NULL, FALSE); - - *tx = x; - *ty = y; - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return FALSE; - } - - minxdist = G_MAXINT; - minydist = G_MAXINT; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - dist = ABS (guide->position - y); - - if (dist < MIN (GUIDE_EPSILON, minydist)) - { - minydist = dist; - *ty = guide->position; - snapped = TRUE; - } - break; - - case ORIENTATION_VERTICAL: - dist = ABS (guide->position - x); - - if (dist < MIN (GUIDE_EPSILON, minxdist)) - { - minxdist = dist; - *tx = guide->position; - snapped = TRUE; - } - break; - - default: - break; - } - } - - return snapped; -} - -gboolean -gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1) -{ - gint nx1, ny1; - gint nx2, ny2; - gboolean snap1, snap2; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx1 != NULL, FALSE); - g_return_val_if_fail (ty1 != NULL, FALSE); - - *tx1 = x1; - *ty1 = y1; - - snap1 = gimp_image_snap_point (gimage, x1, y1, &nx1, &ny1); - snap2 = gimp_image_snap_point (gimage, x2, y2, &nx2, &ny2); - - if (snap1 || snap2) - { - if (x1 != nx1) - *tx1 = nx1; - else if (x2 != nx2) - *tx1 = x1 + (nx2 - x2); - - if (y1 != ny1) - *ty1 = ny1; - else if (y2 != ny2) - *ty1 = y1 + (ny2 - y2); - } - - return snap1 || snap2; -} - -GimpParasite * -gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimp_parasite_list_find (gimage->parasites, name); -} - -static void -list_func (gchar *key, - GimpParasite *p, - gchar ***cur) -{ - *(*cur)++ = (gchar *) g_strdup (key); -} - -gchar ** -gimp_image_parasite_list (const GimpImage *gimage, - gint *count) -{ - gchar **list; - gchar **cur; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - *count = gimp_parasite_list_length (gimage->parasites); - cur = list = g_new (gchar*, *count); - - gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur); - - return list; -} - -void -gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL); - - /* only set the dirty bit manually if we can be saved and the new - parasite differs from the current one and we aren't undoable */ - if (gimp_parasite_is_undoable (parasite)) - undo_push_image_parasite (gimage, parasite); - - /* We used to push an cantundo on te stack here. This made the undo stack - unusable (NULL on the stack) and prevented people from undoing after a - save (since most save plug-ins attach an undoable comment parasite). - Now we simply attach the parasite without pushing an undo. That way it's - undoable but does not block the undo system. --Sven - */ - - gimp_parasite_list_add (gimage->parasites, parasite); - - if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT)) - { - gimp_parasite_shift_parent (parasite); - gimp_parasite_attach (gimage->gimp, parasite); - } -} - -void -gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite) -{ - GimpParasite *p; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (parasite != NULL); - - if (!(p = gimp_parasite_list_find (gimage->parasites, parasite))) - return; - - if (gimp_parasite_is_undoable (p)) - undo_push_image_parasite_remove (gimage, gimp_parasite_name (p)); - - gimp_parasite_list_remove (gimage->parasites, parasite); -} - -GimpTattoo -gimp_image_get_new_tattoo (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - gimage->tattoo_state++; - - if (gimage->tattoo_state <= 0) - g_warning ("%s: Tattoo state corrupted " - "(integer overflow).", G_GNUC_PRETTY_FUNCTION); - - return gimage->tattoo_state; -} - -GimpTattoo -gimp_image_get_tattoo_state (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->tattoo_state; -} - -gboolean -gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val) -{ - GList *list; - gboolean retval = TRUE; - GimpChannel *channel; - GimpTattoo maxval = 0; - Path *pptr = NULL; - PathList *plist; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ltattoo; - - ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data)); - if (ltattoo > maxval) - maxval = ltattoo; - if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in channel */ - } - - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Now check that the paths channel tattoos don't overlap */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ctattoo; - - channel = (GimpChannel *) list->data; - - ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)); - if (ctattoo > maxval) - maxval = ctattoo; - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ctattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Find the max tatto value in the paths */ - plist = gimage->paths; - - if (plist && plist->bz_paths) - { - GimpTattoo ptattoo; - GSList *pl; - - for (pl = plist->bz_paths; pl; pl = g_slist_next (pl)) - { - pptr = pl->data; - - ptattoo = path_get_tattoo (pptr); - - if (ptattoo > maxval) - maxval = ptattoo; - } - } - - if (val < maxval) - retval = FALSE; - /* Must check the state is valid */ - if (retval == TRUE) - gimage->tattoo_state = val; - - return retval; -} - -void -gimp_image_set_paths (GimpImage *gimage, - PathList *paths) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->paths = paths; -} - -PathList * -gimp_image_get_paths (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->paths; -} - -void -gimp_image_colormap_changed (GimpImage *gimage, - gint col) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (col < gimage->num_cols); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[COLORMAP_CHANGED], 0, - col); -} - -void -gimp_image_mode_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MODE_CHANGED], 0); -} - -void -gimp_image_mask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MASK_CHANGED], 0); -} - -void -gimp_image_resolution_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[RESOLUTION_CHANGED], 0); -} - -void -gimp_image_unit_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNIT_CHANGED], 0); -} - -void -gimp_image_qmask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[QMASK_CHANGED], 0); -} - -void -gimp_image_alpha_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED], 0); -} - -void -gimp_image_floating_selection_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[FLOATING_SELECTION_CHANGED], 0); -} - -void -gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE], 0, - x, y, width, height); -} - -void -gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (guide != NULL); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE_GUIDE], 0, - guide); -} - -void -gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[SELECTION_CONTROL], 0, - control); -} - -void -gimp_image_invalidate_layer_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->layers, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -void -gimp_image_invalidate_channel_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->channels, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -GimpContainer * -gimp_image_get_layers (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->layers; -} - -GimpContainer * -gimp_image_get_channels (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->channels; -} - -gint -gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_LAYER (layer), -1); - - return gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); -} - -gint -gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1); - - return gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); -} - -GimpLayer * -gimp_image_get_active_layer (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_layer; -} - -GimpChannel * -gimp_image_get_active_channel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_channel; -} - -GimpLayer * -gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo) - return layer; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name)) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_mask (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->selection_mask; -} - -void -gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && active != gimage->active[pixel]) - { - gimage->active[pixel] = active ? TRUE : FALSE; - - /* If there is an active channel and we mess with the components, - * the active channel gets unset... - */ - gimp_image_unset_active_channel (gimage); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, - type); - } -} - -gboolean -gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->active[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->active[ALPHA_PIX]; break; - case GRAY: return gimage->active[ALPHA_G_PIX]; break; - case INDEXED: return gimage->active[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -void -gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active) -{ - GimpLayer *layer; - gint i; - - /* first, blindly copy the gimage active channels */ - for (i = 0; i < MAX_CHANNELS; i++) - active[i] = gimage->active[i]; - - /* If the drawable is a channel (a saved selection, etc.) - * make sure that the alpha channel is not valid - */ - if (GIMP_IS_CHANNEL (drawable)) - { - active[ALPHA_G_PIX] = 0; /* no alpha values in channels */ - } - else - { - /* otherwise, check whether preserve transparency is - * enabled in the layer and if the layer has alpha - */ - if (GIMP_IS_LAYER (drawable)) - { - layer = GIMP_LAYER (drawable); - if (gimp_layer_has_alpha (layer) && layer->preserve_trans) - active[gimp_drawable_bytes (drawable) - 1] = 0; - } - } -} - -void -gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && visible != gimage->visible[pixel]) - { - gimage->visible[pixel] = visible ? TRUE : FALSE; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED], 0, - type); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - } -} - -gboolean -gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->visible[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->visible[ALPHA_PIX]; break; - case GRAY: return gimage->visible[ALPHA_G_PIX]; break; - case INDEXED: return gimage->visible[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -gboolean -gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs) -{ - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (segs != NULL, FALSE); - g_return_val_if_fail (n_segs != NULL, FALSE); - - /* The second boundary corresponds to the active layer's - * perimeter... - */ - layer = gimp_image_get_active_layer (gimage); - - if (layer) - { - *segs = gimp_layer_boundary (layer, n_segs); - return TRUE; - } - else - { - *segs = NULL; - *n_segs = 0; - return FALSE; - } -} - -GimpLayer * -gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); - - /* First, find the layer in the gimage - * If it isn't valid, find the first layer that is - */ - if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0); - - if (layer) - { - /* Configure the layer stack to reflect this change */ - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer); - - /* invalidate the selection boundary because of a layer modification */ - gimp_layer_invalidate_boundary (layer); - } - - if (layer != gimage->active_layer) - { - gimage->active_layer = layer; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - - if (gimage->active_channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - } - } - - /* return the layer */ - return layer; -} - -GimpChannel * -gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* Not if there is a floating selection */ - if (gimp_image_floating_sel (gimage)) - return NULL; - - /* First, find the channel - * If it doesn't exist, find the first channel that does - */ - if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0); - - if (channel != gimage->active_channel) - { - gimage->active_channel = channel; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->active_layer) - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* return the channel */ - return channel; -} - -GimpChannel * -gimp_image_unset_active_channel (GimpImage *gimage) -{ - GimpChannel *channel; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - channel = gimp_image_get_active_channel (gimage); - - if (channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->layer_stack) - { - GimpLayer *layer; - - layer = (GimpLayer *) gimage->layer_stack->data; - - gimp_image_set_active_layer (gimage, layer); - } - } - - return channel; -} - -GimpLayer * -gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_layer_pick_correlate (layer, x, y)) - return layer; - } - - return NULL; -} - -gboolean -gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the top layer already? */ - if (curpos == 0) - { - g_message (_("Layer cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE); -} - -gboolean -gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the bottom layer already? */ - length = gimp_container_num_children (gimage->layers); - if (curpos >= length - 1) - { - g_message (_("Layer cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE); -} - -gboolean -gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - if (curpos == 0) - { - g_message (_("Layer is already on top.")); - return FALSE; - } - - if (! gimp_layer_has_alpha (layer)) - { - g_message (_("Cannot raise a layer without alpha.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, 0, TRUE); -} - -gboolean -gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - length = gimp_container_num_children (gimage->layers); - - if (curpos >= length - 1) - { - g_message (_("Layer is already on the bottom.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, length - 1, TRUE); -} - -gboolean -gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo) -{ - gint off_x, off_y; - gint index; - gint num_layers; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - index = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - if (index < 0) - return FALSE; - - num_layers = gimp_container_num_children (gimage->layers); - - if (new_index < 0) - new_index = 0; - - if (new_index >= num_layers) - new_index = num_layers - 1; - - if (new_index == index) - return TRUE; - - /* check if we want to move it below a bottom layer without alpha */ - if (new_index == num_layers - 1) - { - GimpLayer *tmp; - - tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, - num_layers - 1); - - if (new_index == num_layers - 1 && - ! gimp_layer_has_alpha (tmp)) - { - g_message (_("Layer \"%s\" has no alpha.\nLayer was placed above it."), - GIMP_OBJECT (tmp)->name); - new_index--; - } - } - - if (push_undo) - undo_push_layer_reposition (gimage, layer); - - gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - gimp_image_update (gimage, - off_x, off_y, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); - - return TRUE; -} - -GimpLayer * -gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type) -{ - GList *list; - GSList *merge_list = NULL; - gboolean had_floating_sel = FALSE; - GimpLayer *layer = NULL; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - { - floating_sel_anchor (gimage->floating_sel); - had_floating_sel = TRUE; - } - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - if (merge_list && merge_list->next) - { - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_slist_free (merge_list); - - /* If there was a floating selection, we have done something. - No need to warn the user. Return the active layer instead */ - if (had_floating_sel) - return layer; - else - g_message (_("Not enough visible layers for a merge.\n" - "There must be at least two.")); - - return NULL; - } -} - -GimpLayer * -gimp_image_flatten (GimpImage *gimage) -{ - GList *list; - GSList *merge_list = NULL; - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - gimp_set_busy (gimage->gimp); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - floating_sel_anchor (gimage->floating_sel); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - layer = gimp_image_merge_layers (gimage, merge_list, FLATTEN_IMAGE); - g_slist_free (merge_list); - - gimp_image_alpha_changed (gimage); - - gimp_unset_busy (gimage->gimp); - - return layer; -} - -GimpLayer * -gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type) -{ - GimpLayer *layer; - GList *list; - GList *layer_list; - GSList *merge_list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list, layer_list = NULL; - list && !layer_list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (layer == current_layer) - break; - } - - for (layer_list = g_list_next (list), merge_list = NULL; - layer_list && !merge_list; - layer_list = g_list_next (layer_list)) - { - layer = (GimpLayer *) layer_list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (NULL, layer); - } - - if (merge_list) - { - merge_list = g_slist_prepend (merge_list, current_layer); - - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_message (_("There are not enough visible layers for a merge down.")); - return NULL; - } -} - -GimpLayer * -gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type) -{ - GList *list; - GSList *reverse_list = NULL; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - GimpLayer *merge_layer; - GimpLayer *layer; - GimpLayer *bottom_layer; - LayerModeEffects bottom_mode; - guchar bg[4] = {0, 0, 0, 0}; - GimpImageType type; - gint count; - gint x1, y1, x2, y2; - gint x3, y3, x4, y4; - gint operation; - gint position; - gint active[MAX_CHANNELS] = {1, 1, 1, 1}; - gint off_x, off_y; - gchar *name; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - layer = NULL; - type = RGBA_GIMAGE; - x1 = y1 = 0; - x2 = y2 = 0; - bottom_layer = NULL; - bottom_mode = NORMAL_MODE; - - /* Get the layer extents */ - count = 0; - while (merge_list) - { - layer = (GimpLayer *) merge_list->data; - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - switch (merge_type) - { - case EXPAND_AS_NECESSARY: - case CLIP_TO_IMAGE: - if (!count) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - else - { - if (off_x < x1) - x1 = off_x; - if (off_y < y1) - y1 = off_y; - if ((off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) > x2) - x2 = (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))); - if ((off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))) > y2) - y2 = (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))); - } - if (merge_type == CLIP_TO_IMAGE) - { - x1 = CLAMP (x1, 0, gimage->width); - y1 = CLAMP (y1, 0, gimage->height); - x2 = CLAMP (x2, 0, gimage->width); - y2 = CLAMP (y2, 0, gimage->height); - } - break; - - case CLIP_TO_BOTTOM_LAYER: - if (merge_list->next == NULL) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - break; - - case FLATTEN_IMAGE: - if (merge_list->next == NULL) - { - x1 = 0; - y1 = 0; - x2 = gimage->width; - y2 = gimage->height; - } - 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 */ - undo_push_group_start (gimage, LAYER_MERGE_UNDO); - - name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); - - if (merge_type == FLATTEN_IMAGE || - gimp_drawable_type (GIMP_DRAWABLE (layer)) == INDEXED_GIMAGE) - { - switch (gimp_image_base_type (gimage)) - { - case RGB: type = RGB_GIMAGE; break; - case GRAY: type = GRAY_GIMAGE; break; - case INDEXED: type = INDEXED_GIMAGE; break; - } - - merge_layer = gimp_layer_new (gimage, (x2 - x1), (y2 - y1), - type, - gimp_object_get_name (GIMP_OBJECT (layer)), - OPAQUE_OPACITY, NORMAL_MODE); - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* get the background for compositing */ - gimp_image_get_background (gimage, GIMP_DRAWABLE (merge_layer), bg); - - /* init the pixel region */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - gimage->width, gimage->height, - 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 (gimage, (x2 - x1), (y2 - y1), - gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), - "merged layer", - OPAQUE_OPACITY, NORMAL_MODE); - - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* Set the layer to transparent */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - (x2 - x1), (y2 - y1), - TRUE); - - /* set the region to 0's */ - color_region (&src1PR, bg); - - /* 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 = (GimpLayer *) reverse_list->data; - position = - gimp_container_num_children (gimage->layers) - - gimp_container_get_child_index (gimage->layers, GIMP_OBJECT (layer)); - - /* set the mode of the bottom layer to normal so that the contents - * aren't lost when merging with the all-alpha merge_layer - * Keep a pointer to it so that we can set the mode right after it's - * been merged so that undo works correctly. - */ - bottom_layer = layer; - bottom_mode = bottom_layer->mode; - - /* 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. - */ - if (bottom_layer->mode != DISSOLVE_MODE) - gimp_layer_set_mode (bottom_layer, NORMAL_MODE); - } - - /* Copy the tattoo and parasites of the bottom layer to the new layer */ - gimp_drawable_set_tattoo (GIMP_DRAWABLE (merge_layer), - gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer))); - GIMP_DRAWABLE (merge_layer)->parasites = - gimp_parasite_list_copy (GIMP_DRAWABLE (layer)->parasites); - - while (reverse_list) - { - layer = (GimpLayer *) reverse_list->data; - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = - valid_combinations[gimp_drawable_type (GIMP_DRAWABLE (merge_layer))][gimp_drawable_bytes (GIMP_DRAWABLE (layer))]; - - if (operation == -1) - { - g_warning ("%s: attempting to merge incompatible layers.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - x3 = CLAMP (off_x, x1, x2); - y3 = CLAMP (off_y, y1, y2); - x4 = CLAMP (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)), x1, x2); - y4 = CLAMP (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)), y1, y2); - - /* configure the pixel regions */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), - TRUE); - pixel_region_init (&src2PR, - gimp_drawable_data (GIMP_DRAWABLE (layer)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - - if (layer->mask && layer->mask->apply_mask) - { - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (layer->mask)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - mask = &maskPR; - } - else - { - mask = NULL; - } - - combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, - layer->opacity, layer->mode, active, operation); - - gimp_image_remove_layer (gimage, layer); - reverse_list = g_slist_next (reverse_list); - } - - /* Save old mode in undo */ - if (bottom_layer) - gimp_layer_set_mode (bottom_layer, bottom_mode); - - g_slist_free (reverse_list); - - /* if the type is flatten, remove all the remaining layers */ - if (merge_type == FLATTEN_IMAGE) - { - list = GIMP_LIST (gimage->layers)->list; - while (list) - { - layer = (GimpLayer *) list->data; - - list = g_list_next (list); - gimp_image_remove_layer (gimage, layer); - } - - gimp_image_add_layer (gimage, merge_layer, position); - } - else - { - /* Add the layer to the gimage */ - gimp_image_add_layer (gimage, merge_layer, - gimp_container_num_children (gimage->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_set_name (GIMP_OBJECT (merge_layer), name); - g_free (name); - - /* End the merge undo group */ - undo_push_group_end (gimage); - - gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE); - - gimp_drawable_update (GIMP_DRAWABLE (merge_layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (merge_layer)), - gimp_drawable_height (GIMP_DRAWABLE (merge_layer))); - - return merge_layer; -} - -gboolean -gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position) -{ - LayerUndo *lu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - if (GIMP_DRAWABLE (layer)->gimage != NULL && - GIMP_DRAWABLE (layer)->gimage != gimage) - { - g_warning ("%s: attempting to add layer to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - { - g_warning ("%s: trying to add layer to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Prepare a layer undo and push it */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = 0; - lu->prev_layer = gimp_image_get_active_layer (gimage); - undo_push_layer (gimage, LAYER_ADD_UNDO, lu); - - /* If the layer is a floating selection, set the ID */ - if (gimp_layer_is_floating_sel (layer)) - gimage->floating_sel = layer; - - /* let the layer know about the gimage */ - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage); - - /* If the layer has a mask, set the mask's gimage */ - if (layer->mask) - { - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage); - } - - /* add the layer to the list at the specified position */ - if (position == -1) - { - GimpLayer *active_layer; - - active_layer = gimp_image_get_active_layer (gimage); - - if (active_layer) - { - position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (active_layer)); - } - else - { - position = 0; - } - } - - /* If there is a floating selection (and this isn't it!), - * make sure the insert position is greater than 0 - */ - if (position == 0 && - gimp_image_floating_sel (gimage) && - (gimage->floating_sel != layer)) - { - position = 1; - } - - gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position); - g_object_unref (G_OBJECT (layer)); - - /* notify the layers dialog of the currently active layer */ - gimp_image_set_active_layer (gimage, layer); - - /* update the new layer's area */ - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - return TRUE; -} - -void -gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer) -{ - LayerUndo *lu; - gint x, y, w, h; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_LAYER (layer)); - - g_return_if_fail (gimp_container_have (gimage->layers, - GIMP_OBJECT (layer))); - - /* Push a layer undo */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - lu->prev_layer = layer; - - undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu); - - g_object_ref (G_OBJECT (layer)); - - gimp_container_remove (gimage->layers, GIMP_OBJECT (layer)); - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - - /* If this was the floating selection, reset the fs pointer */ - if (gimage->floating_sel == layer) - { - gimage->floating_sel = NULL; - - floating_sel_reset (layer); - } - - if (layer == gimp_image_get_active_layer (gimage)) - { - if (gimage->layer_stack) - { - gimp_image_set_active_layer (gimage, gimage->layer_stack->data); - } - else - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* Send out REMOVED signal from layer */ - gimp_drawable_removed (GIMP_DRAWABLE (layer)); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &x, &y); - w = gimp_drawable_width (GIMP_DRAWABLE (layer)); - h = gimp_drawable_height (GIMP_DRAWABLE (layer)); - - g_object_unref (G_OBJECT (layer)); - - gimp_image_update (gimage, x, y, w, h); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -gboolean -gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == 0) - { - g_message (_("Channel cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index - 1, TRUE); -} - -gboolean -gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == gimp_container_num_children (gimage->channels) - 1) - { - g_message (_("Channel cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index + 1, TRUE); -} - -gboolean -gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo /* FIXME unused */) -{ - gint index; - gint num_channels; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index < 0) - return FALSE; - - num_channels = gimp_container_num_children (gimage->channels); - - new_index = CLAMP (new_index, 0, num_channels - 1); - - if (new_index == index) - return TRUE; - - gimp_container_reorder (gimage->channels, - GIMP_OBJECT (channel), new_index); - - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -gboolean -gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position) -{ - ChannelUndo *cu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - if (GIMP_DRAWABLE (channel)->gimage != NULL && - GIMP_DRAWABLE (channel)->gimage != gimage) - { - g_warning ("%s: attempting to add channel to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - { - g_warning ("%s: trying to add channel to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Push a channel undo */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = 0; - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu); - - /* add the channel to the list */ - gimp_container_add (gimage->channels, GIMP_OBJECT (channel)); - g_object_unref (G_OBJECT (channel)); - - /* notify this gimage of the currently active channel */ - gimp_image_set_active_channel (gimage, channel); - - /* if channel is visible, update the image */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -void -gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel) -{ - ChannelUndo *cu; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_CHANNEL (channel)); - - g_return_if_fail (gimp_container_have (gimage->channels, - GIMP_OBJECT (channel))); - - /* Prepare a channel undo--push it below */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu); - - g_object_ref (G_OBJECT (channel)); - - gimp_container_remove (gimage->channels, GIMP_OBJECT (channel)); - - /* Send out REMOVED signal from channel */ - gimp_drawable_removed (GIMP_DRAWABLE (channel)); - - if (channel == gimp_image_get_active_channel (gimage)) - { - if (gimp_container_num_children (gimage->channels) > 0) - { - gimp_image_set_active_channel - (gimage, - GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels, - 0))); - } - else - { - gimp_image_unset_active_channel (gimage); - } - } - - g_object_unref (G_OBJECT (channel)); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -/************************************************************/ -/* Access functions */ -/************************************************************/ - -gboolean -gimp_image_is_empty (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE); - - return (gimp_container_num_children (gimage->layers) == 0); -} - -GimpDrawable * -gimp_image_active_drawable (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* If there is an active channel (a saved selection, etc.), - * we ignore the active layer - */ - if (gimage->active_channel) - { - return GIMP_DRAWABLE (gimage->active_channel); - } - else if (gimage->active_layer) - { - GimpLayer *layer; - - layer = gimage->active_layer; - - if (layer->mask && layer->mask->edit_mask) - return GIMP_DRAWABLE (layer->mask); - else - return GIMP_DRAWABLE (layer); - } - - return NULL; -} - -GimpImageBaseType -gimp_image_base_type (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->base_type; -} - -GimpImageType -gimp_image_base_type_with_alpha (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - switch (gimage->base_type) - { - case RGB: - return RGBA_GIMAGE; - case GRAY: - return GRAYA_GIMAGE; - case INDEXED: - return INDEXEDA_GIMAGE; - } - return RGB_GIMAGE; -} - -const gchar * -gimp_image_filename (const GimpImage *gimage) -{ - const gchar *filename; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - filename = gimp_object_get_name (GIMP_OBJECT (gimage)); - - return filename ? filename : _("Untitled"); -} - -gboolean -gimp_image_undo_is_enabled (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->undo_on; -} - -gboolean -gimp_image_undo_freeze (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = FALSE; - - return TRUE; -} - -gboolean -gimp_image_undo_thaw (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = TRUE; - - return TRUE; -} - -gboolean -gimp_image_undo_disable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimp_image_undo_freeze (gimage); -} - -gboolean -gimp_image_undo_enable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - /* Free all undo steps as they are now invalidated */ - undo_free (gimage); - - return gimp_image_undo_thaw (gimage); -} - -void -gimp_image_undo_event (GimpImage *gimage, - gint event) -{ - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], 0, - event); -} - - -/* NOTE about the gimage->dirty counter: - * If 0, then the image is clean (ie, copy on disk is the same as the one - * in memory). - * If positive, then that's the number of dirtying operations done - * on the image since the last save. - * If negative, then user has hit undo and gone back in time prior - * to the saved copy. Hitting redo will eventually come back to - * the saved copy. - * - * The image is dirty (ie, needs saving) if counter is non-zero. - * - * If the counter is around 10000, this is due to undo-ing back - * before a saved version, then mutating the image (thus destroying - * the redo stack). Once this has happened, it's impossible to get - * the image back to the state on disk, since the redo info has been - * freed. See undo.c for the gorey details. - */ - - -/* - * NEVER CALL gimp_image_dirty() directly! - * - * If your code has just dirtied the image, push an undo instead. - * Failing that, push the trivial undo which tells the user the - * command is not undoable: undo_push_cantundo() (But really, it would - * be best to push a proper undo). If you just dirty the image - * without pushing an undo then the dirty count is increased, but - * popping that many undo actions won't lead to a clean image. - */ - -gint -gimp_image_dirty (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty++; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[DIRTY], 0); - - TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty)); - - return gimage->dirty; -} - -gint -gimp_image_clean (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty--; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); - - TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty)); - - return gimage->dirty; -} - -void -gimp_image_clean_all (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->dirty = 0; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); -} - -GimpLayer * -gimp_image_floating_sel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - if (gimage->floating_sel == NULL) - return NULL; - else - return gimage->floating_sel; -} - -guchar * -gimp_image_cmap (const GimpImage *gimage) -{ - return gimp_drawable_cmap (gimp_image_active_drawable (gimage)); -} - -static TempBuf * -gimp_image_get_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (viewable); - - if (gimage->comp_preview_valid && - gimage->comp_preview->width == width && - gimage->comp_preview->height == height) - { - /* The easy way */ - return gimage->comp_preview; - } - else - { - /* The hard way */ - if (gimage->comp_preview) - temp_buf_free (gimage->comp_preview); - - /* Actually construct the composite preview from the layer previews! - * This might seem ridiculous, but it's actually the best way, given - * a number of unsavory alternatives. - */ - gimage->comp_preview = gimp_image_get_new_preview (viewable, - width, height); - - gimage->comp_preview_valid = TRUE; - - return gimage->comp_preview; - } -} - -static TempBuf * -gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - GimpLayer *layer; - GimpLayer *floating_sel; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - TempBuf *comp; - TempBuf *layer_buf; - TempBuf *mask_buf; - GList *list; - GSList *reverse_list = NULL; - gdouble ratio; - gint x, y, w, h; - gint x1, y1, x2, y2; - gint bytes; - gboolean construct_flag; - gint visible[MAX_CHANNELS] = { 1, 1, 1, 1 }; - gint off_x, off_y; - - gimage = GIMP_IMAGE (viewable); - - ratio = (gdouble) width / (gdouble) gimage->width; - - switch (gimp_image_base_type (gimage)) - { - case RGB: - case INDEXED: - bytes = 4; - break; - case GRAY: - bytes = 2; - break; - default: - bytes = 0; - break; - } - - /* The construction buffer */ - comp = temp_buf_new (width, height, bytes, 0, 0, NULL); - temp_buf_data_clear (comp); - - floating_sel = NULL; - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - /* only add layers that are visible to the list */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - { - /* floating selections are added right above the layer - * they are attached to - */ - if (gimp_layer_is_floating_sel (layer)) - { - floating_sel = layer; - } - else - { - if (floating_sel && - floating_sel->fs.drawable == GIMP_DRAWABLE (layer)) - { - reverse_list = g_slist_prepend (reverse_list, floating_sel); - } - - reverse_list = g_slist_prepend (reverse_list, layer); - } - } - } - - construct_flag = FALSE; - - for (; reverse_list; reverse_list = g_slist_next (reverse_list)) - { - layer = (GimpLayer *) reverse_list->data; - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - x = (gint) RINT (ratio * off_x); - y = (gint) RINT (ratio * off_y); - w = (gint) RINT (ratio * gimp_drawable_width (GIMP_DRAWABLE (layer))); - h = (gint) RINT (ratio * gimp_drawable_height (GIMP_DRAWABLE (layer))); - - if (w < 1 || h < 1) - continue; - - x1 = CLAMP (x, 0, width); - y1 = CLAMP (y, 0, height); - x2 = CLAMP (x + w, 0, width); - y2 = CLAMP (y + h, 0, height); - - src1PR.bytes = comp->bytes; - src1PR.x = x1; - src1PR.y = y1; - src1PR.w = (x2 - x1); - src1PR.h = (y2 - y1); - src1PR.rowstride = comp->width * src1PR.bytes; - src1PR.data = (temp_buf_data (comp) + - y1 * src1PR.rowstride + x1 * src1PR.bytes); - - layer_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h); - src2PR.bytes = layer_buf->bytes; - src2PR.w = src1PR.w; - src2PR.h = src1PR.h; - src2PR.x = src1PR.x; - src2PR.y = src1PR.y; - src2PR.rowstride = layer_buf->width * src2PR.bytes; - src2PR.data = (temp_buf_data (layer_buf) + - (y1 - y) * src2PR.rowstride + - (x1 - x) * src2PR.bytes); - - if (layer->mask && layer->mask->apply_mask) - { - mask_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer->mask), - w, h); - maskPR.bytes = mask_buf->bytes; - maskPR.rowstride = mask_buf->width; - maskPR.data = (mask_buf_data (mask_buf) + - (y1 - y) * maskPR.rowstride + - (x1 - x) * maskPR.bytes); - mask = &maskPR; - } - else - { - mask = NULL; - } - - /* Based on the type of the layer, project the layer onto the - * composite preview... - * Indexed images are actually already converted to RGB and RGBA, - * so just project them as if they were type "intensity" - * Send in all TRUE for visible since that info doesn't matter - * for previews - */ - switch (gimp_drawable_type (GIMP_DRAWABLE (layer))) - { - case RGB_GIMAGE: case GRAY_GIMAGE: case INDEXED_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN); - break; - - case RGBA_GIMAGE: case GRAYA_GIMAGE: case INDEXEDA_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY_ALPHA); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN_A); - break; - - default: - break; - } - - construct_flag = TRUE; - } - - g_slist_free (reverse_list); - - return comp; -} diff --git a/app/core/gimpimage-resize.h b/app/core/gimpimage-resize.h index be0b5eea83..eb132deda9 100644 --- a/app/core/gimpimage-resize.h +++ b/app/core/gimpimage-resize.h @@ -16,425 +16,15 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __GIMP_IMAGE_H__ -#define __GIMP_IMAGE_H__ +#ifndef __GIMP_IMAGE_RESIZE_H__ +#define __GIMP_IMAGE_RESIZE_H__ -#include "gimpviewable.h" +void gimp_image_resize (GimpImage *gimage, + gint new_width, + gint new_height, + gint offset_x, + gint offset_y); -#define COLORMAP_SIZE 768 - -#define GIMP_IMAGE_TYPE_HAS_ALPHA(t) ((t) == RGBA_GIMAGE || \ - (t) == GRAYA_GIMAGE || \ - (t) == INDEXEDA_GIMAGE) - - -struct _GimpGuide -{ - gint ref_count; - gint position; - InternalOrientationType orientation; - guint32 guide_ID; -}; - - -#define GIMP_TYPE_IMAGE (gimp_image_get_type ()) -#define GIMP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_IMAGE, GimpImage)) -#define GIMP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_IMAGE, GimpImageClass)) -#define GIMP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_IMAGE)) -#define GIMP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_IMAGE)) -#define GIMP_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_IMAGE, GimpImageClass)) - - -typedef struct _GimpImageClass GimpImageClass; - -struct _GimpImage -{ - GimpViewable parent_instance; - - Gimp *gimp; /* the GIMP the image belongs to*/ - - gint ID; /* provides a unique ID */ - - PlugInProcDef *save_proc; /* last PDB save proc used */ - - gint width, height; /* width and height attributes */ - gdouble xresolution; /* image x-res, in dpi */ - gdouble yresolution; /* image y-res, in dpi */ - GimpUnit unit; /* image unit */ - GimpImageBaseType base_type; /* base gimp_image type */ - - guchar *cmap; /* colormap--for indexed */ - gint num_cols; /* number of cols--for indexed */ - - gint dirty; /* dirty flag -- # of ops */ - gboolean undo_on; /* Is undo enabled? */ - - gint instance_count; /* number of instances */ - gint disp_count; /* number of displays */ - - GimpTattoo tattoo_state; /* the next unique tattoo to use*/ - - TileManager *shadow; /* shadow buffer tiles */ - - /* Projection attributes */ - gboolean construct_flag; /* flag for construction */ - GimpImageType proj_type; /* type of the projection image */ - gint proj_bytes; /* bpp in projection image */ - gint proj_level; /* projection level */ - TileManager *projection; /* The projection--layers & */ - /* channels */ - - GList *guides; /* guides */ - - /* Layer/Channel attributes */ - GimpContainer *layers; /* the list of layers */ - GimpContainer *channels; /* the list of masks */ - GSList *layer_stack; /* the layers in MRU order */ - - GimpLayer *active_layer; /* the active layer */ - GimpChannel *active_channel; /* the active channel */ - GimpLayer *floating_sel; /* the FS layer */ - GimpChannel *selection_mask; /* the selection mask channel */ - - GimpParasiteList *parasites; /* Plug-in parasite data */ - - PathList *paths; /* Paths data for this image */ - - gboolean visible[MAX_CHANNELS]; /* visible channels */ - gboolean active[MAX_CHANNELS]; /* active channels */ - - gboolean qmask_state; /* TRUE if qmask is on */ - GimpRGB qmask_color; /* rgba triplet of the color */ - - /* Old undo apparatus */ - GSList *undo_stack; /* stack for undo operations */ - GSList *redo_stack; /* stack for redo operations */ - gint undo_bytes; /* bytes in undo stack */ - gint undo_levels; /* levels in undo stack */ - gint group_count; /* nested undo groups */ - UndoType pushing_undo_group; /* undo group status flag */ - - /* New undo apparatus */ - GimpUndoStack *new_undo_stack; /* stack for undo operations */ - GimpUndoStack *new_redo_stack; /* stack for redo operations */ - - /* Composite preview */ - TempBuf *comp_preview; /* the composite preview */ - gboolean comp_preview_valid; /* preview valid-1/channel */ -}; - -struct _GimpImageClass -{ - GimpViewableClass parent_class; - - void (* mode_changed) (GimpImage *gimage); - void (* alpha_changed) (GimpImage *gimage); - void (* floating_selection_changed) (GimpImage *gimage); - void (* active_layer_changed) (GimpImage *gimage); - void (* active_channel_changed) (GimpImage *gimage); - void (* component_visibility_changed) (GimpImage *gimage, - ChannelType channel); - void (* component_active_changed) (GimpImage *gimage, - ChannelType channel); - void (* mask_changed) (GimpImage *gimage); - void (* resolution_changed) (GimpImage *gimage); - void (* unit_changed) (GimpImage *gimage); - void (* qmask_changed) (GimpImage *gimage); - void (* selection_control) (GimpImage *gimage, - GimpSelectionControl control); - - void (* clean) (GimpImage *gimage); - void (* dirty) (GimpImage *gimage); - void (* update) (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); - void (* update_guide) (GimpImage *gimage, - GimpGuide *guide); - void (* colormap_changed) (GimpImage *gimage, - gint color_index); - void (* undo_event) (GimpImage *gimage, - gint event); - - void (* undo) (GimpImage *gimage); - void (* redo) (GimpImage *gimage); -}; - - -/* function declarations */ - -GType gimp_image_get_type (void) G_GNUC_CONST; - -GimpImage * gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type); - -gint gimp_image_get_ID (GimpImage *gimage); -GimpImage * gimp_image_get_by_ID (Gimp *gimp, - gint id); - -void gimp_image_set_filename (GimpImage *gimage, - const gchar *filename); -void gimp_image_set_resolution (GimpImage *gimage, - gdouble xres, - gdouble yres); -void gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution); -void gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit); -GimpUnit gimp_image_get_unit (const GimpImage *gimage); - -void gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state); -gboolean gimp_image_get_qmask_state (const GimpImage *gimage); - -void gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc); -PlugInProcDef * gimp_image_get_save_proc (const GimpImage *gimage); - -gint gimp_image_get_width (const GimpImage *gimage); -gint gimp_image_get_height (const GimpImage *gimage); - -void gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y); -void gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data); -gboolean gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height); - -TileManager * gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); -void gimp_image_free_shadow (GimpImage *gimage); - -void gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - TileManager *src1_tiles, - gint x, - gint y); -void gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y); - -void gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg); -void gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg); -void gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src); -void gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type); - -GimpGuide * gimp_image_add_hguide (GimpImage *gimage); -GimpGuide * gimp_image_add_vguide (GimpImage *gimage); -void gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide); -GimpGuide * gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty); -gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1); - -GimpParasite * gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name); -gchar ** gimp_image_parasite_list (const GimpImage *gimage, - gint *count); -void gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite); -void gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite); - -GimpTattoo gimp_image_get_new_tattoo (GimpImage *gimage); -gboolean gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val); -GimpTattoo gimp_image_get_tattoo_state (GimpImage *gimage); - -void gimp_image_set_paths (GimpImage *gimage, - PathList *paths); -PathList * gimp_image_get_paths (const GimpImage *gimage); - -/* Temporary hack till colormap manipulation is encapsulated in functions. - * Call this whenever you modify an image's colormap. The col argument - * specifies which color has changed, or negative if there's a bigger change. - * Currently, use this also when the image's base type is changed to/from - * indexed. - */ -void gimp_image_colormap_changed (GimpImage *gimage, - gint col); - -void gimp_image_mode_changed (GimpImage *gimage); -void gimp_image_alpha_changed (GimpImage *gimage); -void gimp_image_floating_selection_changed (GimpImage *gimage); -void gimp_image_mask_changed (GimpImage *gimage); -void gimp_image_resolution_changed (GimpImage *gimage); -void gimp_image_unit_changed (GimpImage *gimage); -void gimp_image_qmask_changed (GimpImage *gimage); -void gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); -void gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control); - - -/* layer/channel functions */ - -GimpContainer * gimp_image_get_layers (const GimpImage *gimage); -GimpContainer * gimp_image_get_channels (const GimpImage *gimage); - -gint gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer); -gint gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel); -GimpLayer * gimp_image_get_active_layer (const GimpImage *gimage); -GimpChannel * gimp_image_get_active_channel (const GimpImage *gimage); -GimpLayer * gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name); -GimpChannel * gimp_image_get_mask (const GimpImage *gimage); - -void gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active); -gboolean gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type); -void gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active); - -void gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible); -gboolean gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type); - -gboolean gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs); -GimpLayer * gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer); -GimpChannel * gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel); -GimpChannel * gimp_image_unset_active_channel (GimpImage *gimage); -GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo); -GimpLayer * gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type); -GimpLayer * gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type); -GimpLayer * gimp_image_flatten (GimpImage *gimage); -GimpLayer * gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type); -gboolean gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position); -void gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo); -gboolean gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position); -void gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel); - -void gimp_image_invalidate_layer_previews (GimpImage *gimage); -void gimp_image_invalidate_channel_previews (GimpImage *gimage); - - -/* Access functions */ - -gboolean gimp_image_is_empty (const GimpImage *gimage); -GimpDrawable * gimp_image_active_drawable (const GimpImage *gimage); - -GimpImageBaseType gimp_image_base_type (const GimpImage *gimage); -GimpImageType gimp_image_base_type_with_alpha (const GimpImage *gimage); - -const gchar * gimp_image_filename (const GimpImage *gimage); -gboolean gimp_image_undo_is_enabled (const GimpImage *gimage); -gboolean gimp_image_undo_enable (GimpImage *gimage); -gboolean gimp_image_undo_disable (GimpImage *gimage); -gboolean gimp_image_undo_freeze (GimpImage *gimage); -gboolean gimp_image_undo_thaw (GimpImage *gimage); -void gimp_image_undo_event (GimpImage *gimage, - gint event); -gint gimp_image_dirty (GimpImage *gimage); -gint gimp_image_clean (GimpImage *gimage); -void gimp_image_clean_all (GimpImage *gimage); -GimpLayer * gimp_image_floating_sel (const GimpImage *gimage); -guchar * gimp_image_cmap (const GimpImage *gimage); - -gboolean gimp_image_preview_valid (const GimpImage *gimage); - - -#endif /* __GIMP_IMAGE_H__ */ +#endif /* __GIMP_IMAGE_RESIZE_H__ */ diff --git a/app/core/gimpimage-scale.c b/app/core/gimpimage-scale.c index cd786391e4..b3426d3725 100644 --- a/app/core/gimpimage-scale.c +++ b/app/core/gimpimage-scale.c @@ -18,908 +18,22 @@ #include "config.h" -#include - #include -#include "libgimpcolor/gimpcolor.h" -#include "libgimpmath/gimpmath.h" -#include "libgimpbase/gimpbase.h" - #include "core-types.h" -#include "base/pixel-region.h" -#include "base/temp-buf.h" -#include "base/tile-manager.h" - -#include "paint-funcs/paint-funcs.h" - #include "gimp.h" -#include "gimpcontext.h" -#include "gimpcoreconfig.h" +#include "gimpchannel.h" #include "gimpimage.h" -#include "gimpimage-colorhash.h" #include "gimpimage-mask.h" #include "gimpimage-projection.h" -#include "gimpimage-undo.h" +#include "gimpimage-scale.h" #include "gimplayer.h" -#include "gimplayermask.h" #include "gimplist.h" -#include "gimpmarshal.h" -#include "gimpparasite.h" -#include "gimpparasitelist.h" -#include "gimpundostack.h" #include "floating_sel.h" -#include "path.h" #include "undo.h" -#include "libgimp/gimpintl.h" - - -#ifdef DEBUG -#define TRC(x) printf x -#else -#define TRC(x) -#endif - -#define GUIDE_EPSILON 5 - - -enum -{ - MODE_CHANGED, - ALPHA_CHANGED, - FLOATING_SELECTION_CHANGED, - ACTIVE_LAYER_CHANGED, - ACTIVE_CHANNEL_CHANGED, - COMPONENT_VISIBILITY_CHANGED, - COMPONENT_ACTIVE_CHANGED, - MASK_CHANGED, - RESOLUTION_CHANGED, - UNIT_CHANGED, - QMASK_CHANGED, - SELECTION_CONTROL, - - CLEAN, - DIRTY, - UPDATE, - UPDATE_GUIDE, - COLORMAP_CHANGED, - UNDO_EVENT, - LAST_SIGNAL -}; - - -/* local function prototypes */ - -static void gimp_image_class_init (GimpImageClass *klass); -static void gimp_image_init (GimpImage *gimage); - -static void gimp_image_dispose (GObject *object); -static void gimp_image_finalize (GObject *object); - -static void gimp_image_name_changed (GimpObject *object); -static void gimp_image_invalidate_preview (GimpViewable *viewable); -static void gimp_image_size_changed (GimpViewable *viewable); -static void gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol); -static TempBuf *gimp_image_get_preview (GimpViewable *gimage, - gint width, - gint height); -static TempBuf *gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height); -static void gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); - -/* - * Static variables - */ -static gint valid_combinations[][MAX_CHANNELS + 1] = -{ - /* RGB GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A }, - /* RGBA GIMAGE */ - { -1, -1, -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A }, - /* GRAY GIMAGE */ - { -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A, -1, -1 }, - /* GRAYA GIMAGE */ - { -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A, -1, -1 }, - /* INDEXED GIMAGE */ - { -1, COMBINE_INDEXED_INDEXED, COMBINE_INDEXED_INDEXED_A, -1, -1 }, - /* INDEXEDA GIMAGE */ - { -1, -1, COMBINE_INDEXED_A_INDEXED_A, -1, -1 }, -}; - -static guint gimp_image_signals[LAST_SIGNAL] = { 0 }; - -static GimpViewableClass *parent_class = NULL; - - -GType -gimp_image_get_type (void) -{ - static GType image_type = 0; - - if (! image_type) - { - static const GTypeInfo image_info = - { - sizeof (GimpImageClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gimp_image_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GimpImage), - 0, /* n_preallocs */ - (GInstanceInitFunc) gimp_image_init, - }; - - image_type = g_type_register_static (GIMP_TYPE_VIEWABLE, - "GimpImage", - &image_info, 0); - } - - return image_type; -} - -static void -gimp_image_class_init (GimpImageClass *klass) -{ - GObjectClass *object_class; - GimpObjectClass *gimp_object_class; - GimpViewableClass *viewable_class; - - object_class = G_OBJECT_CLASS (klass); - gimp_object_class = GIMP_OBJECT_CLASS (klass); - viewable_class = GIMP_VIEWABLE_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gimp_image_signals[MODE_CHANGED] = - g_signal_new ("mode_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mode_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ALPHA_CHANGED] = - g_signal_new ("alpha_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, alpha_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[FLOATING_SELECTION_CHANGED] = - g_signal_new ("floating_selection_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, floating_selection_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_LAYER_CHANGED] = - g_signal_new ("active_layer_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_layer_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[ACTIVE_CHANNEL_CHANGED] = - g_signal_new ("active_channel_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_channel_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] = - g_signal_new ("component_visibility_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_visibility_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[COMPONENT_ACTIVE_CHANGED] = - g_signal_new ("component_active_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, component_active_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[MASK_CHANGED] = - g_signal_new ("mask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, mask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[RESOLUTION_CHANGED] = - g_signal_new ("resolution_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, resolution_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UNIT_CHANGED] = - g_signal_new ("unit_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, unit_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[QMASK_CHANGED] = - g_signal_new ("qmask_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, qmask_changed), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[SELECTION_CONTROL] = - g_signal_new ("selection_control", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, selection_control), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[CLEAN] = - g_signal_new ("clean", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, clean), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[DIRTY] = - g_signal_new ("dirty", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, dirty), - NULL, NULL, - gimp_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gimp_image_signals[UPDATE] = - g_signal_new ("update", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update), - NULL, NULL, - gimp_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT); - - gimp_image_signals[UPDATE_GUIDE] = - g_signal_new ("update_guide", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, update_guide), - NULL, NULL, - gimp_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - gimp_image_signals[COLORMAP_CHANGED] = - g_signal_new ("colormap_changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, colormap_changed), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - gimp_image_signals[UNDO_EVENT] = - g_signal_new ("undo_event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, undo_event), - NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); - - object_class->dispose = gimp_image_dispose; - object_class->finalize = gimp_image_finalize; - - gimp_object_class->name_changed = gimp_image_name_changed; - - viewable_class->invalidate_preview = gimp_image_invalidate_preview; - viewable_class->size_changed = gimp_image_size_changed; - viewable_class->get_preview = gimp_image_get_preview; - viewable_class->get_new_preview = gimp_image_get_new_preview; - - klass->mode_changed = NULL; - klass->alpha_changed = NULL; - klass->floating_selection_changed = NULL; - klass->active_layer_changed = NULL; - klass->active_channel_changed = NULL; - klass->component_visibility_changed = NULL; - klass->component_active_changed = NULL; - klass->mask_changed = NULL; - - klass->clean = NULL; - klass->dirty = NULL; - klass->update = NULL; - klass->update_guide = NULL; - klass->colormap_changed = gimp_image_real_colormap_changed; - klass->undo_event = NULL; - klass->undo = gimp_image_undo; - klass->redo = gimp_image_redo; - - gimp_image_color_hash_init (); -} - - -/* static functions */ - -static void -gimp_image_init (GimpImage *gimage) -{ - gimage->ID = 0; - - gimage->save_proc = NULL; - - gimage->width = 0; - gimage->height = 0; - gimage->xresolution = 1.0; - gimage->yresolution = 1.0; - gimage->unit = GIMP_UNIT_INCH; - gimage->base_type = RGB; - - gimage->cmap = NULL; - gimage->num_cols = 0; - - gimage->dirty = 1; - gimage->undo_on = TRUE; - - gimage->instance_count = 0; - gimage->disp_count = 0; - - gimage->tattoo_state = 0; - - gimage->shadow = NULL; - - gimage->construct_flag = FALSE; - gimage->proj_type = RGBA_GIMAGE; - gimage->projection = NULL; - - gimage->guides = NULL; - - gimage->layers = gimp_list_new (GIMP_TYPE_LAYER, - GIMP_CONTAINER_POLICY_STRONG); - gimage->channels = gimp_list_new (GIMP_TYPE_CHANNEL, - GIMP_CONTAINER_POLICY_STRONG); - gimage->layer_stack = NULL; - - gimage->active_layer = NULL; - gimage->active_channel = NULL; - gimage->floating_sel = NULL; - gimage->selection_mask = NULL; - - gimage->parasites = gimp_parasite_list_new (); - - gimage->paths = NULL; - - gimage->qmask_state = FALSE; - gimage->qmask_color.r = 1.0; - gimage->qmask_color.g = 0.0; - gimage->qmask_color.b = 0.0; - gimage->qmask_color.a = 0.5; - - gimage->undo_stack = NULL; - gimage->redo_stack = NULL; - gimage->undo_bytes = 0; - gimage->undo_levels = 0; - gimage->group_count = 0; - gimage->pushing_undo_group = UNDO_NULL; - - gimage->new_undo_stack = gimp_undo_stack_new (gimage); - gimage->new_redo_stack = gimp_undo_stack_new (gimage); - - gimage->comp_preview = NULL; - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_dispose (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - undo_free (gimage); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gimp_image_finalize (GObject *object) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); - - if (gimage->gimp && gimage->gimp->image_table) - { - g_hash_table_remove (gimage->gimp->image_table, - GINT_TO_POINTER (gimage->ID)); - gimage->gimp = NULL; - } - - if (gimage->projection) - gimp_image_projection_free (gimage); - - if (gimage->shadow) - gimp_image_free_shadow (gimage); - - if (gimage->cmap) - { - g_free (gimage->cmap); - gimage->cmap = NULL; - } - - if (gimage->layers) - { - g_object_unref (G_OBJECT (gimage->layers)); - gimage->layers = NULL; - } - if (gimage->channels) - { - g_object_unref (G_OBJECT (gimage->channels)); - gimage->channels = NULL; - } - if (gimage->layer_stack) - { - g_slist_free (gimage->layer_stack); - gimage->layer_stack = NULL; - } - - if (gimage->selection_mask) - { - g_object_unref (G_OBJECT (gimage->selection_mask)); - gimage->selection_mask = NULL; - } - - if (gimage->comp_preview) - { - temp_buf_free (gimage->comp_preview); - gimage->comp_preview = NULL; - } - - if (gimage->parasites) - { - g_object_unref (G_OBJECT (gimage->parasites)); - gimage->parasites = NULL; - } - - if (gimage->guides) - { - g_list_foreach (gimage->guides, (GFunc) g_free, NULL); - g_list_free (gimage->guides); - gimage->guides = NULL; - } - - if (gimage->new_undo_stack) - { - g_object_unref (G_OBJECT (gimage->new_undo_stack)); - gimage->new_undo_stack = NULL; - } - if (gimage->new_redo_stack) - { - g_object_unref (G_OBJECT (gimage->new_redo_stack)); - gimage->new_redo_stack = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gimp_image_name_changed (GimpObject *object) -{ - GimpImage *gimage; - const gchar *name; - - if (GIMP_OBJECT_CLASS (parent_class)->name_changed) - GIMP_OBJECT_CLASS (parent_class)->name_changed (object); - - gimage = GIMP_IMAGE (object); - name = gimp_object_get_name (object); - - if (! (name && strlen (name))) - { - g_free (object->name); - object->name = NULL; - } -} - -static void -gimp_image_invalidate_preview (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview) - GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimage->comp_preview_valid = FALSE; -} - -static void -gimp_image_size_changed (GimpViewable *viewable) -{ - GimpImage *gimage; - - if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed) - GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable); - - gimage = GIMP_IMAGE (viewable); - - gimp_image_invalidate_layer_previews (gimage); - gimp_image_invalidate_channel_previews (gimage); -} - -static void -gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol) -{ - if (gimp_image_base_type (gimage) == INDEXED) - gimp_image_color_hash_invalidate (gimage, ncol); -} - -static void -gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - /* allocate the new projection */ - gimage->shadow = tile_manager_new (width, height, bpp); -} - - -/* function definitions */ - -GimpImage * -gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type) -{ - GimpImage *gimage; - gint i; - - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - gimage = GIMP_IMAGE (g_object_new (GIMP_TYPE_IMAGE, NULL)); - - gimage->gimp = gimp; - gimage->ID = gimp->next_image_ID++; - - g_hash_table_insert (gimp->image_table, - GINT_TO_POINTER (gimage->ID), - (gpointer) gimage); - - gimage->width = width; - gimage->height = height; - gimage->base_type = base_type; - - gimage->xresolution = gimp->config->default_xresolution; - gimage->yresolution = gimp->config->default_yresolution; - gimage->unit = gimp->config->default_units; - - switch (base_type) - { - case RGB: - case GRAY: - break; - case INDEXED: - /* always allocate 256 colors for the colormap */ - gimage->num_cols = 0; - gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE); - break; - default: - break; - } - - /* set all color channels visible and active */ - for (i = 0; i < MAX_CHANNELS; i++) - { - gimage->visible[i] = TRUE; - gimage->active[i] = TRUE; - } - - /* create the selection mask */ - gimage->selection_mask = gimp_channel_new_mask (gimage, - gimage->width, - gimage->height); - - - return gimage; -} - -gint -gimp_image_get_ID (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->ID; -} - -GimpImage * -gimp_image_get_by_ID (Gimp *gimp, - gint image_id) -{ - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - if (gimp->image_table == NULL) - return NULL; - - return (GimpImage *) g_hash_table_lookup (gimp->image_table, - GINT_TO_POINTER (image_id)); -} - -void -gimp_image_set_filename (GimpImage *gimage, - const gchar *filename) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_object_set_name (GIMP_OBJECT (gimage), filename); -} - -void -gimp_image_set_resolution (GimpImage *gimage, - gdouble xresolution, - gdouble yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* don't allow to set the resolution out of bounds */ - if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION || - yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION) - return; - - if ((ABS (gimage->xresolution - xresolution) >= 1e-5) || - (ABS (gimage->yresolution - yresolution) >= 1e-5)) - { - undo_push_resolution (gimage); - - gimage->xresolution = xresolution; - gimage->yresolution = yresolution; - - gimp_image_resolution_changed (gimage); - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - } -} - -void -gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (xresolution && yresolution); - - *xresolution = gimage->xresolution; - *yresolution = gimage->yresolution; -} - -void -gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->unit != unit) - { - undo_push_resolution (gimage); - - gimage->unit = unit; - - gimp_image_unit_changed (gimage); - } -} - -GimpUnit -gimp_image_get_unit (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_UNIT_INCH); - - return gimage->unit; -} - -void -gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (qmask_state != gimage->qmask_state) - { - gimage->qmask_state = qmask_state ? TRUE : FALSE; - - gimp_image_qmask_changed (gimage); - } -} - -gboolean -gimp_image_get_qmask_state (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->qmask_state; -} - -void -gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->save_proc = proc; -} - -PlugInProcDef * -gimp_image_get_save_proc (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->save_proc; -} - -gint -gimp_image_get_width (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->width; -} - -gint -gimp_image_get_height (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->height; -} - -void -gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GList *guide_list; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_RESIZE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - gimage->width = new_width; - gimage->height = new_height; - - /* Resize all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y); - } - - /* Reposition or remove any guides */ - guide_list = gimage->guides; - while (guide_list) - { - GimpGuide *guide; - - guide = (GimpGuide *) guide_list->data; - guide_list = g_list_next (guide_list); - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position += offset_y; - if (guide->position < 0 || guide->position > new_height) - gimp_image_delete_guide (gimage, guide); - break; - - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position += offset_x; - if (guide->position < 0 || guide->position > new_width) - gimp_image_delete_guide (gimage, guide); - break; - - default: - g_error ("Unknown guide orientation\n"); - } - } - - /* Don't forget the selection mask! */ - gimp_channel_resize (gimage->selection_mask, - new_width, new_height, offset_x, offset_y); - gimage_mask_invalidate (gimage); - - /* Reposition all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - gimp_layer_translate (layer, offset_x, offset_y); - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} void gimp_image_scale (GimpImage *gimage, @@ -1102,2766 +216,3 @@ gimp_image_check_scaling (const GimpImage *gimage, return TRUE; } - -TileManager * -gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (gimage->shadow && - ((width != tile_manager_width (gimage->shadow)) || - (height != tile_manager_height (gimage->shadow)) || - (bpp != tile_manager_bpp (gimage->shadow)))) - gimp_image_free_shadow (gimage); - else if (gimage->shadow) - return gimage->shadow; - - gimp_image_allocate_shadow (gimage, width, height, bpp); - - return gimage->shadow; -} - -void -gimp_image_free_shadow (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->shadow) - { - tile_manager_destroy (gimage->shadow); - gimage->shadow = NULL; - } -} - -void -gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - /* alternative to using drawable tiles as src1: */ - TileManager *src1_tiles, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR, maskPR; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations[gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - if (src1_tiles) - pixel_region_init (&src1PR, src1_tiles, - x1, y1, (x2 - x1), (y2 - y1), FALSE); - else - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - gint mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL, - opacity, mode, active, operation); - } - else - { - combine_regions (&src1PR, src2PR, &destPR, NULL, NULL, - opacity, mode, active, operation); - } -} - -/* Similar to gimp_image_apply_image but works in "replace" mode (i.e. - transparent pixels in src2 make the result transparent rather - than opaque. - - Takes an additional mask pixel region as well. -*/ -void -gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR; - PixelRegion mask2PR, tempPR; - guchar *temp_data; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations [gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - gimp_drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - int mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&mask2PR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - - tempPR.bytes = 1; - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.rowstride = tempPR.w * tempPR.bytes; - temp_data = g_malloc (tempPR.h * tempPR.rowstride); - tempPR.data = temp_data; - - copy_region (&mask2PR, &tempPR); - - /* apparently, region operations can mutate some PR data. */ - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); - - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, - opacity, active, operation); - - g_free (temp_data); - } - else - { - combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL, - opacity, active, operation); - } -} - -/* Get rid of these! A "foreground" is an UI concept.. */ - -void -gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg) -{ - GimpRGB color; - guchar pfg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (fg != NULL); - - gimp_context_get_foreground (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]); - - gimp_image_transform_color (gimage, drawable, pfg, fg, RGB); -} - -void -gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg) -{ - GimpRGB color; - guchar pbg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (bg != NULL); - - gimp_context_get_background (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]); - - gimp_image_transform_color (gimage, drawable, pbg, bg, RGB); -} - -void -gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - map_to_color (0, NULL, src, rgb); - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - map_to_color (1, NULL, src, rgb); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - map_to_color (2, gimage->cmap, src, rgb); - break; - } -} - -void -gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type) -{ - GimpImageType d_type; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - d_type = (drawable != NULL) ? gimp_drawable_type (drawable) : - gimp_image_base_type_with_alpha (gimage); - - switch (type) - { - case RGB: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Straight copy */ - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* NTSC conversion */ - *dest = INTENSITY (src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - } - break; - case GRAY: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Gray to RG&B */ - *dest++ = *src; - *dest++ = *src; - *dest++ = *src; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* Straight copy */ - *dest = *src; - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[GRAY_PIX], - src[GRAY_PIX], - src[GRAY_PIX]); - break; - } - break; - default: - break; - } -} - -GimpGuide * -gimp_image_add_hguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_HORIZONTAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -GimpGuide * -gimp_image_add_vguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_VERTICAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -void -gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_prepend (gimage->guides, guide); -} - -void -gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_remove (gimage->guides, guide); -} - -void -gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide) -{ - guide->position = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (guide->ref_count <= 0) - { - gimage->guides = g_list_remove (gimage->guides, guide); - g_free (guide); - } -} - -GimpGuide * -gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y) -{ - GList *list; - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return NULL; - } - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - if (ABS (guide->position - y) < GUIDE_EPSILON) - return guide; - break; - - case ORIENTATION_VERTICAL: - if (ABS (guide->position - x) < GUIDE_EPSILON) - return guide; - break; - - default: - break; - } - } - - return NULL; -} - -gboolean -gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty) -{ - GList *list; - GimpGuide *guide; - gint minxdist, minydist; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx != NULL, FALSE); - g_return_val_if_fail (ty != NULL, FALSE); - - *tx = x; - *ty = y; - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return FALSE; - } - - minxdist = G_MAXINT; - minydist = G_MAXINT; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - dist = ABS (guide->position - y); - - if (dist < MIN (GUIDE_EPSILON, minydist)) - { - minydist = dist; - *ty = guide->position; - snapped = TRUE; - } - break; - - case ORIENTATION_VERTICAL: - dist = ABS (guide->position - x); - - if (dist < MIN (GUIDE_EPSILON, minxdist)) - { - minxdist = dist; - *tx = guide->position; - snapped = TRUE; - } - break; - - default: - break; - } - } - - return snapped; -} - -gboolean -gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1) -{ - gint nx1, ny1; - gint nx2, ny2; - gboolean snap1, snap2; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx1 != NULL, FALSE); - g_return_val_if_fail (ty1 != NULL, FALSE); - - *tx1 = x1; - *ty1 = y1; - - snap1 = gimp_image_snap_point (gimage, x1, y1, &nx1, &ny1); - snap2 = gimp_image_snap_point (gimage, x2, y2, &nx2, &ny2); - - if (snap1 || snap2) - { - if (x1 != nx1) - *tx1 = nx1; - else if (x2 != nx2) - *tx1 = x1 + (nx2 - x2); - - if (y1 != ny1) - *ty1 = ny1; - else if (y2 != ny2) - *ty1 = y1 + (ny2 - y2); - } - - return snap1 || snap2; -} - -GimpParasite * -gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimp_parasite_list_find (gimage->parasites, name); -} - -static void -list_func (gchar *key, - GimpParasite *p, - gchar ***cur) -{ - *(*cur)++ = (gchar *) g_strdup (key); -} - -gchar ** -gimp_image_parasite_list (const GimpImage *gimage, - gint *count) -{ - gchar **list; - gchar **cur; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - *count = gimp_parasite_list_length (gimage->parasites); - cur = list = g_new (gchar*, *count); - - gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur); - - return list; -} - -void -gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL); - - /* only set the dirty bit manually if we can be saved and the new - parasite differs from the current one and we aren't undoable */ - if (gimp_parasite_is_undoable (parasite)) - undo_push_image_parasite (gimage, parasite); - - /* We used to push an cantundo on te stack here. This made the undo stack - unusable (NULL on the stack) and prevented people from undoing after a - save (since most save plug-ins attach an undoable comment parasite). - Now we simply attach the parasite without pushing an undo. That way it's - undoable but does not block the undo system. --Sven - */ - - gimp_parasite_list_add (gimage->parasites, parasite); - - if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT)) - { - gimp_parasite_shift_parent (parasite); - gimp_parasite_attach (gimage->gimp, parasite); - } -} - -void -gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite) -{ - GimpParasite *p; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (parasite != NULL); - - if (!(p = gimp_parasite_list_find (gimage->parasites, parasite))) - return; - - if (gimp_parasite_is_undoable (p)) - undo_push_image_parasite_remove (gimage, gimp_parasite_name (p)); - - gimp_parasite_list_remove (gimage->parasites, parasite); -} - -GimpTattoo -gimp_image_get_new_tattoo (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - gimage->tattoo_state++; - - if (gimage->tattoo_state <= 0) - g_warning ("%s: Tattoo state corrupted " - "(integer overflow).", G_GNUC_PRETTY_FUNCTION); - - return gimage->tattoo_state; -} - -GimpTattoo -gimp_image_get_tattoo_state (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->tattoo_state; -} - -gboolean -gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val) -{ - GList *list; - gboolean retval = TRUE; - GimpChannel *channel; - GimpTattoo maxval = 0; - Path *pptr = NULL; - PathList *plist; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ltattoo; - - ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data)); - if (ltattoo > maxval) - maxval = ltattoo; - if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in channel */ - } - - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Now check that the paths channel tattoos don't overlap */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ctattoo; - - channel = (GimpChannel *) list->data; - - ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)); - if (ctattoo > maxval) - maxval = ctattoo; - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ctattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Find the max tatto value in the paths */ - plist = gimage->paths; - - if (plist && plist->bz_paths) - { - GimpTattoo ptattoo; - GSList *pl; - - for (pl = plist->bz_paths; pl; pl = g_slist_next (pl)) - { - pptr = pl->data; - - ptattoo = path_get_tattoo (pptr); - - if (ptattoo > maxval) - maxval = ptattoo; - } - } - - if (val < maxval) - retval = FALSE; - /* Must check the state is valid */ - if (retval == TRUE) - gimage->tattoo_state = val; - - return retval; -} - -void -gimp_image_set_paths (GimpImage *gimage, - PathList *paths) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->paths = paths; -} - -PathList * -gimp_image_get_paths (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->paths; -} - -void -gimp_image_colormap_changed (GimpImage *gimage, - gint col) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (col < gimage->num_cols); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[COLORMAP_CHANGED], 0, - col); -} - -void -gimp_image_mode_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MODE_CHANGED], 0); -} - -void -gimp_image_mask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MASK_CHANGED], 0); -} - -void -gimp_image_resolution_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[RESOLUTION_CHANGED], 0); -} - -void -gimp_image_unit_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNIT_CHANGED], 0); -} - -void -gimp_image_qmask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[QMASK_CHANGED], 0); -} - -void -gimp_image_alpha_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED], 0); -} - -void -gimp_image_floating_selection_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[FLOATING_SELECTION_CHANGED], 0); -} - -void -gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE], 0, - x, y, width, height); -} - -void -gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (guide != NULL); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE_GUIDE], 0, - guide); -} - -void -gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[SELECTION_CONTROL], 0, - control); -} - -void -gimp_image_invalidate_layer_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->layers, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -void -gimp_image_invalidate_channel_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->channels, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -GimpContainer * -gimp_image_get_layers (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->layers; -} - -GimpContainer * -gimp_image_get_channels (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->channels; -} - -gint -gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_LAYER (layer), -1); - - return gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); -} - -gint -gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1); - - return gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); -} - -GimpLayer * -gimp_image_get_active_layer (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_layer; -} - -GimpChannel * -gimp_image_get_active_channel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_channel; -} - -GimpLayer * -gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo) - return layer; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name)) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_mask (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->selection_mask; -} - -void -gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && active != gimage->active[pixel]) - { - gimage->active[pixel] = active ? TRUE : FALSE; - - /* If there is an active channel and we mess with the components, - * the active channel gets unset... - */ - gimp_image_unset_active_channel (gimage); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, - type); - } -} - -gboolean -gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->active[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->active[ALPHA_PIX]; break; - case GRAY: return gimage->active[ALPHA_G_PIX]; break; - case INDEXED: return gimage->active[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -void -gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active) -{ - GimpLayer *layer; - gint i; - - /* first, blindly copy the gimage active channels */ - for (i = 0; i < MAX_CHANNELS; i++) - active[i] = gimage->active[i]; - - /* If the drawable is a channel (a saved selection, etc.) - * make sure that the alpha channel is not valid - */ - if (GIMP_IS_CHANNEL (drawable)) - { - active[ALPHA_G_PIX] = 0; /* no alpha values in channels */ - } - else - { - /* otherwise, check whether preserve transparency is - * enabled in the layer and if the layer has alpha - */ - if (GIMP_IS_LAYER (drawable)) - { - layer = GIMP_LAYER (drawable); - if (gimp_layer_has_alpha (layer) && layer->preserve_trans) - active[gimp_drawable_bytes (drawable) - 1] = 0; - } - } -} - -void -gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && visible != gimage->visible[pixel]) - { - gimage->visible[pixel] = visible ? TRUE : FALSE; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED], 0, - type); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - } -} - -gboolean -gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->visible[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->visible[ALPHA_PIX]; break; - case GRAY: return gimage->visible[ALPHA_G_PIX]; break; - case INDEXED: return gimage->visible[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -gboolean -gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs) -{ - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (segs != NULL, FALSE); - g_return_val_if_fail (n_segs != NULL, FALSE); - - /* The second boundary corresponds to the active layer's - * perimeter... - */ - layer = gimp_image_get_active_layer (gimage); - - if (layer) - { - *segs = gimp_layer_boundary (layer, n_segs); - return TRUE; - } - else - { - *segs = NULL; - *n_segs = 0; - return FALSE; - } -} - -GimpLayer * -gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); - - /* First, find the layer in the gimage - * If it isn't valid, find the first layer that is - */ - if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0); - - if (layer) - { - /* Configure the layer stack to reflect this change */ - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer); - - /* invalidate the selection boundary because of a layer modification */ - gimp_layer_invalidate_boundary (layer); - } - - if (layer != gimage->active_layer) - { - gimage->active_layer = layer; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - - if (gimage->active_channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - } - } - - /* return the layer */ - return layer; -} - -GimpChannel * -gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* Not if there is a floating selection */ - if (gimp_image_floating_sel (gimage)) - return NULL; - - /* First, find the channel - * If it doesn't exist, find the first channel that does - */ - if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0); - - if (channel != gimage->active_channel) - { - gimage->active_channel = channel; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->active_layer) - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* return the channel */ - return channel; -} - -GimpChannel * -gimp_image_unset_active_channel (GimpImage *gimage) -{ - GimpChannel *channel; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - channel = gimp_image_get_active_channel (gimage); - - if (channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->layer_stack) - { - GimpLayer *layer; - - layer = (GimpLayer *) gimage->layer_stack->data; - - gimp_image_set_active_layer (gimage, layer); - } - } - - return channel; -} - -GimpLayer * -gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_layer_pick_correlate (layer, x, y)) - return layer; - } - - return NULL; -} - -gboolean -gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the top layer already? */ - if (curpos == 0) - { - g_message (_("Layer cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE); -} - -gboolean -gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the bottom layer already? */ - length = gimp_container_num_children (gimage->layers); - if (curpos >= length - 1) - { - g_message (_("Layer cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE); -} - -gboolean -gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - if (curpos == 0) - { - g_message (_("Layer is already on top.")); - return FALSE; - } - - if (! gimp_layer_has_alpha (layer)) - { - g_message (_("Cannot raise a layer without alpha.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, 0, TRUE); -} - -gboolean -gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - length = gimp_container_num_children (gimage->layers); - - if (curpos >= length - 1) - { - g_message (_("Layer is already on the bottom.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, length - 1, TRUE); -} - -gboolean -gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo) -{ - gint off_x, off_y; - gint index; - gint num_layers; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - index = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - if (index < 0) - return FALSE; - - num_layers = gimp_container_num_children (gimage->layers); - - if (new_index < 0) - new_index = 0; - - if (new_index >= num_layers) - new_index = num_layers - 1; - - if (new_index == index) - return TRUE; - - /* check if we want to move it below a bottom layer without alpha */ - if (new_index == num_layers - 1) - { - GimpLayer *tmp; - - tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, - num_layers - 1); - - if (new_index == num_layers - 1 && - ! gimp_layer_has_alpha (tmp)) - { - g_message (_("Layer \"%s\" has no alpha.\nLayer was placed above it."), - GIMP_OBJECT (tmp)->name); - new_index--; - } - } - - if (push_undo) - undo_push_layer_reposition (gimage, layer); - - gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - gimp_image_update (gimage, - off_x, off_y, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); - - return TRUE; -} - -GimpLayer * -gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type) -{ - GList *list; - GSList *merge_list = NULL; - gboolean had_floating_sel = FALSE; - GimpLayer *layer = NULL; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - { - floating_sel_anchor (gimage->floating_sel); - had_floating_sel = TRUE; - } - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - if (merge_list && merge_list->next) - { - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_slist_free (merge_list); - - /* If there was a floating selection, we have done something. - No need to warn the user. Return the active layer instead */ - if (had_floating_sel) - return layer; - else - g_message (_("Not enough visible layers for a merge.\n" - "There must be at least two.")); - - return NULL; - } -} - -GimpLayer * -gimp_image_flatten (GimpImage *gimage) -{ - GList *list; - GSList *merge_list = NULL; - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - gimp_set_busy (gimage->gimp); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - floating_sel_anchor (gimage->floating_sel); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - layer = gimp_image_merge_layers (gimage, merge_list, FLATTEN_IMAGE); - g_slist_free (merge_list); - - gimp_image_alpha_changed (gimage); - - gimp_unset_busy (gimage->gimp); - - return layer; -} - -GimpLayer * -gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type) -{ - GimpLayer *layer; - GList *list; - GList *layer_list; - GSList *merge_list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list, layer_list = NULL; - list && !layer_list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (layer == current_layer) - break; - } - - for (layer_list = g_list_next (list), merge_list = NULL; - layer_list && !merge_list; - layer_list = g_list_next (layer_list)) - { - layer = (GimpLayer *) layer_list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (NULL, layer); - } - - if (merge_list) - { - merge_list = g_slist_prepend (merge_list, current_layer); - - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_message (_("There are not enough visible layers for a merge down.")); - return NULL; - } -} - -GimpLayer * -gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type) -{ - GList *list; - GSList *reverse_list = NULL; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - GimpLayer *merge_layer; - GimpLayer *layer; - GimpLayer *bottom_layer; - LayerModeEffects bottom_mode; - guchar bg[4] = {0, 0, 0, 0}; - GimpImageType type; - gint count; - gint x1, y1, x2, y2; - gint x3, y3, x4, y4; - gint operation; - gint position; - gint active[MAX_CHANNELS] = {1, 1, 1, 1}; - gint off_x, off_y; - gchar *name; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - layer = NULL; - type = RGBA_GIMAGE; - x1 = y1 = 0; - x2 = y2 = 0; - bottom_layer = NULL; - bottom_mode = NORMAL_MODE; - - /* Get the layer extents */ - count = 0; - while (merge_list) - { - layer = (GimpLayer *) merge_list->data; - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - switch (merge_type) - { - case EXPAND_AS_NECESSARY: - case CLIP_TO_IMAGE: - if (!count) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - else - { - if (off_x < x1) - x1 = off_x; - if (off_y < y1) - y1 = off_y; - if ((off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) > x2) - x2 = (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))); - if ((off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))) > y2) - y2 = (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))); - } - if (merge_type == CLIP_TO_IMAGE) - { - x1 = CLAMP (x1, 0, gimage->width); - y1 = CLAMP (y1, 0, gimage->height); - x2 = CLAMP (x2, 0, gimage->width); - y2 = CLAMP (y2, 0, gimage->height); - } - break; - - case CLIP_TO_BOTTOM_LAYER: - if (merge_list->next == NULL) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - break; - - case FLATTEN_IMAGE: - if (merge_list->next == NULL) - { - x1 = 0; - y1 = 0; - x2 = gimage->width; - y2 = gimage->height; - } - 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 */ - undo_push_group_start (gimage, LAYER_MERGE_UNDO); - - name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); - - if (merge_type == FLATTEN_IMAGE || - gimp_drawable_type (GIMP_DRAWABLE (layer)) == INDEXED_GIMAGE) - { - switch (gimp_image_base_type (gimage)) - { - case RGB: type = RGB_GIMAGE; break; - case GRAY: type = GRAY_GIMAGE; break; - case INDEXED: type = INDEXED_GIMAGE; break; - } - - merge_layer = gimp_layer_new (gimage, (x2 - x1), (y2 - y1), - type, - gimp_object_get_name (GIMP_OBJECT (layer)), - OPAQUE_OPACITY, NORMAL_MODE); - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* get the background for compositing */ - gimp_image_get_background (gimage, GIMP_DRAWABLE (merge_layer), bg); - - /* init the pixel region */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - gimage->width, gimage->height, - 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 (gimage, (x2 - x1), (y2 - y1), - gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), - "merged layer", - OPAQUE_OPACITY, NORMAL_MODE); - - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* Set the layer to transparent */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - (x2 - x1), (y2 - y1), - TRUE); - - /* set the region to 0's */ - color_region (&src1PR, bg); - - /* 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 = (GimpLayer *) reverse_list->data; - position = - gimp_container_num_children (gimage->layers) - - gimp_container_get_child_index (gimage->layers, GIMP_OBJECT (layer)); - - /* set the mode of the bottom layer to normal so that the contents - * aren't lost when merging with the all-alpha merge_layer - * Keep a pointer to it so that we can set the mode right after it's - * been merged so that undo works correctly. - */ - bottom_layer = layer; - bottom_mode = bottom_layer->mode; - - /* 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. - */ - if (bottom_layer->mode != DISSOLVE_MODE) - gimp_layer_set_mode (bottom_layer, NORMAL_MODE); - } - - /* Copy the tattoo and parasites of the bottom layer to the new layer */ - gimp_drawable_set_tattoo (GIMP_DRAWABLE (merge_layer), - gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer))); - GIMP_DRAWABLE (merge_layer)->parasites = - gimp_parasite_list_copy (GIMP_DRAWABLE (layer)->parasites); - - while (reverse_list) - { - layer = (GimpLayer *) reverse_list->data; - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = - valid_combinations[gimp_drawable_type (GIMP_DRAWABLE (merge_layer))][gimp_drawable_bytes (GIMP_DRAWABLE (layer))]; - - if (operation == -1) - { - g_warning ("%s: attempting to merge incompatible layers.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - x3 = CLAMP (off_x, x1, x2); - y3 = CLAMP (off_y, y1, y2); - x4 = CLAMP (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)), x1, x2); - y4 = CLAMP (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)), y1, y2); - - /* configure the pixel regions */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), - TRUE); - pixel_region_init (&src2PR, - gimp_drawable_data (GIMP_DRAWABLE (layer)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - - if (layer->mask && layer->mask->apply_mask) - { - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (layer->mask)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - mask = &maskPR; - } - else - { - mask = NULL; - } - - combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, - layer->opacity, layer->mode, active, operation); - - gimp_image_remove_layer (gimage, layer); - reverse_list = g_slist_next (reverse_list); - } - - /* Save old mode in undo */ - if (bottom_layer) - gimp_layer_set_mode (bottom_layer, bottom_mode); - - g_slist_free (reverse_list); - - /* if the type is flatten, remove all the remaining layers */ - if (merge_type == FLATTEN_IMAGE) - { - list = GIMP_LIST (gimage->layers)->list; - while (list) - { - layer = (GimpLayer *) list->data; - - list = g_list_next (list); - gimp_image_remove_layer (gimage, layer); - } - - gimp_image_add_layer (gimage, merge_layer, position); - } - else - { - /* Add the layer to the gimage */ - gimp_image_add_layer (gimage, merge_layer, - gimp_container_num_children (gimage->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_set_name (GIMP_OBJECT (merge_layer), name); - g_free (name); - - /* End the merge undo group */ - undo_push_group_end (gimage); - - gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE); - - gimp_drawable_update (GIMP_DRAWABLE (merge_layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (merge_layer)), - gimp_drawable_height (GIMP_DRAWABLE (merge_layer))); - - return merge_layer; -} - -gboolean -gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position) -{ - LayerUndo *lu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - if (GIMP_DRAWABLE (layer)->gimage != NULL && - GIMP_DRAWABLE (layer)->gimage != gimage) - { - g_warning ("%s: attempting to add layer to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - { - g_warning ("%s: trying to add layer to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Prepare a layer undo and push it */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = 0; - lu->prev_layer = gimp_image_get_active_layer (gimage); - undo_push_layer (gimage, LAYER_ADD_UNDO, lu); - - /* If the layer is a floating selection, set the ID */ - if (gimp_layer_is_floating_sel (layer)) - gimage->floating_sel = layer; - - /* let the layer know about the gimage */ - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage); - - /* If the layer has a mask, set the mask's gimage */ - if (layer->mask) - { - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage); - } - - /* add the layer to the list at the specified position */ - if (position == -1) - { - GimpLayer *active_layer; - - active_layer = gimp_image_get_active_layer (gimage); - - if (active_layer) - { - position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (active_layer)); - } - else - { - position = 0; - } - } - - /* If there is a floating selection (and this isn't it!), - * make sure the insert position is greater than 0 - */ - if (position == 0 && - gimp_image_floating_sel (gimage) && - (gimage->floating_sel != layer)) - { - position = 1; - } - - gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position); - g_object_unref (G_OBJECT (layer)); - - /* notify the layers dialog of the currently active layer */ - gimp_image_set_active_layer (gimage, layer); - - /* update the new layer's area */ - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - return TRUE; -} - -void -gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer) -{ - LayerUndo *lu; - gint x, y, w, h; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_LAYER (layer)); - - g_return_if_fail (gimp_container_have (gimage->layers, - GIMP_OBJECT (layer))); - - /* Push a layer undo */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - lu->prev_layer = layer; - - undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu); - - g_object_ref (G_OBJECT (layer)); - - gimp_container_remove (gimage->layers, GIMP_OBJECT (layer)); - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - - /* If this was the floating selection, reset the fs pointer */ - if (gimage->floating_sel == layer) - { - gimage->floating_sel = NULL; - - floating_sel_reset (layer); - } - - if (layer == gimp_image_get_active_layer (gimage)) - { - if (gimage->layer_stack) - { - gimp_image_set_active_layer (gimage, gimage->layer_stack->data); - } - else - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* Send out REMOVED signal from layer */ - gimp_drawable_removed (GIMP_DRAWABLE (layer)); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &x, &y); - w = gimp_drawable_width (GIMP_DRAWABLE (layer)); - h = gimp_drawable_height (GIMP_DRAWABLE (layer)); - - g_object_unref (G_OBJECT (layer)); - - gimp_image_update (gimage, x, y, w, h); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -gboolean -gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == 0) - { - g_message (_("Channel cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index - 1, TRUE); -} - -gboolean -gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == gimp_container_num_children (gimage->channels) - 1) - { - g_message (_("Channel cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index + 1, TRUE); -} - -gboolean -gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo /* FIXME unused */) -{ - gint index; - gint num_channels; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index < 0) - return FALSE; - - num_channels = gimp_container_num_children (gimage->channels); - - new_index = CLAMP (new_index, 0, num_channels - 1); - - if (new_index == index) - return TRUE; - - gimp_container_reorder (gimage->channels, - GIMP_OBJECT (channel), new_index); - - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -gboolean -gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position) -{ - ChannelUndo *cu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - if (GIMP_DRAWABLE (channel)->gimage != NULL && - GIMP_DRAWABLE (channel)->gimage != gimage) - { - g_warning ("%s: attempting to add channel to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - { - g_warning ("%s: trying to add channel to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Push a channel undo */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = 0; - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu); - - /* add the channel to the list */ - gimp_container_add (gimage->channels, GIMP_OBJECT (channel)); - g_object_unref (G_OBJECT (channel)); - - /* notify this gimage of the currently active channel */ - gimp_image_set_active_channel (gimage, channel); - - /* if channel is visible, update the image */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -void -gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel) -{ - ChannelUndo *cu; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_CHANNEL (channel)); - - g_return_if_fail (gimp_container_have (gimage->channels, - GIMP_OBJECT (channel))); - - /* Prepare a channel undo--push it below */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu); - - g_object_ref (G_OBJECT (channel)); - - gimp_container_remove (gimage->channels, GIMP_OBJECT (channel)); - - /* Send out REMOVED signal from channel */ - gimp_drawable_removed (GIMP_DRAWABLE (channel)); - - if (channel == gimp_image_get_active_channel (gimage)) - { - if (gimp_container_num_children (gimage->channels) > 0) - { - gimp_image_set_active_channel - (gimage, - GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels, - 0))); - } - else - { - gimp_image_unset_active_channel (gimage); - } - } - - g_object_unref (G_OBJECT (channel)); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -/************************************************************/ -/* Access functions */ -/************************************************************/ - -gboolean -gimp_image_is_empty (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE); - - return (gimp_container_num_children (gimage->layers) == 0); -} - -GimpDrawable * -gimp_image_active_drawable (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* If there is an active channel (a saved selection, etc.), - * we ignore the active layer - */ - if (gimage->active_channel) - { - return GIMP_DRAWABLE (gimage->active_channel); - } - else if (gimage->active_layer) - { - GimpLayer *layer; - - layer = gimage->active_layer; - - if (layer->mask && layer->mask->edit_mask) - return GIMP_DRAWABLE (layer->mask); - else - return GIMP_DRAWABLE (layer); - } - - return NULL; -} - -GimpImageBaseType -gimp_image_base_type (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->base_type; -} - -GimpImageType -gimp_image_base_type_with_alpha (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - switch (gimage->base_type) - { - case RGB: - return RGBA_GIMAGE; - case GRAY: - return GRAYA_GIMAGE; - case INDEXED: - return INDEXEDA_GIMAGE; - } - return RGB_GIMAGE; -} - -const gchar * -gimp_image_filename (const GimpImage *gimage) -{ - const gchar *filename; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - filename = gimp_object_get_name (GIMP_OBJECT (gimage)); - - return filename ? filename : _("Untitled"); -} - -gboolean -gimp_image_undo_is_enabled (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->undo_on; -} - -gboolean -gimp_image_undo_freeze (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = FALSE; - - return TRUE; -} - -gboolean -gimp_image_undo_thaw (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = TRUE; - - return TRUE; -} - -gboolean -gimp_image_undo_disable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimp_image_undo_freeze (gimage); -} - -gboolean -gimp_image_undo_enable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - /* Free all undo steps as they are now invalidated */ - undo_free (gimage); - - return gimp_image_undo_thaw (gimage); -} - -void -gimp_image_undo_event (GimpImage *gimage, - gint event) -{ - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], 0, - event); -} - - -/* NOTE about the gimage->dirty counter: - * If 0, then the image is clean (ie, copy on disk is the same as the one - * in memory). - * If positive, then that's the number of dirtying operations done - * on the image since the last save. - * If negative, then user has hit undo and gone back in time prior - * to the saved copy. Hitting redo will eventually come back to - * the saved copy. - * - * The image is dirty (ie, needs saving) if counter is non-zero. - * - * If the counter is around 10000, this is due to undo-ing back - * before a saved version, then mutating the image (thus destroying - * the redo stack). Once this has happened, it's impossible to get - * the image back to the state on disk, since the redo info has been - * freed. See undo.c for the gorey details. - */ - - -/* - * NEVER CALL gimp_image_dirty() directly! - * - * If your code has just dirtied the image, push an undo instead. - * Failing that, push the trivial undo which tells the user the - * command is not undoable: undo_push_cantundo() (But really, it would - * be best to push a proper undo). If you just dirty the image - * without pushing an undo then the dirty count is increased, but - * popping that many undo actions won't lead to a clean image. - */ - -gint -gimp_image_dirty (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty++; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[DIRTY], 0); - - TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty)); - - return gimage->dirty; -} - -gint -gimp_image_clean (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty--; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); - - TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty)); - - return gimage->dirty; -} - -void -gimp_image_clean_all (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->dirty = 0; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); -} - -GimpLayer * -gimp_image_floating_sel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - if (gimage->floating_sel == NULL) - return NULL; - else - return gimage->floating_sel; -} - -guchar * -gimp_image_cmap (const GimpImage *gimage) -{ - return gimp_drawable_cmap (gimp_image_active_drawable (gimage)); -} - -static TempBuf * -gimp_image_get_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - - gimage = GIMP_IMAGE (viewable); - - if (gimage->comp_preview_valid && - gimage->comp_preview->width == width && - gimage->comp_preview->height == height) - { - /* The easy way */ - return gimage->comp_preview; - } - else - { - /* The hard way */ - if (gimage->comp_preview) - temp_buf_free (gimage->comp_preview); - - /* Actually construct the composite preview from the layer previews! - * This might seem ridiculous, but it's actually the best way, given - * a number of unsavory alternatives. - */ - gimage->comp_preview = gimp_image_get_new_preview (viewable, - width, height); - - gimage->comp_preview_valid = TRUE; - - return gimage->comp_preview; - } -} - -static TempBuf * -gimp_image_get_new_preview (GimpViewable *viewable, - gint width, - gint height) -{ - GimpImage *gimage; - GimpLayer *layer; - GimpLayer *floating_sel; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - TempBuf *comp; - TempBuf *layer_buf; - TempBuf *mask_buf; - GList *list; - GSList *reverse_list = NULL; - gdouble ratio; - gint x, y, w, h; - gint x1, y1, x2, y2; - gint bytes; - gboolean construct_flag; - gint visible[MAX_CHANNELS] = { 1, 1, 1, 1 }; - gint off_x, off_y; - - gimage = GIMP_IMAGE (viewable); - - ratio = (gdouble) width / (gdouble) gimage->width; - - switch (gimp_image_base_type (gimage)) - { - case RGB: - case INDEXED: - bytes = 4; - break; - case GRAY: - bytes = 2; - break; - default: - bytes = 0; - break; - } - - /* The construction buffer */ - comp = temp_buf_new (width, height, bytes, 0, 0, NULL); - temp_buf_data_clear (comp); - - floating_sel = NULL; - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - /* only add layers that are visible to the list */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - { - /* floating selections are added right above the layer - * they are attached to - */ - if (gimp_layer_is_floating_sel (layer)) - { - floating_sel = layer; - } - else - { - if (floating_sel && - floating_sel->fs.drawable == GIMP_DRAWABLE (layer)) - { - reverse_list = g_slist_prepend (reverse_list, floating_sel); - } - - reverse_list = g_slist_prepend (reverse_list, layer); - } - } - } - - construct_flag = FALSE; - - for (; reverse_list; reverse_list = g_slist_next (reverse_list)) - { - layer = (GimpLayer *) reverse_list->data; - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - x = (gint) RINT (ratio * off_x); - y = (gint) RINT (ratio * off_y); - w = (gint) RINT (ratio * gimp_drawable_width (GIMP_DRAWABLE (layer))); - h = (gint) RINT (ratio * gimp_drawable_height (GIMP_DRAWABLE (layer))); - - if (w < 1 || h < 1) - continue; - - x1 = CLAMP (x, 0, width); - y1 = CLAMP (y, 0, height); - x2 = CLAMP (x + w, 0, width); - y2 = CLAMP (y + h, 0, height); - - src1PR.bytes = comp->bytes; - src1PR.x = x1; - src1PR.y = y1; - src1PR.w = (x2 - x1); - src1PR.h = (y2 - y1); - src1PR.rowstride = comp->width * src1PR.bytes; - src1PR.data = (temp_buf_data (comp) + - y1 * src1PR.rowstride + x1 * src1PR.bytes); - - layer_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h); - src2PR.bytes = layer_buf->bytes; - src2PR.w = src1PR.w; - src2PR.h = src1PR.h; - src2PR.x = src1PR.x; - src2PR.y = src1PR.y; - src2PR.rowstride = layer_buf->width * src2PR.bytes; - src2PR.data = (temp_buf_data (layer_buf) + - (y1 - y) * src2PR.rowstride + - (x1 - x) * src2PR.bytes); - - if (layer->mask && layer->mask->apply_mask) - { - mask_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer->mask), - w, h); - maskPR.bytes = mask_buf->bytes; - maskPR.rowstride = mask_buf->width; - maskPR.data = (mask_buf_data (mask_buf) + - (y1 - y) * maskPR.rowstride + - (x1 - x) * maskPR.bytes); - mask = &maskPR; - } - else - { - mask = NULL; - } - - /* Based on the type of the layer, project the layer onto the - * composite preview... - * Indexed images are actually already converted to RGB and RGBA, - * so just project them as if they were type "intensity" - * Send in all TRUE for visible since that info doesn't matter - * for previews - */ - switch (gimp_drawable_type (GIMP_DRAWABLE (layer))) - { - case RGB_GIMAGE: case GRAY_GIMAGE: case INDEXED_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN); - break; - - case RGBA_GIMAGE: case GRAYA_GIMAGE: case INDEXEDA_GIMAGE: - if (! construct_flag) - initial_region (&src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, INITIAL_INTENSITY_ALPHA); - else - combine_regions (&src1PR, &src2PR, &src1PR, - mask, NULL, layer->opacity, - layer->mode, visible, COMBINE_INTEN_A_INTEN_A); - break; - - default: - break; - } - - construct_flag = TRUE; - } - - g_slist_free (reverse_list); - - return comp; -} diff --git a/app/core/gimpimage-scale.h b/app/core/gimpimage-scale.h index be0b5eea83..7c09401a66 100644 --- a/app/core/gimpimage-scale.h +++ b/app/core/gimpimage-scale.h @@ -16,425 +16,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __GIMP_IMAGE_H__ -#define __GIMP_IMAGE_H__ +#ifndef __GIMP_IMAGE_SCALE_H__ +#define __GIMP_IMAGE_SCALE_H__ -#include "gimpviewable.h" +void gimp_image_scale (GimpImage *gimage, + gint new_width, + gint new_height, + GimpProgressFunc progress_func, + gpointer progress_data); +gboolean gimp_image_check_scaling (const GimpImage *gimage, + gint new_width, + gint new_height); -#define COLORMAP_SIZE 768 -#define GIMP_IMAGE_TYPE_HAS_ALPHA(t) ((t) == RGBA_GIMAGE || \ - (t) == GRAYA_GIMAGE || \ - (t) == INDEXEDA_GIMAGE) - - -struct _GimpGuide -{ - gint ref_count; - gint position; - InternalOrientationType orientation; - guint32 guide_ID; -}; - - -#define GIMP_TYPE_IMAGE (gimp_image_get_type ()) -#define GIMP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_IMAGE, GimpImage)) -#define GIMP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_IMAGE, GimpImageClass)) -#define GIMP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_IMAGE)) -#define GIMP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_IMAGE)) -#define GIMP_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_IMAGE, GimpImageClass)) - - -typedef struct _GimpImageClass GimpImageClass; - -struct _GimpImage -{ - GimpViewable parent_instance; - - Gimp *gimp; /* the GIMP the image belongs to*/ - - gint ID; /* provides a unique ID */ - - PlugInProcDef *save_proc; /* last PDB save proc used */ - - gint width, height; /* width and height attributes */ - gdouble xresolution; /* image x-res, in dpi */ - gdouble yresolution; /* image y-res, in dpi */ - GimpUnit unit; /* image unit */ - GimpImageBaseType base_type; /* base gimp_image type */ - - guchar *cmap; /* colormap--for indexed */ - gint num_cols; /* number of cols--for indexed */ - - gint dirty; /* dirty flag -- # of ops */ - gboolean undo_on; /* Is undo enabled? */ - - gint instance_count; /* number of instances */ - gint disp_count; /* number of displays */ - - GimpTattoo tattoo_state; /* the next unique tattoo to use*/ - - TileManager *shadow; /* shadow buffer tiles */ - - /* Projection attributes */ - gboolean construct_flag; /* flag for construction */ - GimpImageType proj_type; /* type of the projection image */ - gint proj_bytes; /* bpp in projection image */ - gint proj_level; /* projection level */ - TileManager *projection; /* The projection--layers & */ - /* channels */ - - GList *guides; /* guides */ - - /* Layer/Channel attributes */ - GimpContainer *layers; /* the list of layers */ - GimpContainer *channels; /* the list of masks */ - GSList *layer_stack; /* the layers in MRU order */ - - GimpLayer *active_layer; /* the active layer */ - GimpChannel *active_channel; /* the active channel */ - GimpLayer *floating_sel; /* the FS layer */ - GimpChannel *selection_mask; /* the selection mask channel */ - - GimpParasiteList *parasites; /* Plug-in parasite data */ - - PathList *paths; /* Paths data for this image */ - - gboolean visible[MAX_CHANNELS]; /* visible channels */ - gboolean active[MAX_CHANNELS]; /* active channels */ - - gboolean qmask_state; /* TRUE if qmask is on */ - GimpRGB qmask_color; /* rgba triplet of the color */ - - /* Old undo apparatus */ - GSList *undo_stack; /* stack for undo operations */ - GSList *redo_stack; /* stack for redo operations */ - gint undo_bytes; /* bytes in undo stack */ - gint undo_levels; /* levels in undo stack */ - gint group_count; /* nested undo groups */ - UndoType pushing_undo_group; /* undo group status flag */ - - /* New undo apparatus */ - GimpUndoStack *new_undo_stack; /* stack for undo operations */ - GimpUndoStack *new_redo_stack; /* stack for redo operations */ - - /* Composite preview */ - TempBuf *comp_preview; /* the composite preview */ - gboolean comp_preview_valid; /* preview valid-1/channel */ -}; - -struct _GimpImageClass -{ - GimpViewableClass parent_class; - - void (* mode_changed) (GimpImage *gimage); - void (* alpha_changed) (GimpImage *gimage); - void (* floating_selection_changed) (GimpImage *gimage); - void (* active_layer_changed) (GimpImage *gimage); - void (* active_channel_changed) (GimpImage *gimage); - void (* component_visibility_changed) (GimpImage *gimage, - ChannelType channel); - void (* component_active_changed) (GimpImage *gimage, - ChannelType channel); - void (* mask_changed) (GimpImage *gimage); - void (* resolution_changed) (GimpImage *gimage); - void (* unit_changed) (GimpImage *gimage); - void (* qmask_changed) (GimpImage *gimage); - void (* selection_control) (GimpImage *gimage, - GimpSelectionControl control); - - void (* clean) (GimpImage *gimage); - void (* dirty) (GimpImage *gimage); - void (* update) (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); - void (* update_guide) (GimpImage *gimage, - GimpGuide *guide); - void (* colormap_changed) (GimpImage *gimage, - gint color_index); - void (* undo_event) (GimpImage *gimage, - gint event); - - void (* undo) (GimpImage *gimage); - void (* redo) (GimpImage *gimage); -}; - - -/* function declarations */ - -GType gimp_image_get_type (void) G_GNUC_CONST; - -GimpImage * gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type); - -gint gimp_image_get_ID (GimpImage *gimage); -GimpImage * gimp_image_get_by_ID (Gimp *gimp, - gint id); - -void gimp_image_set_filename (GimpImage *gimage, - const gchar *filename); -void gimp_image_set_resolution (GimpImage *gimage, - gdouble xres, - gdouble yres); -void gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution); -void gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit); -GimpUnit gimp_image_get_unit (const GimpImage *gimage); - -void gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state); -gboolean gimp_image_get_qmask_state (const GimpImage *gimage); - -void gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc); -PlugInProcDef * gimp_image_get_save_proc (const GimpImage *gimage); - -gint gimp_image_get_width (const GimpImage *gimage); -gint gimp_image_get_height (const GimpImage *gimage); - -void gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y); -void gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data); -gboolean gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height); - -TileManager * gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); -void gimp_image_free_shadow (GimpImage *gimage); - -void gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - TileManager *src1_tiles, - gint x, - gint y); -void gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y); - -void gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg); -void gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg); -void gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src); -void gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type); - -GimpGuide * gimp_image_add_hguide (GimpImage *gimage); -GimpGuide * gimp_image_add_vguide (GimpImage *gimage); -void gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide); -GimpGuide * gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty); -gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1); - -GimpParasite * gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name); -gchar ** gimp_image_parasite_list (const GimpImage *gimage, - gint *count); -void gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite); -void gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite); - -GimpTattoo gimp_image_get_new_tattoo (GimpImage *gimage); -gboolean gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val); -GimpTattoo gimp_image_get_tattoo_state (GimpImage *gimage); - -void gimp_image_set_paths (GimpImage *gimage, - PathList *paths); -PathList * gimp_image_get_paths (const GimpImage *gimage); - -/* Temporary hack till colormap manipulation is encapsulated in functions. - * Call this whenever you modify an image's colormap. The col argument - * specifies which color has changed, or negative if there's a bigger change. - * Currently, use this also when the image's base type is changed to/from - * indexed. - */ -void gimp_image_colormap_changed (GimpImage *gimage, - gint col); - -void gimp_image_mode_changed (GimpImage *gimage); -void gimp_image_alpha_changed (GimpImage *gimage); -void gimp_image_floating_selection_changed (GimpImage *gimage); -void gimp_image_mask_changed (GimpImage *gimage); -void gimp_image_resolution_changed (GimpImage *gimage); -void gimp_image_unit_changed (GimpImage *gimage); -void gimp_image_qmask_changed (GimpImage *gimage); -void gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); -void gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control); - - -/* layer/channel functions */ - -GimpContainer * gimp_image_get_layers (const GimpImage *gimage); -GimpContainer * gimp_image_get_channels (const GimpImage *gimage); - -gint gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer); -gint gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel); -GimpLayer * gimp_image_get_active_layer (const GimpImage *gimage); -GimpChannel * gimp_image_get_active_channel (const GimpImage *gimage); -GimpLayer * gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name); -GimpChannel * gimp_image_get_mask (const GimpImage *gimage); - -void gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active); -gboolean gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type); -void gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active); - -void gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible); -gboolean gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type); - -gboolean gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs); -GimpLayer * gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer); -GimpChannel * gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel); -GimpChannel * gimp_image_unset_active_channel (GimpImage *gimage); -GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo); -GimpLayer * gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type); -GimpLayer * gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type); -GimpLayer * gimp_image_flatten (GimpImage *gimage); -GimpLayer * gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type); -gboolean gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position); -void gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo); -gboolean gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position); -void gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel); - -void gimp_image_invalidate_layer_previews (GimpImage *gimage); -void gimp_image_invalidate_channel_previews (GimpImage *gimage); - - -/* Access functions */ - -gboolean gimp_image_is_empty (const GimpImage *gimage); -GimpDrawable * gimp_image_active_drawable (const GimpImage *gimage); - -GimpImageBaseType gimp_image_base_type (const GimpImage *gimage); -GimpImageType gimp_image_base_type_with_alpha (const GimpImage *gimage); - -const gchar * gimp_image_filename (const GimpImage *gimage); -gboolean gimp_image_undo_is_enabled (const GimpImage *gimage); -gboolean gimp_image_undo_enable (GimpImage *gimage); -gboolean gimp_image_undo_disable (GimpImage *gimage); -gboolean gimp_image_undo_freeze (GimpImage *gimage); -gboolean gimp_image_undo_thaw (GimpImage *gimage); -void gimp_image_undo_event (GimpImage *gimage, - gint event); -gint gimp_image_dirty (GimpImage *gimage); -gint gimp_image_clean (GimpImage *gimage); -void gimp_image_clean_all (GimpImage *gimage); -GimpLayer * gimp_image_floating_sel (const GimpImage *gimage); -guchar * gimp_image_cmap (const GimpImage *gimage); - -gboolean gimp_image_preview_valid (const GimpImage *gimage); - - -#endif /* __GIMP_IMAGE_H__ */ +#endif /* __GIMP_IMAGE_SCALE_H__ */ diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index f0184430e9..150b7c1d84 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -39,6 +39,7 @@ #include "core/gimpcontext.h" #include "core/gimpcoreconfig.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" #include "core/gimpimage-projection.h" #include "core/gimplayer.h" diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index cd786391e4..ec29f0c2bf 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -63,8 +63,6 @@ #define TRC(x) #endif -#define GUIDE_EPSILON 5 - enum { @@ -100,24 +98,20 @@ static void gimp_image_dispose (GObject *object); static void gimp_image_finalize (GObject *object); static void gimp_image_name_changed (GimpObject *object); + static void gimp_image_invalidate_preview (GimpViewable *viewable); static void gimp_image_size_changed (GimpViewable *viewable); -static void gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol); static TempBuf *gimp_image_get_preview (GimpViewable *gimage, gint width, gint height); static TempBuf *gimp_image_get_new_preview (GimpViewable *viewable, gint width, gint height); -static void gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); -/* - * Static variables - */ +static void gimp_image_real_colormap_changed (GimpImage *gimage, + gint ncol); + + static gint valid_combinations[][MAX_CHANNELS + 1] = { /* RGB GIMAGE */ @@ -167,6 +161,9 @@ gimp_image_get_type (void) return image_type; } + +/* private functions */ + static void gimp_image_class_init (GimpImageClass *klass) { @@ -383,9 +380,6 @@ gimp_image_class_init (GimpImageClass *klass) gimp_image_color_hash_init (); } - -/* static functions */ - static void gimp_image_init (GimpImage *gimage) { @@ -593,3068 +587,6 @@ gimp_image_size_changed (GimpViewable *viewable) gimp_image_invalidate_channel_previews (gimage); } -static void -gimp_image_real_colormap_changed (GimpImage *gimage, - gint ncol) -{ - if (gimp_image_base_type (gimage) == INDEXED) - gimp_image_color_hash_invalidate (gimage, ncol); -} - -static void -gimp_image_allocate_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - /* allocate the new projection */ - gimage->shadow = tile_manager_new (width, height, bpp); -} - - -/* function definitions */ - -GimpImage * -gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type) -{ - GimpImage *gimage; - gint i; - - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - gimage = GIMP_IMAGE (g_object_new (GIMP_TYPE_IMAGE, NULL)); - - gimage->gimp = gimp; - gimage->ID = gimp->next_image_ID++; - - g_hash_table_insert (gimp->image_table, - GINT_TO_POINTER (gimage->ID), - (gpointer) gimage); - - gimage->width = width; - gimage->height = height; - gimage->base_type = base_type; - - gimage->xresolution = gimp->config->default_xresolution; - gimage->yresolution = gimp->config->default_yresolution; - gimage->unit = gimp->config->default_units; - - switch (base_type) - { - case RGB: - case GRAY: - break; - case INDEXED: - /* always allocate 256 colors for the colormap */ - gimage->num_cols = 0; - gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE); - break; - default: - break; - } - - /* set all color channels visible and active */ - for (i = 0; i < MAX_CHANNELS; i++) - { - gimage->visible[i] = TRUE; - gimage->active[i] = TRUE; - } - - /* create the selection mask */ - gimage->selection_mask = gimp_channel_new_mask (gimage, - gimage->width, - gimage->height); - - - return gimage; -} - -gint -gimp_image_get_ID (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->ID; -} - -GimpImage * -gimp_image_get_by_ID (Gimp *gimp, - gint image_id) -{ - g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); - - if (gimp->image_table == NULL) - return NULL; - - return (GimpImage *) g_hash_table_lookup (gimp->image_table, - GINT_TO_POINTER (image_id)); -} - -void -gimp_image_set_filename (GimpImage *gimage, - const gchar *filename) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_object_set_name (GIMP_OBJECT (gimage), filename); -} - -void -gimp_image_set_resolution (GimpImage *gimage, - gdouble xresolution, - gdouble yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* don't allow to set the resolution out of bounds */ - if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION || - yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION) - return; - - if ((ABS (gimage->xresolution - xresolution) >= 1e-5) || - (ABS (gimage->yresolution - yresolution) >= 1e-5)) - { - undo_push_resolution (gimage); - - gimage->xresolution = xresolution; - gimage->yresolution = yresolution; - - gimp_image_resolution_changed (gimage); - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - } -} - -void -gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (xresolution && yresolution); - - *xresolution = gimage->xresolution; - *yresolution = gimage->yresolution; -} - -void -gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->unit != unit) - { - undo_push_resolution (gimage); - - gimage->unit = unit; - - gimp_image_unit_changed (gimage); - } -} - -GimpUnit -gimp_image_get_unit (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_UNIT_INCH); - - return gimage->unit; -} - -void -gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (qmask_state != gimage->qmask_state) - { - gimage->qmask_state = qmask_state ? TRUE : FALSE; - - gimp_image_qmask_changed (gimage); - } -} - -gboolean -gimp_image_get_qmask_state (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->qmask_state; -} - -void -gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->save_proc = proc; -} - -PlugInProcDef * -gimp_image_get_save_proc (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->save_proc; -} - -gint -gimp_image_get_width (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->width; -} - -gint -gimp_image_get_height (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->height; -} - -void -gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GList *guide_list; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_RESIZE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - gimage->width = new_width; - gimage->height = new_height; - - /* Resize all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y); - } - - /* Reposition or remove any guides */ - guide_list = gimage->guides; - while (guide_list) - { - GimpGuide *guide; - - guide = (GimpGuide *) guide_list->data; - guide_list = g_list_next (guide_list); - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position += offset_y; - if (guide->position < 0 || guide->position > new_height) - gimp_image_delete_guide (gimage, guide); - break; - - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position += offset_x; - if (guide->position < 0 || guide->position > new_width) - gimp_image_delete_guide (gimage, guide); - break; - - default: - g_error ("Unknown guide orientation\n"); - } - } - - /* Don't forget the selection mask! */ - gimp_channel_resize (gimage->selection_mask, - new_width, new_height, offset_x, offset_y); - gimage_mask_invalidate (gimage); - - /* Reposition all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - gimp_layer_translate (layer, offset_x, offset_y); - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -void -gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data) -{ - GimpChannel *channel; - GimpLayer *layer; - GimpLayer *floating_layer; - GList *list; - GSList *remove = NULL; - GSList *slist; - GimpGuide *guide; - gint old_width; - gint old_height; - gdouble img_scale_w = 1.0; - gdouble img_scale_h = 1.0; - gint num_channels; - gint num_layers; - gint progress_current = 1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (new_width > 0 && new_height > 0); - - gimp_set_busy (gimage->gimp); - - num_channels = gimage->channels->num_children; - num_layers = gimage->layers->num_children; - - /* Get the floating layer if one exists */ - floating_layer = gimp_image_floating_sel (gimage); - - undo_push_group_start (gimage, IMAGE_SCALE_UNDO); - - /* Relax the floating selection */ - if (floating_layer) - floating_sel_relax (floating_layer, TRUE); - - /* Push the image size to the stack */ - undo_push_gimage_mod (gimage); - - /* Set the new width and height */ - - old_width = gimage->width; - old_height = gimage->height; - gimage->width = new_width; - gimage->height = new_height; - img_scale_w = (gdouble) new_width / (gdouble) old_width; - img_scale_h = (gdouble) new_height / (gdouble) old_height; - - /* Scale all channels */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - gimp_channel_scale (channel, new_width, new_height); - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* Don't forget the selection mask! */ - /* if (channel_is_empty(gimage->selection_mask)) - gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0) - else - */ - - gimp_channel_scale (gimage->selection_mask, new_width, new_height); - gimage_mask_invalidate (gimage); - - /* Scale all layers */ - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h)) - { - /* Since 0 < img_scale_w, img_scale_h, failure due to one or more - * vanishing scaled layer dimensions. Implicit delete implemented - * here. Upstream warning implemented in resize_check_layer_scaling() - * [resize.c line 1295], which offers the user the chance to bail out. - */ - remove = g_slist_append (remove, layer); - } - - if (progress_func) - { - (* progress_func) (0, num_channels + num_layers, - progress_current++, - progress_data); - } - } - - /* We defer removing layers lost to scaling until now so as not to mix - * the operations of iterating over and removal from gimage->layers. - */ - for (slist = remove; slist; slist = g_slist_next (slist)) - { - layer = slist->data; - gimp_image_remove_layer (gimage, layer); - } - g_slist_free (remove); - - /* Scale any Guides */ - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_height) / old_height; - break; - case ORIENTATION_VERTICAL: - undo_push_guide (gimage, guide); - guide->position = (guide->position * new_width) / old_width; - break; - default: - g_error("Unknown guide orientation II.\n"); - } - } - - /* Make sure the projection matches the gimage size */ - gimp_image_projection_allocate (gimage); - - /* Rigor the floating selection */ - if (floating_layer) - floating_sel_rigor (floating_layer, TRUE); - - undo_push_group_end (gimage); - - gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); - - gimp_unset_busy (gimage->gimp); -} - -/** - * gimp_image_check_scaling: - * @gimage: A #GimpImage. - * @new_width: The new width. - * @new_height: The new height. - * - * Inventory the layer list in gimage and return #TRUE if, after - * scaling, they all retain positive x and y pixel dimensions. - * - * Return value: #TRUE if scaling the image will shrink none of it's - * layers completely away. - **/ -gboolean -gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height) -{ - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpLayer *layer; - - layer = (GimpLayer *) list->data; - - if (! gimp_layer_check_scaling (layer, new_width, new_height)) - return FALSE; - } - - return TRUE; -} - -TileManager * -gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (gimage->shadow && - ((width != tile_manager_width (gimage->shadow)) || - (height != tile_manager_height (gimage->shadow)) || - (bpp != tile_manager_bpp (gimage->shadow)))) - gimp_image_free_shadow (gimage); - else if (gimage->shadow) - return gimage->shadow; - - gimp_image_allocate_shadow (gimage, width, height, bpp); - - return gimage->shadow; -} - -void -gimp_image_free_shadow (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (gimage->shadow) - { - tile_manager_destroy (gimage->shadow); - gimage->shadow = NULL; - } -} - -void -gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - /* alternative to using drawable tiles as src1: */ - TileManager *src1_tiles, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR, maskPR; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations[gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - if (src1_tiles) - pixel_region_init (&src1PR, src1_tiles, - x1, y1, (x2 - x1), (y2 - y1), FALSE); - else - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - gint mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL, - opacity, mode, active, operation); - } - else - { - combine_regions (&src1PR, src2PR, &destPR, NULL, NULL, - opacity, mode, active, operation); - } -} - -/* Similar to gimp_image_apply_image but works in "replace" mode (i.e. - transparent pixels in src2 make the result transparent rather - than opaque. - - Takes an additional mask pixel region as well. -*/ -void -gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y) -{ - GimpChannel *mask; - gint x1, y1, x2, y2; - gint offset_x, offset_y; - PixelRegion src1PR, destPR; - PixelRegion mask2PR, tempPR; - guchar *temp_data; - gint operation; - gint active [MAX_CHANNELS]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - /* get the selection mask if one exists */ - mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); - - /* configure the active channel array */ - gimp_image_get_active_components (gimage, drawable, active); - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = valid_combinations [gimp_drawable_type (drawable)][src2PR->bytes]; - if (operation == -1) - { - g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); - return; - } - - /* get the layer offsets */ - gimp_drawable_offsets (drawable, &offset_x, &offset_y); - - /* make sure the image application coordinates are within gimage bounds */ - x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); - y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); - x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); - y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); - - if (mask) - { - /* make sure coordinates are in mask bounds ... - * we need to add the layer offset to transform coords - * into the mask coordinate system - */ - x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); - y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); - } - - /* If the calling procedure specified an undo step... */ - if (undo) - gimp_drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE); - - /* configure the pixel regions - * If an alternative to using the drawable's data as src1 was provided... - */ - pixel_region_init (&src1PR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, gimp_drawable_data (drawable), - x1, y1, (x2 - x1), (y2 - y1), TRUE); - pixel_region_resize (src2PR, - src2PR->x + (x1 - x), src2PR->y + (y1 - y), - (x2 - x1), (y2 - y1)); - - if (mask) - { - int mx, my; - - /* configure the mask pixel region - * don't use x1 and y1 because they are in layer - * coordinate system. Need mask coordinate system - */ - mx = x1 + offset_x; - my = y1 + offset_y; - - pixel_region_init (&mask2PR, - gimp_drawable_data (GIMP_DRAWABLE (mask)), - mx, my, - (x2 - x1), (y2 - y1), - FALSE); - - tempPR.bytes = 1; - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.rowstride = tempPR.w * tempPR.bytes; - temp_data = g_malloc (tempPR.h * tempPR.rowstride); - tempPR.data = temp_data; - - copy_region (&mask2PR, &tempPR); - - /* apparently, region operations can mutate some PR data. */ - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); - - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; - tempPR.data = temp_data; - - combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, - opacity, active, operation); - - g_free (temp_data); - } - else - { - combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL, - opacity, active, operation); - } -} - -/* Get rid of these! A "foreground" is an UI concept.. */ - -void -gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg) -{ - GimpRGB color; - guchar pfg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (fg != NULL); - - gimp_context_get_foreground (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]); - - gimp_image_transform_color (gimage, drawable, pfg, fg, RGB); -} - -void -gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg) -{ - GimpRGB color; - guchar pbg[3]; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); - g_return_if_fail (bg != NULL); - - gimp_context_get_background (gimp_get_current_context (gimage->gimp), &color); - - gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]); - - gimp_image_transform_color (gimage, drawable, pbg, bg, RGB); -} - -void -gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - map_to_color (0, NULL, src, rgb); - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - map_to_color (1, NULL, src, rgb); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - map_to_color (2, gimage->cmap, src, rgb); - break; - } -} - -void -gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type) -{ - GimpImageType d_type; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - d_type = (drawable != NULL) ? gimp_drawable_type (drawable) : - gimp_image_base_type_with_alpha (gimage); - - switch (type) - { - case RGB: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Straight copy */ - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* NTSC conversion */ - *dest = INTENSITY (src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[RED_PIX], - src[GREEN_PIX], - src[BLUE_PIX]); - break; - } - break; - case GRAY: - switch (d_type) - { - case RGB_GIMAGE: case RGBA_GIMAGE: - /* Gray to RG&B */ - *dest++ = *src; - *dest++ = *src; - *dest++ = *src; - break; - case GRAY_GIMAGE: case GRAYA_GIMAGE: - /* Straight copy */ - *dest = *src; - break; - case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: - /* Least squares method */ - *dest = gimp_image_color_hash_rgb_to_indexed (gimage, - src[GRAY_PIX], - src[GRAY_PIX], - src[GRAY_PIX]); - break; - } - break; - default: - break; - } -} - -GimpGuide * -gimp_image_add_hguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_HORIZONTAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -GimpGuide * -gimp_image_add_vguide (GimpImage *gimage) -{ - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - guide = g_new (GimpGuide, 1); - - guide->ref_count = 0; - guide->position = -1; - guide->guide_ID = gimage->gimp->next_guide_ID++; - guide->orientation = ORIENTATION_VERTICAL; - - gimage->guides = g_list_prepend (gimage->guides, guide); - - return guide; -} - -void -gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_prepend (gimage->guides, guide); -} - -void -gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->guides = g_list_remove (gimage->guides, guide); -} - -void -gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide) -{ - guide->position = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - if (guide->ref_count <= 0) - { - gimage->guides = g_list_remove (gimage->guides, guide); - g_free (guide); - } -} - -GimpGuide * -gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y) -{ - GList *list; - GimpGuide *guide; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return NULL; - } - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - if (guide->position < 0) - continue; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - if (ABS (guide->position - y) < GUIDE_EPSILON) - return guide; - break; - - case ORIENTATION_VERTICAL: - if (ABS (guide->position - x) < GUIDE_EPSILON) - return guide; - break; - - default: - break; - } - } - - return NULL; -} - -gboolean -gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty) -{ - GList *list; - GimpGuide *guide; - gint minxdist, minydist; - gint dist; - gboolean snapped = FALSE; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx != NULL, FALSE); - g_return_val_if_fail (ty != NULL, FALSE); - - *tx = x; - *ty = y; - - if (x < 0 || x >= gimage->width || - y < 0 || y >= gimage->height) - { - return FALSE; - } - - minxdist = G_MAXINT; - minydist = G_MAXINT; - - for (list = gimage->guides; list; list = g_list_next (list)) - { - guide = (GimpGuide *) list->data; - - switch (guide->orientation) - { - case ORIENTATION_HORIZONTAL: - dist = ABS (guide->position - y); - - if (dist < MIN (GUIDE_EPSILON, minydist)) - { - minydist = dist; - *ty = guide->position; - snapped = TRUE; - } - break; - - case ORIENTATION_VERTICAL: - dist = ABS (guide->position - x); - - if (dist < MIN (GUIDE_EPSILON, minxdist)) - { - minxdist = dist; - *tx = guide->position; - snapped = TRUE; - } - break; - - default: - break; - } - } - - return snapped; -} - -gboolean -gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1) -{ - gint nx1, ny1; - gint nx2, ny2; - gboolean snap1, snap2; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (tx1 != NULL, FALSE); - g_return_val_if_fail (ty1 != NULL, FALSE); - - *tx1 = x1; - *ty1 = y1; - - snap1 = gimp_image_snap_point (gimage, x1, y1, &nx1, &ny1); - snap2 = gimp_image_snap_point (gimage, x2, y2, &nx2, &ny2); - - if (snap1 || snap2) - { - if (x1 != nx1) - *tx1 = nx1; - else if (x2 != nx2) - *tx1 = x1 + (nx2 - x2); - - if (y1 != ny1) - *ty1 = ny1; - else if (y2 != ny2) - *ty1 = y1 + (ny2 - y2); - } - - return snap1 || snap2; -} - -GimpParasite * -gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimp_parasite_list_find (gimage->parasites, name); -} - -static void -list_func (gchar *key, - GimpParasite *p, - gchar ***cur) -{ - *(*cur)++ = (gchar *) g_strdup (key); -} - -gchar ** -gimp_image_parasite_list (const GimpImage *gimage, - gint *count) -{ - gchar **list; - gchar **cur; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - *count = gimp_parasite_list_length (gimage->parasites); - cur = list = g_new (gchar*, *count); - - gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur); - - return list; -} - -void -gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL); - - /* only set the dirty bit manually if we can be saved and the new - parasite differs from the current one and we aren't undoable */ - if (gimp_parasite_is_undoable (parasite)) - undo_push_image_parasite (gimage, parasite); - - /* We used to push an cantundo on te stack here. This made the undo stack - unusable (NULL on the stack) and prevented people from undoing after a - save (since most save plug-ins attach an undoable comment parasite). - Now we simply attach the parasite without pushing an undo. That way it's - undoable but does not block the undo system. --Sven - */ - - gimp_parasite_list_add (gimage->parasites, parasite); - - if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT)) - { - gimp_parasite_shift_parent (parasite); - gimp_parasite_attach (gimage->gimp, parasite); - } -} - -void -gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite) -{ - GimpParasite *p; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (parasite != NULL); - - if (!(p = gimp_parasite_list_find (gimage->parasites, parasite))) - return; - - if (gimp_parasite_is_undoable (p)) - undo_push_image_parasite_remove (gimage, gimp_parasite_name (p)); - - gimp_parasite_list_remove (gimage->parasites, parasite); -} - -GimpTattoo -gimp_image_get_new_tattoo (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - gimage->tattoo_state++; - - if (gimage->tattoo_state <= 0) - g_warning ("%s: Tattoo state corrupted " - "(integer overflow).", G_GNUC_PRETTY_FUNCTION); - - return gimage->tattoo_state; -} - -GimpTattoo -gimp_image_get_tattoo_state (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); - - return gimage->tattoo_state; -} - -gboolean -gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val) -{ - GList *list; - gboolean retval = TRUE; - GimpChannel *channel; - GimpTattoo maxval = 0; - Path *pptr = NULL; - PathList *plist; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ltattoo; - - ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data)); - if (ltattoo > maxval) - maxval = ltattoo; - if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in channel */ - } - - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ltattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Now check that the paths channel tattoos don't overlap */ - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - GimpTattoo ctattoo; - - channel = (GimpChannel *) list->data; - - ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)); - if (ctattoo > maxval) - maxval = ctattoo; - /* Now check path an't got this tattoo */ - if (path_get_path_by_tattoo (gimage, ctattoo) != NULL) - { - retval = FALSE; /* Oopps duplicated tattoo in layer */ - } - } - - /* Find the max tatto value in the paths */ - plist = gimage->paths; - - if (plist && plist->bz_paths) - { - GimpTattoo ptattoo; - GSList *pl; - - for (pl = plist->bz_paths; pl; pl = g_slist_next (pl)) - { - pptr = pl->data; - - ptattoo = path_get_tattoo (pptr); - - if (ptattoo > maxval) - maxval = ptattoo; - } - } - - if (val < maxval) - retval = FALSE; - /* Must check the state is valid */ - if (retval == TRUE) - gimage->tattoo_state = val; - - return retval; -} - -void -gimp_image_set_paths (GimpImage *gimage, - PathList *paths) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->paths = paths; -} - -PathList * -gimp_image_get_paths (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->paths; -} - -void -gimp_image_colormap_changed (GimpImage *gimage, - gint col) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (col < gimage->num_cols); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[COLORMAP_CHANGED], 0, - col); -} - -void -gimp_image_mode_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MODE_CHANGED], 0); -} - -void -gimp_image_mask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MASK_CHANGED], 0); -} - -void -gimp_image_resolution_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[RESOLUTION_CHANGED], 0); -} - -void -gimp_image_unit_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNIT_CHANGED], 0); -} - -void -gimp_image_qmask_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[QMASK_CHANGED], 0); -} - -void -gimp_image_alpha_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED], 0); -} - -void -gimp_image_floating_selection_changed (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[FLOATING_SELECTION_CHANGED], 0); -} - -void -gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE], 0, - x, y, width, height); -} - -void -gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (guide != NULL); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE_GUIDE], 0, - guide); -} - -void -gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[SELECTION_CONTROL], 0, - control); -} - -void -gimp_image_invalidate_layer_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->layers, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -void -gimp_image_invalidate_channel_previews (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimp_container_foreach (gimage->channels, - (GFunc) gimp_viewable_invalidate_preview, - NULL); -} - -GimpContainer * -gimp_image_get_layers (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->layers; -} - -GimpContainer * -gimp_image_get_channels (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->channels; -} - -gint -gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_LAYER (layer), -1); - - return gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); -} - -gint -gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1); - - return gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); -} - -GimpLayer * -gimp_image_get_active_layer (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_layer; -} - -GimpChannel * -gimp_image_get_active_channel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->active_channel; -} - -GimpLayer * -gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo) - return layer; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tattoo) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - - if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name) -{ - GimpChannel *channel; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->channels)->list; - list; - list = g_list_next (list)) - { - channel = (GimpChannel *) list->data; - if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name)) - return channel; - } - - return NULL; -} - -GimpChannel * -gimp_image_get_mask (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - return gimage->selection_mask; -} - -void -gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && active != gimage->active[pixel]) - { - gimage->active[pixel] = active ? TRUE : FALSE; - - /* If there is an active channel and we mess with the components, - * the active channel gets unset... - */ - gimp_image_unset_active_channel (gimage); - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, - type); - } -} - -gboolean -gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->active[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->active[ALPHA_PIX]; break; - case GRAY: return gimage->active[ALPHA_G_PIX]; break; - case INDEXED: return gimage->active[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -void -gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active) -{ - GimpLayer *layer; - gint i; - - /* first, blindly copy the gimage active channels */ - for (i = 0; i < MAX_CHANNELS; i++) - active[i] = gimage->active[i]; - - /* If the drawable is a channel (a saved selection, etc.) - * make sure that the alpha channel is not valid - */ - if (GIMP_IS_CHANNEL (drawable)) - { - active[ALPHA_G_PIX] = 0; /* no alpha values in channels */ - } - else - { - /* otherwise, check whether preserve transparency is - * enabled in the layer and if the layer has alpha - */ - if (GIMP_IS_LAYER (drawable)) - { - layer = GIMP_LAYER (drawable); - if (gimp_layer_has_alpha (layer) && layer->preserve_trans) - active[gimp_drawable_bytes (drawable) - 1] = 0; - } - } -} - -void -gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible) -{ - gint pixel = -1; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - switch (type) - { - case RED_CHANNEL: pixel = RED_PIX; break; - case GREEN_CHANNEL: pixel = GREEN_PIX; break; - case BLUE_CHANNEL: pixel = BLUE_PIX; break; - case GRAY_CHANNEL: pixel = GRAY_PIX; break; - case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: pixel = ALPHA_PIX; break; - case GRAY: pixel = ALPHA_G_PIX; break; - case INDEXED: pixel = ALPHA_I_PIX; break; - } - break; - - default: - break; - } - - if (pixel != -1 && visible != gimage->visible[pixel]) - { - gimage->visible[pixel] = visible ? TRUE : FALSE; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[COMPONENT_VISIBILITY_CHANGED], 0, - type); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - } -} - -gboolean -gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type) -{ - /* No sanity checking here... */ - switch (type) - { - case RED_CHANNEL: return gimage->visible[RED_PIX]; break; - case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break; - case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break; - case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break; - case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break; - case ALPHA_CHANNEL: - switch (gimp_image_base_type (gimage)) - { - case RGB: return gimage->visible[ALPHA_PIX]; break; - case GRAY: return gimage->visible[ALPHA_G_PIX]; break; - case INDEXED: return gimage->visible[ALPHA_I_PIX]; break; - } - break; - - default: - break; - } - - return FALSE; -} - -gboolean -gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs) -{ - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (segs != NULL, FALSE); - g_return_val_if_fail (n_segs != NULL, FALSE); - - /* The second boundary corresponds to the active layer's - * perimeter... - */ - layer = gimp_image_get_active_layer (gimage); - - if (layer) - { - *segs = gimp_layer_boundary (layer, n_segs); - return TRUE; - } - else - { - *segs = NULL; - *n_segs = 0; - return FALSE; - } -} - -GimpLayer * -gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); - - /* First, find the layer in the gimage - * If it isn't valid, find the first layer that is - */ - if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0); - - if (layer) - { - /* Configure the layer stack to reflect this change */ - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer); - - /* invalidate the selection boundary because of a layer modification */ - gimp_layer_invalidate_boundary (layer); - } - - if (layer != gimage->active_layer) - { - gimage->active_layer = layer; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - - if (gimage->active_channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - } - } - - /* return the layer */ - return layer; -} - -GimpChannel * -gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* Not if there is a floating selection */ - if (gimp_image_floating_sel (gimage)) - return NULL; - - /* First, find the channel - * If it doesn't exist, find the first channel that does - */ - if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0); - - if (channel != gimage->active_channel) - { - gimage->active_channel = channel; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->active_layer) - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* return the channel */ - return channel; -} - -GimpChannel * -gimp_image_unset_active_channel (GimpImage *gimage) -{ - GimpChannel *channel; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - channel = gimp_image_get_active_channel (gimage); - - if (channel) - { - gimage->active_channel = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); - - if (gimage->layer_stack) - { - GimpLayer *layer; - - layer = (GimpLayer *) gimage->layer_stack->data; - - gimp_image_set_active_layer (gimage, layer); - } - } - - return channel; -} - -GimpLayer * -gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y) -{ - GimpLayer *layer; - GList *list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_layer_pick_correlate (layer, x, y)) - return layer; - } - - return NULL; -} - -gboolean -gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the top layer already? */ - if (curpos == 0) - { - g_message (_("Layer cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE); -} - -gboolean -gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - /* is this the bottom layer already? */ - length = gimp_container_num_children (gimage->layers); - if (curpos >= length - 1) - { - g_message (_("Layer cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE); -} - -gboolean -gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - if (curpos == 0) - { - g_message (_("Layer is already on top.")); - return FALSE; - } - - if (! gimp_layer_has_alpha (layer)) - { - g_message (_("Cannot raise a layer without alpha.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, 0, TRUE); -} - -gboolean -gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer) -{ - gint curpos; - gint length; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - curpos = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - - length = gimp_container_num_children (gimage->layers); - - if (curpos >= length - 1) - { - g_message (_("Layer is already on the bottom.")); - return FALSE; - } - - return gimp_image_position_layer (gimage, layer, length - 1, TRUE); -} - -gboolean -gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo) -{ - gint off_x, off_y; - gint index; - gint num_layers; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - index = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - if (index < 0) - return FALSE; - - num_layers = gimp_container_num_children (gimage->layers); - - if (new_index < 0) - new_index = 0; - - if (new_index >= num_layers) - new_index = num_layers - 1; - - if (new_index == index) - return TRUE; - - /* check if we want to move it below a bottom layer without alpha */ - if (new_index == num_layers - 1) - { - GimpLayer *tmp; - - tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, - num_layers - 1); - - if (new_index == num_layers - 1 && - ! gimp_layer_has_alpha (tmp)) - { - g_message (_("Layer \"%s\" has no alpha.\nLayer was placed above it."), - GIMP_OBJECT (tmp)->name); - new_index--; - } - } - - if (push_undo) - undo_push_layer_reposition (gimage, layer); - - gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - gimp_image_update (gimage, - off_x, off_y, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); - - return TRUE; -} - -GimpLayer * -gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type) -{ - GList *list; - GSList *merge_list = NULL; - gboolean had_floating_sel = FALSE; - GimpLayer *layer = NULL; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - { - floating_sel_anchor (gimage->floating_sel); - had_floating_sel = TRUE; - } - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - if (merge_list && merge_list->next) - { - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_slist_free (merge_list); - - /* If there was a floating selection, we have done something. - No need to warn the user. Return the active layer instead */ - if (had_floating_sel) - return layer; - else - g_message (_("Not enough visible layers for a merge.\n" - "There must be at least two.")); - - return NULL; - } -} - -GimpLayer * -gimp_image_flatten (GimpImage *gimage) -{ - GList *list; - GSList *merge_list = NULL; - GimpLayer *layer; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - gimp_set_busy (gimage->gimp); - - /* if there's a floating selection, anchor it */ - if (gimp_image_floating_sel (gimage)) - floating_sel_anchor (gimage->floating_sel); - - for (list = GIMP_LIST (gimage->layers)->list; - list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (merge_list, layer); - } - - layer = gimp_image_merge_layers (gimage, merge_list, FLATTEN_IMAGE); - g_slist_free (merge_list); - - gimp_image_alpha_changed (gimage); - - gimp_unset_busy (gimage->gimp); - - return layer; -} - -GimpLayer * -gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type) -{ - GimpLayer *layer; - GList *list; - GList *layer_list; - GSList *merge_list; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - for (list = GIMP_LIST (gimage->layers)->list, layer_list = NULL; - list && !layer_list; - list = g_list_next (list)) - { - layer = (GimpLayer *) list->data; - - if (layer == current_layer) - break; - } - - for (layer_list = g_list_next (list), merge_list = NULL; - layer_list && !merge_list; - layer_list = g_list_next (layer_list)) - { - layer = (GimpLayer *) layer_list->data; - - if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) - merge_list = g_slist_append (NULL, layer); - } - - if (merge_list) - { - merge_list = g_slist_prepend (merge_list, current_layer); - - gimp_set_busy (gimage->gimp); - - layer = gimp_image_merge_layers (gimage, merge_list, merge_type); - g_slist_free (merge_list); - - gimp_unset_busy (gimage->gimp); - - return layer; - } - else - { - g_message (_("There are not enough visible layers for a merge down.")); - return NULL; - } -} - -GimpLayer * -gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type) -{ - GList *list; - GSList *reverse_list = NULL; - PixelRegion src1PR, src2PR, maskPR; - PixelRegion *mask; - GimpLayer *merge_layer; - GimpLayer *layer; - GimpLayer *bottom_layer; - LayerModeEffects bottom_mode; - guchar bg[4] = {0, 0, 0, 0}; - GimpImageType type; - gint count; - gint x1, y1, x2, y2; - gint x3, y3, x4, y4; - gint operation; - gint position; - gint active[MAX_CHANNELS] = {1, 1, 1, 1}; - gint off_x, off_y; - gchar *name; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - layer = NULL; - type = RGBA_GIMAGE; - x1 = y1 = 0; - x2 = y2 = 0; - bottom_layer = NULL; - bottom_mode = NORMAL_MODE; - - /* Get the layer extents */ - count = 0; - while (merge_list) - { - layer = (GimpLayer *) merge_list->data; - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - - switch (merge_type) - { - case EXPAND_AS_NECESSARY: - case CLIP_TO_IMAGE: - if (!count) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - else - { - if (off_x < x1) - x1 = off_x; - if (off_y < y1) - y1 = off_y; - if ((off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) > x2) - x2 = (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))); - if ((off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))) > y2) - y2 = (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))); - } - if (merge_type == CLIP_TO_IMAGE) - { - x1 = CLAMP (x1, 0, gimage->width); - y1 = CLAMP (y1, 0, gimage->height); - x2 = CLAMP (x2, 0, gimage->width); - y2 = CLAMP (y2, 0, gimage->height); - } - break; - - case CLIP_TO_BOTTOM_LAYER: - if (merge_list->next == NULL) - { - x1 = off_x; - y1 = off_y; - x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)); - y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)); - } - break; - - case FLATTEN_IMAGE: - if (merge_list->next == NULL) - { - x1 = 0; - y1 = 0; - x2 = gimage->width; - y2 = gimage->height; - } - 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 */ - undo_push_group_start (gimage, LAYER_MERGE_UNDO); - - name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); - - if (merge_type == FLATTEN_IMAGE || - gimp_drawable_type (GIMP_DRAWABLE (layer)) == INDEXED_GIMAGE) - { - switch (gimp_image_base_type (gimage)) - { - case RGB: type = RGB_GIMAGE; break; - case GRAY: type = GRAY_GIMAGE; break; - case INDEXED: type = INDEXED_GIMAGE; break; - } - - merge_layer = gimp_layer_new (gimage, (x2 - x1), (y2 - y1), - type, - gimp_object_get_name (GIMP_OBJECT (layer)), - OPAQUE_OPACITY, NORMAL_MODE); - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* get the background for compositing */ - gimp_image_get_background (gimage, GIMP_DRAWABLE (merge_layer), bg); - - /* init the pixel region */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - gimage->width, gimage->height, - 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 (gimage, (x2 - x1), (y2 - y1), - gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), - "merged layer", - OPAQUE_OPACITY, NORMAL_MODE); - - if (!merge_layer) - { - g_warning ("%s: could not allocate merge layer", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - GIMP_DRAWABLE (merge_layer)->offset_x = x1; - GIMP_DRAWABLE (merge_layer)->offset_y = y1; - - /* Set the layer to transparent */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - 0, 0, - (x2 - x1), (y2 - y1), - TRUE); - - /* set the region to 0's */ - color_region (&src1PR, bg); - - /* 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 = (GimpLayer *) reverse_list->data; - position = - gimp_container_num_children (gimage->layers) - - gimp_container_get_child_index (gimage->layers, GIMP_OBJECT (layer)); - - /* set the mode of the bottom layer to normal so that the contents - * aren't lost when merging with the all-alpha merge_layer - * Keep a pointer to it so that we can set the mode right after it's - * been merged so that undo works correctly. - */ - bottom_layer = layer; - bottom_mode = bottom_layer->mode; - - /* 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. - */ - if (bottom_layer->mode != DISSOLVE_MODE) - gimp_layer_set_mode (bottom_layer, NORMAL_MODE); - } - - /* Copy the tattoo and parasites of the bottom layer to the new layer */ - gimp_drawable_set_tattoo (GIMP_DRAWABLE (merge_layer), - gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer))); - GIMP_DRAWABLE (merge_layer)->parasites = - gimp_parasite_list_copy (GIMP_DRAWABLE (layer)->parasites); - - while (reverse_list) - { - layer = (GimpLayer *) reverse_list->data; - - /* determine what sort of operation is being attempted and - * if it's actually legal... - */ - operation = - valid_combinations[gimp_drawable_type (GIMP_DRAWABLE (merge_layer))][gimp_drawable_bytes (GIMP_DRAWABLE (layer))]; - - if (operation == -1) - { - g_warning ("%s: attempting to merge incompatible layers.", - G_GNUC_PRETTY_FUNCTION); - return NULL; - } - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); - x3 = CLAMP (off_x, x1, x2); - y3 = CLAMP (off_y, y1, y2); - x4 = CLAMP (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)), x1, x2); - y4 = CLAMP (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)), y1, y2); - - /* configure the pixel regions */ - pixel_region_init (&src1PR, - gimp_drawable_data (GIMP_DRAWABLE (merge_layer)), - (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), - TRUE); - pixel_region_init (&src2PR, - gimp_drawable_data (GIMP_DRAWABLE (layer)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - - if (layer->mask && layer->mask->apply_mask) - { - pixel_region_init (&maskPR, - gimp_drawable_data (GIMP_DRAWABLE (layer->mask)), - (x3 - off_x), (y3 - off_y), - (x4 - x3), (y4 - y3), - FALSE); - mask = &maskPR; - } - else - { - mask = NULL; - } - - combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, - layer->opacity, layer->mode, active, operation); - - gimp_image_remove_layer (gimage, layer); - reverse_list = g_slist_next (reverse_list); - } - - /* Save old mode in undo */ - if (bottom_layer) - gimp_layer_set_mode (bottom_layer, bottom_mode); - - g_slist_free (reverse_list); - - /* if the type is flatten, remove all the remaining layers */ - if (merge_type == FLATTEN_IMAGE) - { - list = GIMP_LIST (gimage->layers)->list; - while (list) - { - layer = (GimpLayer *) list->data; - - list = g_list_next (list); - gimp_image_remove_layer (gimage, layer); - } - - gimp_image_add_layer (gimage, merge_layer, position); - } - else - { - /* Add the layer to the gimage */ - gimp_image_add_layer (gimage, merge_layer, - gimp_container_num_children (gimage->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_set_name (GIMP_OBJECT (merge_layer), name); - g_free (name); - - /* End the merge undo group */ - undo_push_group_end (gimage); - - gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE); - - gimp_drawable_update (GIMP_DRAWABLE (merge_layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (merge_layer)), - gimp_drawable_height (GIMP_DRAWABLE (merge_layer))); - - return merge_layer; -} - -gboolean -gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position) -{ - LayerUndo *lu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - - if (GIMP_DRAWABLE (layer)->gimage != NULL && - GIMP_DRAWABLE (layer)->gimage != gimage) - { - g_warning ("%s: attempting to add layer to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) - { - g_warning ("%s: trying to add layer to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Prepare a layer undo and push it */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = 0; - lu->prev_layer = gimp_image_get_active_layer (gimage); - undo_push_layer (gimage, LAYER_ADD_UNDO, lu); - - /* If the layer is a floating selection, set the ID */ - if (gimp_layer_is_floating_sel (layer)) - gimage->floating_sel = layer; - - /* let the layer know about the gimage */ - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage); - - /* If the layer has a mask, set the mask's gimage */ - if (layer->mask) - { - gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage); - } - - /* add the layer to the list at the specified position */ - if (position == -1) - { - GimpLayer *active_layer; - - active_layer = gimp_image_get_active_layer (gimage); - - if (active_layer) - { - position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (active_layer)); - } - else - { - position = 0; - } - } - - /* If there is a floating selection (and this isn't it!), - * make sure the insert position is greater than 0 - */ - if (position == 0 && - gimp_image_floating_sel (gimage) && - (gimage->floating_sel != layer)) - { - position = 1; - } - - gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position); - g_object_unref (G_OBJECT (layer)); - - /* notify the layers dialog of the currently active layer */ - gimp_image_set_active_layer (gimage, layer); - - /* update the new layer's area */ - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (layer)), - gimp_drawable_height (GIMP_DRAWABLE (layer))); - - return TRUE; -} - -void -gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer) -{ - LayerUndo *lu; - gint x, y, w, h; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_LAYER (layer)); - - g_return_if_fail (gimp_container_have (gimage->layers, - GIMP_OBJECT (layer))); - - /* Push a layer undo */ - lu = g_new (LayerUndo, 1); - lu->layer = layer; - lu->prev_position = gimp_container_get_child_index (gimage->layers, - GIMP_OBJECT (layer)); - lu->prev_layer = layer; - - undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu); - - g_object_ref (G_OBJECT (layer)); - - gimp_container_remove (gimage->layers, GIMP_OBJECT (layer)); - gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); - - /* If this was the floating selection, reset the fs pointer */ - if (gimage->floating_sel == layer) - { - gimage->floating_sel = NULL; - - floating_sel_reset (layer); - } - - if (layer == gimp_image_get_active_layer (gimage)) - { - if (gimage->layer_stack) - { - gimp_image_set_active_layer (gimage, gimage->layer_stack->data); - } - else - { - gimage->active_layer = NULL; - - g_signal_emit (G_OBJECT (gimage), - gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); - } - } - - /* Send out REMOVED signal from layer */ - gimp_drawable_removed (GIMP_DRAWABLE (layer)); - - gimp_drawable_offsets (GIMP_DRAWABLE (layer), &x, &y); - w = gimp_drawable_width (GIMP_DRAWABLE (layer)); - h = gimp_drawable_height (GIMP_DRAWABLE (layer)); - - g_object_unref (G_OBJECT (layer)); - - gimp_image_update (gimage, x, y, w, h); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -gboolean -gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == 0) - { - g_message (_("Channel cannot be raised higher.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index - 1, TRUE); -} - -gboolean -gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel) -{ - gint index; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index == gimp_container_num_children (gimage->channels) - 1) - { - g_message (_("Channel cannot be lowered more.")); - return FALSE; - } - - return gimp_image_position_channel (gimage, channel, index + 1, TRUE); -} - -gboolean -gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo /* FIXME unused */) -{ - gint index; - gint num_channels; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - index = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - if (index < 0) - return FALSE; - - num_channels = gimp_container_num_children (gimage->channels); - - new_index = CLAMP (new_index, 0, num_channels - 1); - - if (new_index == index) - return TRUE; - - gimp_container_reorder (gimage->channels, - GIMP_OBJECT (channel), new_index); - - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -gboolean -gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position) -{ - ChannelUndo *cu; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - - if (GIMP_DRAWABLE (channel)->gimage != NULL && - GIMP_DRAWABLE (channel)->gimage != gimage) - { - g_warning ("%s: attempting to add channel to wrong image.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) - { - g_warning ("%s: trying to add channel to image twice.", - G_GNUC_PRETTY_FUNCTION); - return FALSE; - } - - /* Push a channel undo */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = 0; - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu); - - /* add the channel to the list */ - gimp_container_add (gimage->channels, GIMP_OBJECT (channel)); - g_object_unref (G_OBJECT (channel)); - - /* notify this gimage of the currently active channel */ - gimp_image_set_active_channel (gimage, channel); - - /* if channel is visible, update the image */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (channel)), - gimp_drawable_height (GIMP_DRAWABLE (channel))); - - return TRUE; -} - -void -gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel) -{ - ChannelUndo *cu; - - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_return_if_fail (GIMP_IS_CHANNEL (channel)); - - g_return_if_fail (gimp_container_have (gimage->channels, - GIMP_OBJECT (channel))); - - /* Prepare a channel undo--push it below */ - cu = g_new (ChannelUndo, 1); - cu->channel = channel; - cu->prev_position = gimp_container_get_child_index (gimage->channels, - GIMP_OBJECT (channel)); - cu->prev_channel = gimp_image_get_active_channel (gimage); - undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu); - - g_object_ref (G_OBJECT (channel)); - - gimp_container_remove (gimage->channels, GIMP_OBJECT (channel)); - - /* Send out REMOVED signal from channel */ - gimp_drawable_removed (GIMP_DRAWABLE (channel)); - - if (channel == gimp_image_get_active_channel (gimage)) - { - if (gimp_container_num_children (gimage->channels) > 0) - { - gimp_image_set_active_channel - (gimage, - GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels, - 0))); - } - else - { - gimp_image_unset_active_channel (gimage); - } - } - - g_object_unref (G_OBJECT (channel)); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); -} - -/************************************************************/ -/* Access functions */ -/************************************************************/ - -gboolean -gimp_image_is_empty (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE); - - return (gimp_container_num_children (gimage->layers) == 0); -} - -GimpDrawable * -gimp_image_active_drawable (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - /* If there is an active channel (a saved selection, etc.), - * we ignore the active layer - */ - if (gimage->active_channel) - { - return GIMP_DRAWABLE (gimage->active_channel); - } - else if (gimage->active_layer) - { - GimpLayer *layer; - - layer = gimage->active_layer; - - if (layer->mask && layer->mask->edit_mask) - return GIMP_DRAWABLE (layer->mask); - else - return GIMP_DRAWABLE (layer); - } - - return NULL; -} - -GimpImageBaseType -gimp_image_base_type (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - return gimage->base_type; -} - -GimpImageType -gimp_image_base_type_with_alpha (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); - - switch (gimage->base_type) - { - case RGB: - return RGBA_GIMAGE; - case GRAY: - return GRAYA_GIMAGE; - case INDEXED: - return INDEXEDA_GIMAGE; - } - return RGB_GIMAGE; -} - -const gchar * -gimp_image_filename (const GimpImage *gimage) -{ - const gchar *filename; - - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); - - filename = gimp_object_get_name (GIMP_OBJECT (gimage)); - - return filename ? filename : _("Untitled"); -} - -gboolean -gimp_image_undo_is_enabled (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimage->undo_on; -} - -gboolean -gimp_image_undo_freeze (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = FALSE; - - return TRUE; -} - -gboolean -gimp_image_undo_thaw (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->undo_on = TRUE; - - return TRUE; -} - -gboolean -gimp_image_undo_disable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - return gimp_image_undo_freeze (gimage); -} - -gboolean -gimp_image_undo_enable (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - /* Free all undo steps as they are now invalidated */ - undo_free (gimage); - - return gimp_image_undo_thaw (gimage); -} - -void -gimp_image_undo_event (GimpImage *gimage, - gint event) -{ - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], 0, - event); -} - - -/* NOTE about the gimage->dirty counter: - * If 0, then the image is clean (ie, copy on disk is the same as the one - * in memory). - * If positive, then that's the number of dirtying operations done - * on the image since the last save. - * If negative, then user has hit undo and gone back in time prior - * to the saved copy. Hitting redo will eventually come back to - * the saved copy. - * - * The image is dirty (ie, needs saving) if counter is non-zero. - * - * If the counter is around 10000, this is due to undo-ing back - * before a saved version, then mutating the image (thus destroying - * the redo stack). Once this has happened, it's impossible to get - * the image back to the state on disk, since the redo info has been - * freed. See undo.c for the gorey details. - */ - - -/* - * NEVER CALL gimp_image_dirty() directly! - * - * If your code has just dirtied the image, push an undo instead. - * Failing that, push the trivial undo which tells the user the - * command is not undoable: undo_push_cantundo() (But really, it would - * be best to push a proper undo). If you just dirty the image - * without pushing an undo then the dirty count is increased, but - * popping that many undo actions won't lead to a clean image. - */ - -gint -gimp_image_dirty (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty++; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[DIRTY], 0); - - TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty)); - - return gimage->dirty; -} - -gint -gimp_image_clean (GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - gimage->dirty--; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); - - TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty)); - - return gimage->dirty; -} - -void -gimp_image_clean_all (GimpImage *gimage) -{ - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - - gimage->dirty = 0; - - g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); -} - -GimpLayer * -gimp_image_floating_sel (const GimpImage *gimage) -{ - g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); - - if (gimage->floating_sel == NULL) - return NULL; - else - return gimage->floating_sel; -} - -guchar * -gimp_image_cmap (const GimpImage *gimage) -{ - return gimp_drawable_cmap (gimp_image_active_drawable (gimage)); -} - static TempBuf * gimp_image_get_preview (GimpViewable *viewable, gint width, @@ -3865,3 +797,2139 @@ gimp_image_get_new_preview (GimpViewable *viewable, return comp; } + +static void +gimp_image_real_colormap_changed (GimpImage *gimage, + gint ncol) +{ + if (gimp_image_base_type (gimage) == INDEXED) + { + /* A colormap alteration affects the whole image */ + gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + + gimp_image_color_hash_invalidate (gimage, ncol); + } +} + + +/* public functions */ + +GimpImage * +gimp_image_new (Gimp *gimp, + gint width, + gint height, + GimpImageBaseType base_type) +{ + GimpImage *gimage; + gint i; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + + gimage = GIMP_IMAGE (g_object_new (GIMP_TYPE_IMAGE, NULL)); + + gimage->gimp = gimp; + gimage->ID = gimp->next_image_ID++; + + g_hash_table_insert (gimp->image_table, + GINT_TO_POINTER (gimage->ID), + (gpointer) gimage); + + gimage->width = width; + gimage->height = height; + gimage->base_type = base_type; + + gimage->xresolution = gimp->config->default_xresolution; + gimage->yresolution = gimp->config->default_yresolution; + gimage->unit = gimp->config->default_units; + + switch (base_type) + { + case RGB: + case GRAY: + break; + case INDEXED: + /* always allocate 256 colors for the colormap */ + gimage->num_cols = 0; + gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE); + break; + default: + break; + } + + /* set all color channels visible and active */ + for (i = 0; i < MAX_CHANNELS; i++) + { + gimage->visible[i] = TRUE; + gimage->active[i] = TRUE; + } + + /* create the selection mask */ + gimage->selection_mask = gimp_channel_new_mask (gimage, + gimage->width, + gimage->height); + + return gimage; +} + +GimpImageBaseType +gimp_image_base_type (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); + + return gimage->base_type; +} + +GimpImageType +gimp_image_base_type_with_alpha (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); + + switch (gimage->base_type) + { + case RGB: + return RGBA_GIMAGE; + case GRAY: + return GRAYA_GIMAGE; + case INDEXED: + return INDEXEDA_GIMAGE; + } + + return RGB_GIMAGE; +} + +CombinationMode +gimp_image_get_combination_mode (GimpImageType dest_type, + gint src_bytes) +{ + return valid_combinations[dest_type][src_bytes]; +} + +gint +gimp_image_get_ID (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); + + return gimage->ID; +} + +GimpImage * +gimp_image_get_by_ID (Gimp *gimp, + gint image_id) +{ + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + + if (gimp->image_table == NULL) + return NULL; + + return (GimpImage *) g_hash_table_lookup (gimp->image_table, + GINT_TO_POINTER (image_id)); +} + +void +gimp_image_set_filename (GimpImage *gimage, + const gchar *filename) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + gimp_object_set_name (GIMP_OBJECT (gimage), filename); +} + +const gchar * +gimp_image_get_filename (const GimpImage *gimage) +{ + const gchar *filename; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + filename = gimp_object_get_name (GIMP_OBJECT (gimage)); + + return filename ? filename : _("Untitled"); +} + +void +gimp_image_set_save_proc (GimpImage *gimage, + PlugInProcDef *proc) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + gimage->save_proc = proc; +} + +PlugInProcDef * +gimp_image_get_save_proc (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->save_proc; +} + +void +gimp_image_set_resolution (GimpImage *gimage, + gdouble xresolution, + gdouble yresolution) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + /* don't allow to set the resolution out of bounds */ + if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION || + yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION) + return; + + if ((ABS (gimage->xresolution - xresolution) >= 1e-5) || + (ABS (gimage->yresolution - yresolution) >= 1e-5)) + { + undo_push_resolution (gimage); + + gimage->xresolution = xresolution; + gimage->yresolution = yresolution; + + gimp_image_resolution_changed (gimage); + gimp_viewable_size_changed (GIMP_VIEWABLE (gimage)); + } +} + +void +gimp_image_get_resolution (const GimpImage *gimage, + gdouble *xresolution, + gdouble *yresolution) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (xresolution && yresolution); + + *xresolution = gimage->xresolution; + *yresolution = gimage->yresolution; +} + +void +gimp_image_resolution_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[RESOLUTION_CHANGED], 0); +} + +void +gimp_image_set_unit (GimpImage *gimage, + GimpUnit unit) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + if (gimage->unit != unit) + { + undo_push_resolution (gimage); + + gimage->unit = unit; + + gimp_image_unit_changed (gimage); + } +} + +GimpUnit +gimp_image_get_unit (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_UNIT_INCH); + + return gimage->unit; +} + +void +gimp_image_unit_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNIT_CHANGED], 0); +} + +void +gimp_image_set_qmask_state (GimpImage *gimage, + gboolean qmask_state) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + if (qmask_state != gimage->qmask_state) + { + gimage->qmask_state = qmask_state ? TRUE : FALSE; + + gimp_image_qmask_changed (gimage); + } +} + +gboolean +gimp_image_get_qmask_state (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + return gimage->qmask_state; +} + +void +gimp_image_qmask_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[QMASK_CHANGED], 0); +} + +gint +gimp_image_get_width (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); + + return gimage->width; +} + +gint +gimp_image_get_height (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); + + return gimage->height; +} + +gboolean +gimp_image_is_empty (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE); + + return (gimp_container_num_children (gimage->layers) == 0); +} + +GimpLayer * +gimp_image_floating_sel (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + if (gimage->floating_sel == NULL) + return NULL; + else + return gimage->floating_sel; +} + +void +gimp_image_floating_selection_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[FLOATING_SELECTION_CHANGED], 0); +} + +guchar * +gimp_image_get_colormap (const GimpImage *gimage) +{ + return gimp_drawable_cmap (gimp_image_active_drawable (gimage)); +} + +void +gimp_image_colormap_changed (GimpImage *gimage, + gint col) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (col < gimage->num_cols); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[COLORMAP_CHANGED], 0, + col); +} + +GimpChannel * +gimp_image_get_mask (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->selection_mask; +} + +void +gimp_image_mask_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MASK_CHANGED], 0); +} + +void +gimp_image_set_component_active (GimpImage *gimage, + ChannelType type, + gboolean active) +{ + gint pixel = -1; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + switch (type) + { + case RED_CHANNEL: pixel = RED_PIX; break; + case GREEN_CHANNEL: pixel = GREEN_PIX; break; + case BLUE_CHANNEL: pixel = BLUE_PIX; break; + case GRAY_CHANNEL: pixel = GRAY_PIX; break; + case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; + case ALPHA_CHANNEL: + switch (gimp_image_base_type (gimage)) + { + case RGB: pixel = ALPHA_PIX; break; + case GRAY: pixel = ALPHA_G_PIX; break; + case INDEXED: pixel = ALPHA_I_PIX; break; + } + break; + + default: + break; + } + + if (pixel != -1 && active != gimage->active[pixel]) + { + gimage->active[pixel] = active ? TRUE : FALSE; + + /* If there is an active channel and we mess with the components, + * the active channel gets unset... + */ + gimp_image_unset_active_channel (gimage); + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, + type); + } +} + +gboolean +gimp_image_get_component_active (const GimpImage *gimage, + ChannelType type) +{ + /* No sanity checking here... */ + switch (type) + { + case RED_CHANNEL: return gimage->active[RED_PIX]; break; + case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break; + case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break; + case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break; + case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break; + case ALPHA_CHANNEL: + switch (gimp_image_base_type (gimage)) + { + case RGB: return gimage->active[ALPHA_PIX]; break; + case GRAY: return gimage->active[ALPHA_G_PIX]; break; + case INDEXED: return gimage->active[ALPHA_I_PIX]; break; + } + break; + + default: + break; + } + + return FALSE; +} + +void +gimp_image_get_active_components (GimpImage *gimage, + GimpDrawable *drawable, + gint *active) +{ + GimpLayer *layer; + gint i; + + /* first, blindly copy the gimage active channels */ + for (i = 0; i < MAX_CHANNELS; i++) + active[i] = gimage->active[i]; + + /* If the drawable is a channel (a saved selection, etc.) + * make sure that the alpha channel is not valid + */ + if (GIMP_IS_CHANNEL (drawable)) + { + active[ALPHA_G_PIX] = 0; /* no alpha values in channels */ + } + else + { + /* otherwise, check whether preserve transparency is + * enabled in the layer and if the layer has alpha + */ + if (GIMP_IS_LAYER (drawable)) + { + layer = GIMP_LAYER (drawable); + if (gimp_layer_has_alpha (layer) && layer->preserve_trans) + active[gimp_drawable_bytes (drawable) - 1] = 0; + } + } +} + +void +gimp_image_set_component_visible (GimpImage *gimage, + ChannelType type, + gboolean visible) +{ + gint pixel = -1; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + switch (type) + { + case RED_CHANNEL: pixel = RED_PIX; break; + case GREEN_CHANNEL: pixel = GREEN_PIX; break; + case BLUE_CHANNEL: pixel = BLUE_PIX; break; + case GRAY_CHANNEL: pixel = GRAY_PIX; break; + case INDEXED_CHANNEL: pixel = INDEXED_PIX; break; + case ALPHA_CHANNEL: + switch (gimp_image_base_type (gimage)) + { + case RGB: pixel = ALPHA_PIX; break; + case GRAY: pixel = ALPHA_G_PIX; break; + case INDEXED: pixel = ALPHA_I_PIX; break; + } + break; + + default: + break; + } + + if (pixel != -1 && visible != gimage->visible[pixel]) + { + gimage->visible[pixel] = visible ? TRUE : FALSE; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[COMPONENT_VISIBILITY_CHANGED], 0, + type); + + gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + } +} + +gboolean +gimp_image_get_component_visible (const GimpImage *gimage, + ChannelType type) +{ + /* No sanity checking here... */ + switch (type) + { + case RED_CHANNEL: return gimage->visible[RED_PIX]; break; + case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break; + case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break; + case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break; + case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break; + case ALPHA_CHANNEL: + switch (gimp_image_base_type (gimage)) + { + case RGB: return gimage->visible[ALPHA_PIX]; break; + case GRAY: return gimage->visible[ALPHA_G_PIX]; break; + case INDEXED: return gimage->visible[ALPHA_I_PIX]; break; + } + break; + + default: + break; + } + + return FALSE; +} + +void +gimp_image_mode_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[MODE_CHANGED], 0); +} + +void +gimp_image_alpha_changed (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED], 0); +} + +void +gimp_image_update (GimpImage *gimage, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE], 0, + x, y, width, height); +} + +void +gimp_image_update_guide (GimpImage *gimage, + GimpGuide *guide) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (guide != NULL); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UPDATE_GUIDE], 0, + guide); +} + +void +gimp_image_selection_control (GimpImage *gimage, + GimpSelectionControl control) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[SELECTION_CONTROL], 0, + control); +} + + +/* undo */ + +gboolean +gimp_image_undo_is_enabled (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + return gimage->undo_on; +} + +gboolean +gimp_image_undo_enable (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + /* Free all undo steps as they are now invalidated */ + undo_free (gimage); + + return gimp_image_undo_thaw (gimage); +} + +gboolean +gimp_image_undo_disable (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + return gimp_image_undo_freeze (gimage); +} + +gboolean +gimp_image_undo_freeze (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + gimage->undo_on = FALSE; + + return TRUE; +} + +gboolean +gimp_image_undo_thaw (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + gimage->undo_on = TRUE; + + return TRUE; +} + +void +gimp_image_undo_event (GimpImage *gimage, + gint event) +{ + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], 0, + event); +} + + +/* NOTE about the gimage->dirty counter: + * If 0, then the image is clean (ie, copy on disk is the same as the one + * in memory). + * If positive, then that's the number of dirtying operations done + * on the image since the last save. + * If negative, then user has hit undo and gone back in time prior + * to the saved copy. Hitting redo will eventually come back to + * the saved copy. + * + * The image is dirty (ie, needs saving) if counter is non-zero. + * + * If the counter is around 10000, this is due to undo-ing back + * before a saved version, then mutating the image (thus destroying + * the redo stack). Once this has happened, it's impossible to get + * the image back to the state on disk, since the redo info has been + * freed. See undo.c for the gorey details. + */ + + +/* + * NEVER CALL gimp_image_dirty() directly! + * + * If your code has just dirtied the image, push an undo instead. + * Failing that, push the trivial undo which tells the user the + * command is not undoable: undo_push_cantundo() (But really, it would + * be best to push a proper undo). If you just dirty the image + * without pushing an undo then the dirty count is increased, but + * popping that many undo actions won't lead to a clean image. + */ + +gint +gimp_image_dirty (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + gimage->dirty++; + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[DIRTY], 0); + + TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty)); + + return gimage->dirty; +} + +gint +gimp_image_clean (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + gimage->dirty--; + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); + + TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty)); + + return gimage->dirty; +} + +void +gimp_image_clean_all (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + gimage->dirty = 0; + + g_signal_emit (G_OBJECT (gimage), gimp_image_signals[CLEAN], 0); +} + + +/* color transforms / utilities */ + + +/* Get rid of these! A "foreground" is an UI concept.. */ + +void +gimp_image_get_foreground (const GimpImage *gimage, + const GimpDrawable *drawable, + guchar *fg) +{ + GimpRGB color; + guchar pfg[3]; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); + g_return_if_fail (fg != NULL); + + gimp_context_get_foreground (gimp_get_current_context (gimage->gimp), &color); + + gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]); + + gimp_image_transform_color (gimage, drawable, pfg, fg, RGB); +} + +void +gimp_image_get_background (const GimpImage *gimage, + const GimpDrawable *drawable, + guchar *bg) +{ + GimpRGB color; + guchar pbg[3]; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (! drawable || GIMP_IS_DRAWABLE (drawable)); + g_return_if_fail (bg != NULL); + + gimp_context_get_background (gimp_get_current_context (gimage->gimp), &color); + + gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]); + + gimp_image_transform_color (gimage, drawable, pbg, bg, RGB); +} + +void +gimp_image_get_color (const GimpImage *gimage, + GimpImageType d_type, + guchar *rgb, + guchar *src) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + switch (d_type) + { + case RGB_GIMAGE: case RGBA_GIMAGE: + map_to_color (0, NULL, src, rgb); + break; + case GRAY_GIMAGE: case GRAYA_GIMAGE: + map_to_color (1, NULL, src, rgb); + break; + case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: + map_to_color (2, gimage->cmap, src, rgb); + break; + } +} + +void +gimp_image_transform_color (const GimpImage *gimage, + const GimpDrawable *drawable, + guchar *src, + guchar *dest, + GimpImageBaseType type) +{ + GimpImageType d_type; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + d_type = (drawable != NULL) ? gimp_drawable_type (drawable) : + gimp_image_base_type_with_alpha (gimage); + + switch (type) + { + case RGB: + switch (d_type) + { + case RGB_GIMAGE: case RGBA_GIMAGE: + /* Straight copy */ + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + break; + case GRAY_GIMAGE: case GRAYA_GIMAGE: + /* NTSC conversion */ + *dest = INTENSITY (src[RED_PIX], + src[GREEN_PIX], + src[BLUE_PIX]); + break; + case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: + /* Least squares method */ + *dest = gimp_image_color_hash_rgb_to_indexed (gimage, + src[RED_PIX], + src[GREEN_PIX], + src[BLUE_PIX]); + break; + } + break; + case GRAY: + switch (d_type) + { + case RGB_GIMAGE: case RGBA_GIMAGE: + /* Gray to RG&B */ + *dest++ = *src; + *dest++ = *src; + *dest++ = *src; + break; + case GRAY_GIMAGE: case GRAYA_GIMAGE: + /* Straight copy */ + *dest = *src; + break; + case INDEXED_GIMAGE: case INDEXEDA_GIMAGE: + /* Least squares method */ + *dest = gimp_image_color_hash_rgb_to_indexed (gimage, + src[GRAY_PIX], + src[GRAY_PIX], + src[GRAY_PIX]); + break; + } + break; + default: + break; + } +} + + +/* shadow tiles */ + +TileManager * +gimp_image_shadow (GimpImage *gimage, + gint width, + gint height, + gint bpp) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + if (gimage->shadow) + { + if ((width != tile_manager_width (gimage->shadow)) || + (height != tile_manager_height (gimage->shadow)) || + (bpp != tile_manager_bpp (gimage->shadow))) + { + gimp_image_free_shadow (gimage); + } + else + { + return gimage->shadow; + } + } + + gimage->shadow = tile_manager_new (width, height, bpp); + + return gimage->shadow; +} + +void +gimp_image_free_shadow (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + if (gimage->shadow) + { + tile_manager_destroy (gimage->shadow); + gimage->shadow = NULL; + } +} + + +/* combine functions */ + +void +gimp_image_apply_image (GimpImage *gimage, + GimpDrawable *drawable, + PixelRegion *src2PR, + gboolean undo, + gint opacity, + LayerModeEffects mode, + /* alternative to using drawable tiles as src1: */ + TileManager *src1_tiles, + gint x, + gint y) +{ + GimpChannel *mask; + gint x1, y1, x2, y2; + gint offset_x, offset_y; + PixelRegion src1PR, destPR, maskPR; + gint operation; + gint active [MAX_CHANNELS]; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + /* get the selection mask if one exists */ + mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); + + /* configure the active channel array */ + gimp_image_get_active_components (gimage, drawable, active); + + /* determine what sort of operation is being attempted and + * if it's actually legal... + */ + operation = gimp_image_get_combination_mode (gimp_drawable_type (drawable), + src2PR->bytes); + if (operation == -1) + { + g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); + return; + } + + /* get the layer offsets */ + gimp_drawable_offsets (drawable, &offset_x, &offset_y); + + /* make sure the image application coordinates are within gimage bounds */ + x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); + y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); + x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); + y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); + + if (mask) + { + /* make sure coordinates are in mask bounds ... + * we need to add the layer offset to transform coords + * into the mask coordinate system + */ + x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); + y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); + x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); + y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); + } + + /* If the calling procedure specified an undo step... */ + if (undo) + undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2); + + /* configure the pixel regions + * If an alternative to using the drawable's data as src1 was provided... + */ + if (src1_tiles) + pixel_region_init (&src1PR, src1_tiles, + x1, y1, (x2 - x1), (y2 - y1), FALSE); + else + pixel_region_init (&src1PR, gimp_drawable_data (drawable), + x1, y1, (x2 - x1), (y2 - y1), FALSE); + pixel_region_init (&destPR, gimp_drawable_data (drawable), + x1, y1, (x2 - x1), (y2 - y1), TRUE); + pixel_region_resize (src2PR, + src2PR->x + (x1 - x), src2PR->y + (y1 - y), + (x2 - x1), (y2 - y1)); + + if (mask) + { + gint mx, my; + + /* configure the mask pixel region + * don't use x1 and y1 because they are in layer + * coordinate system. Need mask coordinate system + */ + mx = x1 + offset_x; + my = y1 + offset_y; + + pixel_region_init (&maskPR, + gimp_drawable_data (GIMP_DRAWABLE (mask)), + mx, my, + (x2 - x1), (y2 - y1), + FALSE); + combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL, + opacity, mode, active, operation); + } + else + { + combine_regions (&src1PR, src2PR, &destPR, NULL, NULL, + opacity, mode, active, operation); + } +} + +/* Similar to gimp_image_apply_image but works in "replace" mode (i.e. + transparent pixels in src2 make the result transparent rather + than opaque. + + Takes an additional mask pixel region as well. +*/ +void +gimp_image_replace_image (GimpImage *gimage, + GimpDrawable *drawable, + PixelRegion *src2PR, + gboolean undo, + gint opacity, + PixelRegion *maskPR, + gint x, + gint y) +{ + GimpChannel *mask; + gint x1, y1, x2, y2; + gint offset_x, offset_y; + PixelRegion src1PR, destPR; + PixelRegion mask2PR, tempPR; + guchar *temp_data; + gint operation; + gint active [MAX_CHANNELS]; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + /* get the selection mask if one exists */ + mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage); + + /* configure the active channel array */ + gimp_image_get_active_components (gimage, drawable, active); + + /* determine what sort of operation is being attempted and + * if it's actually legal... + */ + operation = gimp_image_get_combination_mode (gimp_drawable_type (drawable), + src2PR->bytes); + if (operation == -1) + { + g_warning ("%s: illegal parameters.", G_GNUC_PRETTY_FUNCTION); + return; + } + + /* get the layer offsets */ + gimp_drawable_offsets (drawable, &offset_x, &offset_y); + + /* make sure the image application coordinates are within gimage bounds */ + x1 = CLAMP (x, 0, gimp_drawable_width (drawable)); + y1 = CLAMP (y, 0, gimp_drawable_height (drawable)); + x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable)); + y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable)); + + if (mask) + { + /* make sure coordinates are in mask bounds ... + * we need to add the layer offset to transform coords + * into the mask coordinate system + */ + x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); + y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); + x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x); + y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y); + } + + /* If the calling procedure specified an undo step... */ + if (undo) + gimp_drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE); + + /* configure the pixel regions + * If an alternative to using the drawable's data as src1 was provided... + */ + pixel_region_init (&src1PR, gimp_drawable_data (drawable), + x1, y1, (x2 - x1), (y2 - y1), FALSE); + pixel_region_init (&destPR, gimp_drawable_data (drawable), + x1, y1, (x2 - x1), (y2 - y1), TRUE); + pixel_region_resize (src2PR, + src2PR->x + (x1 - x), src2PR->y + (y1 - y), + (x2 - x1), (y2 - y1)); + + if (mask) + { + int mx, my; + + /* configure the mask pixel region + * don't use x1 and y1 because they are in layer + * coordinate system. Need mask coordinate system + */ + mx = x1 + offset_x; + my = y1 + offset_y; + + pixel_region_init (&mask2PR, + gimp_drawable_data (GIMP_DRAWABLE (mask)), + mx, my, + (x2 - x1), (y2 - y1), + FALSE); + + tempPR.bytes = 1; + tempPR.x = 0; + tempPR.y = 0; + tempPR.w = x2 - x1; + tempPR.h = y2 - y1; + tempPR.rowstride = tempPR.w * tempPR.bytes; + temp_data = g_malloc (tempPR.h * tempPR.rowstride); + tempPR.data = temp_data; + + copy_region (&mask2PR, &tempPR); + + /* apparently, region operations can mutate some PR data. */ + tempPR.x = 0; + tempPR.y = 0; + tempPR.w = x2 - x1; + tempPR.h = y2 - y1; + tempPR.data = temp_data; + + apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); + + tempPR.x = 0; + tempPR.y = 0; + tempPR.w = x2 - x1; + tempPR.h = y2 - y1; + tempPR.data = temp_data; + + combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, + opacity, active, operation); + + g_free (temp_data); + } + else + { + combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL, + opacity, active, operation); + } +} + + +/* parasites */ + +GimpParasite * +gimp_image_parasite_find (const GimpImage *gimage, + const gchar *name) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimp_parasite_list_find (gimage->parasites, name); +} + +static void +list_func (gchar *key, + GimpParasite *p, + gchar ***cur) +{ + *(*cur)++ = (gchar *) g_strdup (key); +} + +gchar ** +gimp_image_parasite_list (const GimpImage *gimage, + gint *count) +{ + gchar **list; + gchar **cur; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + *count = gimp_parasite_list_length (gimage->parasites); + cur = list = g_new (gchar*, *count); + + gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur); + + return list; +} + +void +gimp_image_parasite_attach (GimpImage *gimage, + GimpParasite *parasite) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL); + + /* only set the dirty bit manually if we can be saved and the new + parasite differs from the current one and we aren't undoable */ + if (gimp_parasite_is_undoable (parasite)) + undo_push_image_parasite (gimage, parasite); + + /* We used to push an cantundo on te stack here. This made the undo stack + unusable (NULL on the stack) and prevented people from undoing after a + save (since most save plug-ins attach an undoable comment parasite). + Now we simply attach the parasite without pushing an undo. That way it's + undoable but does not block the undo system. --Sven + */ + + gimp_parasite_list_add (gimage->parasites, parasite); + + if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT)) + { + gimp_parasite_shift_parent (parasite); + gimp_parasite_attach (gimage->gimp, parasite); + } +} + +void +gimp_image_parasite_detach (GimpImage *gimage, + const gchar *parasite) +{ + GimpParasite *p; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (parasite != NULL); + + if (!(p = gimp_parasite_list_find (gimage->parasites, parasite))) + return; + + if (gimp_parasite_is_undoable (p)) + undo_push_image_parasite_remove (gimage, gimp_parasite_name (p)); + + gimp_parasite_list_remove (gimage->parasites, parasite); +} + + +/* tattoos */ + +GimpTattoo +gimp_image_get_new_tattoo (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); + + gimage->tattoo_state++; + + if (gimage->tattoo_state <= 0) + g_warning ("%s: Tattoo state corrupted " + "(integer overflow).", G_GNUC_PRETTY_FUNCTION); + + return gimage->tattoo_state; +} + +GimpTattoo +gimp_image_get_tattoo_state (GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0); + + return gimage->tattoo_state; +} + +gboolean +gimp_image_set_tattoo_state (GimpImage *gimage, + GimpTattoo val) +{ + GList *list; + gboolean retval = TRUE; + GimpChannel *channel; + GimpTattoo maxval = 0; + Path *pptr = NULL; + PathList *plist; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + + for (list = GIMP_LIST (gimage->layers)->list; + list; + list = g_list_next (list)) + { + GimpTattoo ltattoo; + + ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data)); + if (ltattoo > maxval) + maxval = ltattoo; + if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL) + { + retval = FALSE; /* Oopps duplicated tattoo in channel */ + } + + /* Now check path an't got this tattoo */ + if (path_get_path_by_tattoo (gimage, ltattoo) != NULL) + { + retval = FALSE; /* Oopps duplicated tattoo in layer */ + } + } + + /* Now check that the paths channel tattoos don't overlap */ + for (list = GIMP_LIST (gimage->channels)->list; + list; + list = g_list_next (list)) + { + GimpTattoo ctattoo; + + channel = (GimpChannel *) list->data; + + ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)); + if (ctattoo > maxval) + maxval = ctattoo; + /* Now check path an't got this tattoo */ + if (path_get_path_by_tattoo (gimage, ctattoo) != NULL) + { + retval = FALSE; /* Oopps duplicated tattoo in layer */ + } + } + + /* Find the max tatto value in the paths */ + plist = gimage->paths; + + if (plist && plist->bz_paths) + { + GimpTattoo ptattoo; + GSList *pl; + + for (pl = plist->bz_paths; pl; pl = g_slist_next (pl)) + { + pptr = pl->data; + + ptattoo = path_get_tattoo (pptr); + + if (ptattoo > maxval) + maxval = ptattoo; + } + } + + if (val < maxval) + retval = FALSE; + /* Must check the state is valid */ + if (retval == TRUE) + gimage->tattoo_state = val; + + return retval; +} + + +/* layers / channels / paths */ + +GimpContainer * +gimp_image_get_layers (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->layers; +} + +GimpContainer * +gimp_image_get_channels (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->channels; +} + +void +gimp_image_set_paths (GimpImage *gimage, + PathList *paths) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + gimage->paths = paths; +} + +PathList * +gimp_image_get_paths (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->paths; +} + +GimpDrawable * +gimp_image_active_drawable (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + /* If there is an active channel (a saved selection, etc.), + * we ignore the active layer + */ + if (gimage->active_channel) + { + return GIMP_DRAWABLE (gimage->active_channel); + } + else if (gimage->active_layer) + { + GimpLayer *layer; + + layer = gimage->active_layer; + + if (layer->mask && layer->mask->edit_mask) + return GIMP_DRAWABLE (layer->mask); + else + return GIMP_DRAWABLE (layer); + } + + return NULL; +} + +GimpLayer * +gimp_image_get_active_layer (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->active_layer; +} + +GimpChannel * +gimp_image_get_active_channel (const GimpImage *gimage) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + return gimage->active_channel; +} + +GimpLayer * +gimp_image_set_active_layer (GimpImage *gimage, + GimpLayer *layer) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); + + /* First, find the layer in the gimage + * If it isn't valid, find the first layer that is + */ + if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) + layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0); + + if (layer) + { + /* Configure the layer stack to reflect this change */ + gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); + gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer); + + /* invalidate the selection boundary because of a layer modification */ + gimp_layer_invalidate_boundary (layer); + } + + if (layer != gimage->active_layer) + { + gimage->active_layer = layer; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); + + if (gimage->active_channel) + { + gimage->active_channel = NULL; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); + } + } + + /* return the layer */ + return layer; +} + +GimpChannel * +gimp_image_set_active_channel (GimpImage *gimage, + GimpChannel *channel) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + /* Not if there is a floating selection */ + if (gimp_image_floating_sel (gimage)) + return NULL; + + /* First, find the channel + * If it doesn't exist, find the first channel that does + */ + if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) + channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0); + + if (channel != gimage->active_channel) + { + gimage->active_channel = channel; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); + + if (gimage->active_layer) + { + gimage->active_layer = NULL; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); + } + } + + /* return the channel */ + return channel; +} + +GimpChannel * +gimp_image_unset_active_channel (GimpImage *gimage) +{ + GimpChannel *channel; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + channel = gimp_image_get_active_channel (gimage); + + if (channel) + { + gimage->active_channel = NULL; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); + + if (gimage->layer_stack) + { + GimpLayer *layer; + + layer = (GimpLayer *) gimage->layer_stack->data; + + gimp_image_set_active_layer (gimage, layer); + } + } + + return channel; +} + +gint +gimp_image_get_layer_index (const GimpImage *gimage, + const GimpLayer *layer) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); + g_return_val_if_fail (GIMP_IS_LAYER (layer), -1); + + return gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); +} + +gint +gimp_image_get_channel_index (const GimpImage *gimage, + const GimpChannel *channel) +{ + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1); + g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1); + + return gimp_container_get_child_index (gimage->channels, + GIMP_OBJECT (channel)); +} + +GimpLayer * +gimp_image_get_layer_by_tattoo (const GimpImage *gimage, + GimpTattoo tattoo) +{ + GimpLayer *layer; + GList *list; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + for (list = GIMP_LIST (gimage->layers)->list; + list; + list = g_list_next (list)) + { + layer = (GimpLayer *) list->data; + + if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo) + return layer; + } + + return NULL; +} + +GimpChannel * +gimp_image_get_channel_by_tattoo (const GimpImage *gimage, + GimpTattoo tattoo) +{ + GimpChannel *channel; + GList *list; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + for (list = GIMP_LIST (gimage->channels)->list; + list; + list = g_list_next (list)) + { + channel = (GimpChannel *) list->data; + + if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo) + return channel; + } + + return NULL; +} + +GimpChannel * +gimp_image_get_channel_by_name (const GimpImage *gimage, + const gchar *name) +{ + GimpChannel *channel; + GList *list; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + for (list = GIMP_LIST (gimage->channels)->list; + list; + list = g_list_next (list)) + { + channel = (GimpChannel *) list->data; + if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name)) + return channel; + } + + return NULL; +} + +gboolean +gimp_image_add_layer (GimpImage *gimage, + GimpLayer *layer, + gint position) +{ + LayerUndo *lu; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + if (GIMP_DRAWABLE (layer)->gimage != NULL && + GIMP_DRAWABLE (layer)->gimage != gimage) + { + g_warning ("%s: attempting to add layer to wrong image.", + G_GNUC_PRETTY_FUNCTION); + return FALSE; + } + + if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer))) + { + g_warning ("%s: trying to add layer to image twice.", + G_GNUC_PRETTY_FUNCTION); + return FALSE; + } + + /* Prepare a layer undo and push it */ + lu = g_new (LayerUndo, 1); + lu->layer = layer; + lu->prev_position = 0; + lu->prev_layer = gimp_image_get_active_layer (gimage); + undo_push_layer (gimage, LAYER_ADD_UNDO, lu); + + /* If the layer is a floating selection, set the ID */ + if (gimp_layer_is_floating_sel (layer)) + gimage->floating_sel = layer; + + /* let the layer know about the gimage */ + gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage); + + /* If the layer has a mask, set the mask's gimage */ + if (layer->mask) + { + gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage); + } + + /* add the layer to the list at the specified position */ + if (position == -1) + { + GimpLayer *active_layer; + + active_layer = gimp_image_get_active_layer (gimage); + + if (active_layer) + { + position = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (active_layer)); + } + else + { + position = 0; + } + } + + /* If there is a floating selection (and this isn't it!), + * make sure the insert position is greater than 0 + */ + if (position == 0 && + gimp_image_floating_sel (gimage) && + (gimage->floating_sel != layer)) + { + position = 1; + } + + gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position); + g_object_unref (G_OBJECT (layer)); + + /* notify the layers dialog of the currently active layer */ + gimp_image_set_active_layer (gimage, layer); + + /* update the new layer's area */ + gimp_drawable_update (GIMP_DRAWABLE (layer), + 0, 0, + gimp_drawable_width (GIMP_DRAWABLE (layer)), + gimp_drawable_height (GIMP_DRAWABLE (layer))); + + return TRUE; +} + +void +gimp_image_remove_layer (GimpImage *gimage, + GimpLayer *layer) +{ + LayerUndo *lu; + gint x, y, w, h; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (GIMP_IS_LAYER (layer)); + + g_return_if_fail (gimp_container_have (gimage->layers, + GIMP_OBJECT (layer))); + + /* Push a layer undo */ + lu = g_new (LayerUndo, 1); + lu->layer = layer; + lu->prev_position = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); + lu->prev_layer = layer; + + undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu); + + g_object_ref (G_OBJECT (layer)); + + gimp_container_remove (gimage->layers, GIMP_OBJECT (layer)); + gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer); + + /* If this was the floating selection, reset the fs pointer */ + if (gimage->floating_sel == layer) + { + gimage->floating_sel = NULL; + + floating_sel_reset (layer); + } + + if (layer == gimp_image_get_active_layer (gimage)) + { + if (gimage->layer_stack) + { + gimp_image_set_active_layer (gimage, gimage->layer_stack->data); + } + else + { + gimage->active_layer = NULL; + + g_signal_emit (G_OBJECT (gimage), + gimp_image_signals[ACTIVE_LAYER_CHANGED], 0); + } + } + + /* Send out REMOVED signal from layer */ + gimp_drawable_removed (GIMP_DRAWABLE (layer)); + + gimp_drawable_offsets (GIMP_DRAWABLE (layer), &x, &y); + w = gimp_drawable_width (GIMP_DRAWABLE (layer)); + h = gimp_drawable_height (GIMP_DRAWABLE (layer)); + + g_object_unref (G_OBJECT (layer)); + + gimp_image_update (gimage, x, y, w, h); + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); +} + +gboolean +gimp_image_raise_layer (GimpImage *gimage, + GimpLayer *layer) +{ + gint curpos; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + curpos = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); + + /* is this the top layer already? */ + if (curpos == 0) + { + g_message (_("Layer cannot be raised higher.")); + return FALSE; + } + + return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE); +} + +gboolean +gimp_image_lower_layer (GimpImage *gimage, + GimpLayer *layer) +{ + gint curpos; + gint length; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + curpos = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); + + /* is this the bottom layer already? */ + length = gimp_container_num_children (gimage->layers); + if (curpos >= length - 1) + { + g_message (_("Layer cannot be lowered more.")); + return FALSE; + } + + return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE); +} + +gboolean +gimp_image_raise_layer_to_top (GimpImage *gimage, + GimpLayer *layer) +{ + gint curpos; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + curpos = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); + + if (curpos == 0) + { + g_message (_("Layer is already on top.")); + return FALSE; + } + + if (! gimp_layer_has_alpha (layer)) + { + g_message (_("Cannot raise a layer without alpha.")); + return FALSE; + } + + return gimp_image_position_layer (gimage, layer, 0, TRUE); +} + +gboolean +gimp_image_lower_layer_to_bottom (GimpImage *gimage, + GimpLayer *layer) +{ + gint curpos; + gint length; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + curpos = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); + + length = gimp_container_num_children (gimage->layers); + + if (curpos >= length - 1) + { + g_message (_("Layer is already on the bottom.")); + return FALSE; + } + + return gimp_image_position_layer (gimage, layer, length - 1, TRUE); +} + +gboolean +gimp_image_position_layer (GimpImage *gimage, + GimpLayer *layer, + gint new_index, + gboolean push_undo) +{ + gint off_x, off_y; + gint index; + gint num_layers; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + index = gimp_container_get_child_index (gimage->layers, + GIMP_OBJECT (layer)); + if (index < 0) + return FALSE; + + num_layers = gimp_container_num_children (gimage->layers); + + if (new_index < 0) + new_index = 0; + + if (new_index >= num_layers) + new_index = num_layers - 1; + + if (new_index == index) + return TRUE; + + /* check if we want to move it below a bottom layer without alpha */ + if (new_index == num_layers - 1) + { + GimpLayer *tmp; + + tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, + num_layers - 1); + + if (new_index == num_layers - 1 && + ! gimp_layer_has_alpha (tmp)) + { + g_message (_("Layer \"%s\" has no alpha.\nLayer was placed above it."), + GIMP_OBJECT (tmp)->name); + new_index--; + } + } + + if (push_undo) + undo_push_layer_reposition (gimage, layer); + + gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); + + gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); + + gimp_image_update (gimage, + off_x, off_y, + gimp_drawable_width (GIMP_DRAWABLE (layer)), + gimp_drawable_height (GIMP_DRAWABLE (layer))); + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); + + return TRUE; +} + +gboolean +gimp_image_add_channel (GimpImage *gimage, + GimpChannel *channel, + gint position) +{ + ChannelUndo *cu; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); + + if (GIMP_DRAWABLE (channel)->gimage != NULL && + GIMP_DRAWABLE (channel)->gimage != gimage) + { + g_warning ("%s: attempting to add channel to wrong image.", + G_GNUC_PRETTY_FUNCTION); + return FALSE; + } + + if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel))) + { + g_warning ("%s: trying to add channel to image twice.", + G_GNUC_PRETTY_FUNCTION); + return FALSE; + } + + /* Push a channel undo */ + cu = g_new (ChannelUndo, 1); + cu->channel = channel; + cu->prev_position = 0; + cu->prev_channel = gimp_image_get_active_channel (gimage); + undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu); + + /* add the channel to the list */ + gimp_container_add (gimage->channels, GIMP_OBJECT (channel)); + g_object_unref (G_OBJECT (channel)); + + /* notify this gimage of the currently active channel */ + gimp_image_set_active_channel (gimage, channel); + + /* if channel is visible, update the image */ + if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) + gimp_drawable_update (GIMP_DRAWABLE (channel), + 0, 0, + gimp_drawable_width (GIMP_DRAWABLE (channel)), + gimp_drawable_height (GIMP_DRAWABLE (channel))); + + return TRUE; +} + +void +gimp_image_remove_channel (GimpImage *gimage, + GimpChannel *channel) +{ + ChannelUndo *cu; + + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (GIMP_IS_CHANNEL (channel)); + + g_return_if_fail (gimp_container_have (gimage->channels, + GIMP_OBJECT (channel))); + + /* Prepare a channel undo--push it below */ + cu = g_new (ChannelUndo, 1); + cu->channel = channel; + cu->prev_position = gimp_container_get_child_index (gimage->channels, + GIMP_OBJECT (channel)); + cu->prev_channel = gimp_image_get_active_channel (gimage); + undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu); + + g_object_ref (G_OBJECT (channel)); + + gimp_container_remove (gimage->channels, GIMP_OBJECT (channel)); + + /* Send out REMOVED signal from channel */ + gimp_drawable_removed (GIMP_DRAWABLE (channel)); + + if (channel == gimp_image_get_active_channel (gimage)) + { + if (gimp_container_num_children (gimage->channels) > 0) + { + gimp_image_set_active_channel + (gimage, + GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels, + 0))); + } + else + { + gimp_image_unset_active_channel (gimage); + } + } + + g_object_unref (G_OBJECT (channel)); + + gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); +} + +gboolean +gimp_image_raise_channel (GimpImage *gimage, + GimpChannel *channel) +{ + gint index; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); + + index = gimp_container_get_child_index (gimage->channels, + GIMP_OBJECT (channel)); + if (index == 0) + { + g_message (_("Channel cannot be raised higher.")); + return FALSE; + } + + return gimp_image_position_channel (gimage, channel, index - 1, TRUE); +} + +gboolean +gimp_image_lower_channel (GimpImage *gimage, + GimpChannel *channel) +{ + gint index; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); + + index = gimp_container_get_child_index (gimage->channels, + GIMP_OBJECT (channel)); + if (index == gimp_container_num_children (gimage->channels) - 1) + { + g_message (_("Channel cannot be lowered more.")); + return FALSE; + } + + return gimp_image_position_channel (gimage, channel, index + 1, TRUE); +} + +gboolean +gimp_image_position_channel (GimpImage *gimage, + GimpChannel *channel, + gint new_index, + gboolean push_undo /* FIXME unused */) +{ + gint index; + gint num_channels; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); + + index = gimp_container_get_child_index (gimage->channels, + GIMP_OBJECT (channel)); + if (index < 0) + return FALSE; + + num_channels = gimp_container_num_children (gimage->channels); + + new_index = CLAMP (new_index, 0, num_channels - 1); + + if (new_index == index) + return TRUE; + + gimp_container_reorder (gimage->channels, + GIMP_OBJECT (channel), new_index); + + gimp_drawable_update (GIMP_DRAWABLE (channel), + 0, 0, + gimp_drawable_width (GIMP_DRAWABLE (channel)), + gimp_drawable_height (GIMP_DRAWABLE (channel))); + + return TRUE; +} + +gboolean +gimp_image_layer_boundary (const GimpImage *gimage, + BoundSeg **segs, + gint *n_segs) +{ + GimpLayer *layer; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (segs != NULL, FALSE); + g_return_val_if_fail (n_segs != NULL, FALSE); + + /* The second boundary corresponds to the active layer's + * perimeter... + */ + layer = gimp_image_get_active_layer (gimage); + + if (layer) + { + *segs = gimp_layer_boundary (layer, n_segs); + return TRUE; + } + else + { + *segs = NULL; + *n_segs = 0; + return FALSE; + } +} + +GimpLayer * +gimp_image_pick_correlate_layer (const GimpImage *gimage, + gint x, + gint y) +{ + GimpLayer *layer; + GList *list; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + + for (list = GIMP_LIST (gimage->layers)->list; + list; + list = g_list_next (list)) + { + layer = (GimpLayer *) list->data; + + if (gimp_layer_pick_correlate (layer, x, y)) + return layer; + } + + return NULL; +} + +void +gimp_image_invalidate_layer_previews (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + gimp_container_foreach (gimage->layers, + (GFunc) gimp_viewable_invalidate_preview, + NULL); +} + +void +gimp_image_invalidate_channel_previews (GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + + gimp_container_foreach (gimage->channels, + (GFunc) gimp_viewable_invalidate_preview, + NULL); +} diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h index be0b5eea83..b4a5f8f062 100644 --- a/app/core/gimpimage.h +++ b/app/core/gimpimage.h @@ -164,277 +164,247 @@ struct _GimpImageClass }; -/* function declarations */ +GType gimp_image_get_type (void) G_GNUC_CONST; -GType gimp_image_get_type (void) G_GNUC_CONST; - -GimpImage * gimp_image_new (Gimp *gimp, - gint width, - gint height, - GimpImageBaseType base_type); +GimpImage * gimp_image_new (Gimp *gimp, + gint width, + gint height, + GimpImageBaseType base_type); -gint gimp_image_get_ID (GimpImage *gimage); -GimpImage * gimp_image_get_by_ID (Gimp *gimp, - gint id); +GimpImageBaseType gimp_image_base_type (const GimpImage *gimage); +GimpImageType gimp_image_base_type_with_alpha (const GimpImage *gimage); +CombinationMode gimp_image_get_combination_mode (GimpImageType dest_type, + gint src_bytes); -void gimp_image_set_filename (GimpImage *gimage, - const gchar *filename); -void gimp_image_set_resolution (GimpImage *gimage, - gdouble xres, - gdouble yres); -void gimp_image_get_resolution (const GimpImage *gimage, - gdouble *xresolution, - gdouble *yresolution); -void gimp_image_set_unit (GimpImage *gimage, - GimpUnit unit); -GimpUnit gimp_image_get_unit (const GimpImage *gimage); +gint gimp_image_get_ID (GimpImage *gimage); +GimpImage * gimp_image_get_by_ID (Gimp *gimp, + gint id); -void gimp_image_set_qmask_state (GimpImage *gimage, - gboolean qmask_state); -gboolean gimp_image_get_qmask_state (const GimpImage *gimage); +void gimp_image_set_filename (GimpImage *gimage, + const gchar *filename); +const gchar * gimp_image_get_filename (const GimpImage *gimage); -void gimp_image_set_save_proc (GimpImage *gimage, - PlugInProcDef *proc); -PlugInProcDef * gimp_image_get_save_proc (const GimpImage *gimage); +void gimp_image_set_save_proc (GimpImage *gimage, + PlugInProcDef *proc); +PlugInProcDef * gimp_image_get_save_proc (const GimpImage *gimage); -gint gimp_image_get_width (const GimpImage *gimage); -gint gimp_image_get_height (const GimpImage *gimage); +void gimp_image_set_resolution (GimpImage *gimage, + gdouble xres, + gdouble yres); +void gimp_image_get_resolution (const GimpImage *gimage, + gdouble *xres, + gdouble *yres); +void gimp_image_resolution_changed (GimpImage *gimage); -void gimp_image_resize (GimpImage *gimage, - gint new_width, - gint new_height, - gint offset_x, - gint offset_y); -void gimp_image_scale (GimpImage *gimage, - gint new_width, - gint new_height, - GimpProgressFunc progress_func, - gpointer progress_data); -gboolean gimp_image_check_scaling (const GimpImage *gimage, - gint new_width, - gint new_height); +void gimp_image_set_unit (GimpImage *gimage, + GimpUnit unit); +GimpUnit gimp_image_get_unit (const GimpImage *gimage); +void gimp_image_unit_changed (GimpImage *gimage); -TileManager * gimp_image_shadow (GimpImage *gimage, - gint width, - gint height, - gint bpp); -void gimp_image_free_shadow (GimpImage *gimage); +void gimp_image_set_qmask_state (GimpImage *gimage, + gboolean qmask_state); +gboolean gimp_image_get_qmask_state (const GimpImage *gimage); +void gimp_image_qmask_changed (GimpImage *gimage); -void gimp_image_apply_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - LayerModeEffects mode, - TileManager *src1_tiles, - gint x, - gint y); -void gimp_image_replace_image (GimpImage *gimage, - GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean undo, - gint opacity, - PixelRegion *maskPR, - gint x, - gint y); +gint gimp_image_get_width (const GimpImage *gimage); +gint gimp_image_get_height (const GimpImage *gimage); -void gimp_image_get_foreground (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *fg); -void gimp_image_get_background (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *bg); -void gimp_image_get_color (const GimpImage *gimage, - GimpImageType d_type, - guchar *rgb, - guchar *src); -void gimp_image_transform_color (const GimpImage *gimage, - const GimpDrawable *drawable, - guchar *src, - guchar *dest, - GimpImageBaseType type); +gboolean gimp_image_is_empty (const GimpImage *gimage); -GimpGuide * gimp_image_add_hguide (GimpImage *gimage); -GimpGuide * gimp_image_add_vguide (GimpImage *gimage); -void gimp_image_add_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_remove_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_delete_guide (GimpImage *gimage, - GimpGuide *guide); -GimpGuide * gimp_image_find_guide (GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_snap_point (GimpImage *gimage, - gint x, - gint y, - gint *tx, - gint *ty); -gboolean gimp_image_snap_rectangle (GimpImage *gimage, - gint x1, - gint y1, - gint x2, - gint y2, - gint *tx1, - gint *ty1); +GimpLayer * gimp_image_floating_sel (const GimpImage *gimage); +void gimp_image_floating_selection_changed (GimpImage *gimage); -GimpParasite * gimp_image_parasite_find (const GimpImage *gimage, - const gchar *name); -gchar ** gimp_image_parasite_list (const GimpImage *gimage, - gint *count); -void gimp_image_parasite_attach (GimpImage *gimage, - GimpParasite *parasite); -void gimp_image_parasite_detach (GimpImage *gimage, - const gchar *parasite); +guchar * gimp_image_get_colormap (const GimpImage *gimage); +void gimp_image_colormap_changed (GimpImage *gimage, + gint col); -GimpTattoo gimp_image_get_new_tattoo (GimpImage *gimage); -gboolean gimp_image_set_tattoo_state (GimpImage *gimage, - GimpTattoo val); -GimpTattoo gimp_image_get_tattoo_state (GimpImage *gimage); +GimpChannel * gimp_image_get_mask (const GimpImage *gimage); +void gimp_image_mask_changed (GimpImage *gimage); -void gimp_image_set_paths (GimpImage *gimage, - PathList *paths); -PathList * gimp_image_get_paths (const GimpImage *gimage); +void gimp_image_set_component_active (GimpImage *gimage, + ChannelType type, + gboolean active); +gboolean gimp_image_get_component_active (const GimpImage *gimage, + ChannelType type); +void gimp_image_get_active_components (GimpImage *gimage, + GimpDrawable *drawable, + gint *active); -/* Temporary hack till colormap manipulation is encapsulated in functions. - * Call this whenever you modify an image's colormap. The col argument - * specifies which color has changed, or negative if there's a bigger change. - * Currently, use this also when the image's base type is changed to/from - * indexed. - */ -void gimp_image_colormap_changed (GimpImage *gimage, - gint col); +void gimp_image_set_component_visible (GimpImage *gimage, + ChannelType type, + gboolean visible); +gboolean gimp_image_get_component_visible (const GimpImage *gimage, + ChannelType type); -void gimp_image_mode_changed (GimpImage *gimage); -void gimp_image_alpha_changed (GimpImage *gimage); -void gimp_image_floating_selection_changed (GimpImage *gimage); -void gimp_image_mask_changed (GimpImage *gimage); -void gimp_image_resolution_changed (GimpImage *gimage); -void gimp_image_unit_changed (GimpImage *gimage); -void gimp_image_qmask_changed (GimpImage *gimage); -void gimp_image_update (GimpImage *gimage, - gint x, - gint y, - gint width, - gint height); -void gimp_image_update_guide (GimpImage *gimage, - GimpGuide *guide); -void gimp_image_selection_control (GimpImage *gimage, - GimpSelectionControl control); +void gimp_image_mode_changed (GimpImage *gimage); +void gimp_image_alpha_changed (GimpImage *gimage); +void gimp_image_update (GimpImage *gimage, + gint x, + gint y, + gint width, + gint height); +void gimp_image_update_guide (GimpImage *gimage, + GimpGuide *guide); +void gimp_image_selection_control (GimpImage *gimage, + GimpSelectionControl control); -/* layer/channel functions */ +/* undo */ -GimpContainer * gimp_image_get_layers (const GimpImage *gimage); -GimpContainer * gimp_image_get_channels (const GimpImage *gimage); - -gint gimp_image_get_layer_index (const GimpImage *gimage, - const GimpLayer *layer); -gint gimp_image_get_channel_index (const GimpImage *gimage, - const GimpChannel *channel); -GimpLayer * gimp_image_get_active_layer (const GimpImage *gimage); -GimpChannel * gimp_image_get_active_channel (const GimpImage *gimage); -GimpLayer * gimp_image_get_layer_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_tattoo (const GimpImage *gimage, - GimpTattoo tatoo); -GimpChannel * gimp_image_get_channel_by_name (const GimpImage *gimage, - const gchar *name); -GimpChannel * gimp_image_get_mask (const GimpImage *gimage); - -void gimp_image_set_component_active (GimpImage *gimage, - ChannelType type, - gboolean active); -gboolean gimp_image_get_component_active (const GimpImage *gimage, - ChannelType type); -void gimp_image_get_active_components (GimpImage *gimage, - GimpDrawable *drawable, - gint *active); - -void gimp_image_set_component_visible (GimpImage *gimage, - ChannelType type, - gboolean visible); -gboolean gimp_image_get_component_visible (const GimpImage *gimage, - ChannelType type); - -gboolean gimp_image_layer_boundary (const GimpImage *gimage, - BoundSeg **segs, - gint *n_segs); -GimpLayer * gimp_image_set_active_layer (GimpImage *gimage, - GimpLayer *layer); -GimpChannel * gimp_image_set_active_channel (GimpImage *gimage, - GimpChannel *channel); -GimpChannel * gimp_image_unset_active_channel (GimpImage *gimage); -GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, - gint x, - gint y); -gboolean gimp_image_raise_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_layer_to_top (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_lower_layer_to_bottom (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_position_layer (GimpImage *gimage, - GimpLayer *layer, - gint new_index, - gboolean push_undo); -GimpLayer * gimp_image_merge_visible_layers (GimpImage *gimage, - MergeType merge_type); -GimpLayer * gimp_image_merge_down (GimpImage *gimage, - GimpLayer *current_layer, - MergeType merge_type); -GimpLayer * gimp_image_flatten (GimpImage *gimage); -GimpLayer * gimp_image_merge_layers (GimpImage *gimage, - GSList *merge_list, - MergeType merge_type); -gboolean gimp_image_add_layer (GimpImage *gimage, - GimpLayer *layer, - gint position); -void gimp_image_remove_layer (GimpImage *gimage, - GimpLayer *layer); -gboolean gimp_image_raise_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_lower_channel (GimpImage *gimage, - GimpChannel *channel); -gboolean gimp_image_position_channel (GimpImage *gimage, - GimpChannel *channel, - gint new_index, - gboolean push_undo); -gboolean gimp_image_add_channel (GimpImage *gimage, - GimpChannel *channel, - gint position); -void gimp_image_remove_channel (GimpImage *gimage, - GimpChannel *channel); - -void gimp_image_invalidate_layer_previews (GimpImage *gimage); -void gimp_image_invalidate_channel_previews (GimpImage *gimage); +gboolean gimp_image_undo_is_enabled (const GimpImage *gimage); +gboolean gimp_image_undo_enable (GimpImage *gimage); +gboolean gimp_image_undo_disable (GimpImage *gimage); +gboolean gimp_image_undo_freeze (GimpImage *gimage); +gboolean gimp_image_undo_thaw (GimpImage *gimage); +void gimp_image_undo_event (GimpImage *gimage, + gint event); +gint gimp_image_dirty (GimpImage *gimage); +gint gimp_image_clean (GimpImage *gimage); +void gimp_image_clean_all (GimpImage *gimage); -/* Access functions */ +/* color transforms / utilities */ -gboolean gimp_image_is_empty (const GimpImage *gimage); -GimpDrawable * gimp_image_active_drawable (const GimpImage *gimage); +void gimp_image_get_foreground (const GimpImage *gimage, + const GimpDrawable *drawable, + guchar *fg); +void gimp_image_get_background (const GimpImage *gimage, + const GimpDrawable *drawable, + guchar *bg); +void gimp_image_get_color (const GimpImage *gimage, + GimpImageType d_type, + guchar *rgb, + guchar *src); +void gimp_image_transform_color (const GimpImage *gimage, + const GimpDrawable *drawable, + guchar *src, + guchar *dest, + GimpImageBaseType type); -GimpImageBaseType gimp_image_base_type (const GimpImage *gimage); -GimpImageType gimp_image_base_type_with_alpha (const GimpImage *gimage); -const gchar * gimp_image_filename (const GimpImage *gimage); -gboolean gimp_image_undo_is_enabled (const GimpImage *gimage); -gboolean gimp_image_undo_enable (GimpImage *gimage); -gboolean gimp_image_undo_disable (GimpImage *gimage); -gboolean gimp_image_undo_freeze (GimpImage *gimage); -gboolean gimp_image_undo_thaw (GimpImage *gimage); -void gimp_image_undo_event (GimpImage *gimage, - gint event); -gint gimp_image_dirty (GimpImage *gimage); -gint gimp_image_clean (GimpImage *gimage); -void gimp_image_clean_all (GimpImage *gimage); -GimpLayer * gimp_image_floating_sel (const GimpImage *gimage); -guchar * gimp_image_cmap (const GimpImage *gimage); +/* shadow tiles */ -gboolean gimp_image_preview_valid (const GimpImage *gimage); +TileManager * gimp_image_shadow (GimpImage *gimage, + gint width, + gint height, + gint bpp); +void gimp_image_free_shadow (GimpImage *gimage); + + +/* combine functions */ + +void gimp_image_apply_image (GimpImage *gimage, + GimpDrawable *drawable, + PixelRegion *src2PR, + gboolean undo, + gint opacity, + LayerModeEffects mode, + TileManager *src1_tiles, + gint x, + gint y); +void gimp_image_replace_image (GimpImage *gimage, + GimpDrawable *drawable, + PixelRegion *src2PR, + gboolean undo, + gint opacity, + PixelRegion *maskPR, + gint x, + gint y); + + +/* parasites */ + +GimpParasite * gimp_image_parasite_find (const GimpImage *gimage, + const gchar *name); +gchar ** gimp_image_parasite_list (const GimpImage *gimage, + gint *count); +void gimp_image_parasite_attach (GimpImage *gimage, + GimpParasite *parasite); +void gimp_image_parasite_detach (GimpImage *gimage, + const gchar *parasite); + + +/* tattoos */ + +GimpTattoo gimp_image_get_new_tattoo (GimpImage *gimage); +gboolean gimp_image_set_tattoo_state (GimpImage *gimage, + GimpTattoo val); +GimpTattoo gimp_image_get_tattoo_state (GimpImage *gimage); + + +/* layers / channels / paths */ + +GimpContainer * gimp_image_get_layers (const GimpImage *gimage); +GimpContainer * gimp_image_get_channels (const GimpImage *gimage); + +void gimp_image_set_paths (GimpImage *gimage, + PathList *paths); +PathList * gimp_image_get_paths (const GimpImage *gimage); + +GimpDrawable * gimp_image_active_drawable (const GimpImage *gimage); +GimpLayer * gimp_image_get_active_layer (const GimpImage *gimage); +GimpChannel * gimp_image_get_active_channel (const GimpImage *gimage); + +GimpLayer * gimp_image_set_active_layer (GimpImage *gimage, + GimpLayer *layer); +GimpChannel * gimp_image_set_active_channel (GimpImage *gimage, + GimpChannel *channel); +GimpChannel * gimp_image_unset_active_channel (GimpImage *gimage); + +gint gimp_image_get_layer_index (const GimpImage *gimage, + const GimpLayer *layer); +gint gimp_image_get_channel_index (const GimpImage *gimage, + const GimpChannel *channel); +GimpLayer * gimp_image_get_layer_by_tattoo (const GimpImage *gimage, + GimpTattoo tatoo); +GimpChannel * gimp_image_get_channel_by_tattoo (const GimpImage *gimage, + GimpTattoo tatoo); +GimpChannel * gimp_image_get_channel_by_name (const GimpImage *gimage, + const gchar *name); + +gboolean gimp_image_add_layer (GimpImage *gimage, + GimpLayer *layer, + gint position); +void gimp_image_remove_layer (GimpImage *gimage, + GimpLayer *layer); + +gboolean gimp_image_raise_layer (GimpImage *gimage, + GimpLayer *layer); +gboolean gimp_image_lower_layer (GimpImage *gimage, + GimpLayer *layer); +gboolean gimp_image_raise_layer_to_top (GimpImage *gimage, + GimpLayer *layer); +gboolean gimp_image_lower_layer_to_bottom (GimpImage *gimage, + GimpLayer *layer); +gboolean gimp_image_position_layer (GimpImage *gimage, + GimpLayer *layer, + gint new_index, + gboolean push_undo); + +gboolean gimp_image_add_channel (GimpImage *gimage, + GimpChannel *channel, + gint position); +void gimp_image_remove_channel (GimpImage *gimage, + GimpChannel *channel); + +gboolean gimp_image_raise_channel (GimpImage *gimage, + GimpChannel *channel); +gboolean gimp_image_lower_channel (GimpImage *gimage, + GimpChannel *channel); +gboolean gimp_image_position_channel (GimpImage *gimage, + GimpChannel *channel, + gint new_index, + gboolean push_undo); + +gboolean gimp_image_layer_boundary (const GimpImage *gimage, + BoundSeg **segs, + gint *n_segs); +GimpLayer * gimp_image_pick_correlate_layer (const GimpImage *gimage, + gint x, + gint y); + +void gimp_image_invalidate_layer_previews (GimpImage *gimage); +void gimp_image_invalidate_channel_previews (GimpImage *gimage); #endif /* __GIMP_IMAGE_H__ */ diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c index a7dee7efc2..11a1d51bec 100644 --- a/app/core/gimpprojection.c +++ b/app/core/gimpprojection.c @@ -29,6 +29,8 @@ #include "core/gimpimage.h" #include "core/gimpimage-projection.h" +#include "tools/tools-types.h" + #include "tools/gimptool.h" #include "tools/tool_manager.h" diff --git a/app/core/gimpviewable.c b/app/core/gimpviewable.c index 876db652db..21ba378ac9 100644 --- a/app/core/gimpviewable.c +++ b/app/core/gimpviewable.c @@ -205,3 +205,70 @@ gimp_viewable_get_new_preview (GimpViewable *viewable, return NULL; } + +GdkPixbuf * +gimp_viewable_get_preview_pixbuf (GimpViewable *viewable, + gint width, + gint height) +{ + GdkPixbuf *pixbuf; + + g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + pixbuf = g_object_get_data (G_OBJECT (viewable), + "static-viewable-preview-pixbuf"); + + if (pixbuf && + gdk_pixbuf_get_width (pixbuf) == width && + gdk_pixbuf_get_height (pixbuf) == height) + { + return pixbuf; + } + + pixbuf = gimp_viewable_get_new_preview_pixbuf (viewable, width, height); + + g_object_set_data_full (G_OBJECT (viewable), "static-viewable-preview-pixbuf", + pixbuf, + (GDestroyNotify) g_object_unref); + + return pixbuf; +} + +GdkPixbuf * +gimp_viewable_get_new_preview_pixbuf (GimpViewable *viewable, + gint width, + gint height) +{ + TempBuf *temp_buf; + GdkPixbuf *pixbuf = NULL; + + g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + temp_buf = gimp_viewable_get_preview (viewable, width, height); + + if (temp_buf) + { + gint width; + gint height; + gint bytes; + + bytes = temp_buf->bytes; + width = temp_buf->width; + height = temp_buf->height; + + pixbuf = gdk_pixbuf_new_from_data (temp_buf_data (temp_buf), + GDK_COLORSPACE_RGB, + (bytes == 2) || (bytes == 4), + 8, + width, + height, + width * bytes, + NULL, NULL); + } + + return pixbuf; +} diff --git a/app/core/gimpviewable.h b/app/core/gimpviewable.h index 020b4cde6b..5ec3f26cbd 100644 --- a/app/core/gimpviewable.h +++ b/app/core/gimpviewable.h @@ -25,6 +25,8 @@ #include "gimpobject.h" +#include + #define GIMP_TYPE_VIEWABLE (gimp_viewable_get_type ()) #define GIMP_VIEWABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VIEWABLE, GimpViewable)) @@ -59,17 +61,24 @@ struct _GimpViewableClass }; -GType gimp_viewable_get_type (void) G_GNUC_CONST; +GType gimp_viewable_get_type (void) G_GNUC_CONST; -void gimp_viewable_invalidate_preview (GimpViewable *viewable); -void gimp_viewable_size_changed (GimpViewable *viewable); +void gimp_viewable_invalidate_preview (GimpViewable *viewable); +void gimp_viewable_size_changed (GimpViewable *viewable); -TempBuf * gimp_viewable_get_preview (GimpViewable *viewable, - gint width, - gint height); -TempBuf * gimp_viewable_get_new_preview (GimpViewable *viewable, - gint width, - gint height); +TempBuf * gimp_viewable_get_preview (GimpViewable *viewable, + gint width, + gint height); +TempBuf * gimp_viewable_get_new_preview (GimpViewable *viewable, + gint width, + gint height); + +GdkPixbuf * gimp_viewable_get_preview_pixbuf (GimpViewable *viewable, + gint width, + gint height); +GdkPixbuf * gimp_viewable_get_new_preview_pixbuf (GimpViewable *viewable, + gint width, + gint height); #endif /* __GIMP_VIEWABLE_H__ */ diff --git a/app/dialogs/info-window.c b/app/dialogs/info-window.c index e63f82c9b5..5425c17b32 100644 --- a/app/dialogs/info-window.c +++ b/app/dialogs/info-window.c @@ -374,7 +374,7 @@ info_window_title (GimpDisplay *gdisp) gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gdisp->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gdisp->gimage)); title = g_strdup_printf (_("Info: %s-%d.%d"), basename, diff --git a/app/dialogs/palette-import-dialog.c b/app/dialogs/palette-import-dialog.c index 58b1b2f3b1..3ba91db2c8 100644 --- a/app/dialogs/palette-import-dialog.c +++ b/app/dialogs/palette-import-dialog.c @@ -258,7 +258,8 @@ palette_import_image_sel_callback (GtkWidget *widget, gimage = GIMP_IMAGE (data); palette_import_update_image_preview (gimage); - basename = g_path_get_basename (gimp_image_filename (import_dialog->gimage)); + basename = + g_path_get_basename (gimp_image_get_filename (import_dialog->gimage)); lab = g_strdup_printf ("%s-%d", basename, @@ -278,7 +279,7 @@ palette_import_image_menu_add (GimpImage *gimage) gchar *basename; gchar *lab; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); lab = g_strdup_printf ("%s-%d", basename, @@ -389,7 +390,7 @@ palette_import_image_menu_activate (ImportDialog *import_dialog, gchar *lab; basename = - g_path_get_basename (gimp_image_filename (import_dialog->gimage)); + g_path_get_basename (gimp_image_get_filename (import_dialog->gimage)); lab = g_strdup_printf ("%s-%d", basename, @@ -405,7 +406,7 @@ palette_import_image_menu_activate (ImportDialog *import_dialog, } g_slist_free (list); - basename = g_path_get_basename (gimp_image_filename (import_dialog->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (import_dialog->gimage)); lab = g_strdup_printf ("%s-%d", basename, diff --git a/app/display/display-types.h b/app/display/display-types.h index 4540405ec9..70f086fbe1 100644 --- a/app/display/display-types.h +++ b/app/display/display-types.h @@ -20,7 +20,7 @@ #define __DISPLAY_TYPES_H__ -#include "tools/tools-types.h" +#include "widgets/widgets-types.h" typedef enum /*< skip >*/ diff --git a/app/display/gimpdisplay.c b/app/display/gimpdisplay.c index a7dee7efc2..11a1d51bec 100644 --- a/app/display/gimpdisplay.c +++ b/app/display/gimpdisplay.c @@ -29,6 +29,8 @@ #include "core/gimpimage.h" #include "core/gimpimage-projection.h" +#include "tools/tools-types.h" + #include "tools/gimptool.h" #include "tools/tool_manager.h" diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c index 88d5758f92..c8c0fd7b32 100644 --- a/app/display/gimpdisplayshell-callbacks.c +++ b/app/display/gimpdisplayshell-callbacks.c @@ -34,6 +34,8 @@ #include "core/gimplayer.h" #include "core/gimptoolinfo.h" +#include "tools/tools-types.h" + #include "tools/gimpfuzzyselecttool.h" #include "tools/gimpmovetool.h" #include "tools/tool_manager.h" diff --git a/app/display/gimpdisplayshell-dnd.c b/app/display/gimpdisplayshell-dnd.c index fe066ea431..d5e02ee3c0 100644 --- a/app/display/gimpdisplayshell-dnd.c +++ b/app/display/gimpdisplayshell-dnd.c @@ -27,6 +27,7 @@ #include "core/gimp.h" #include "core/gimpbuffer.h" +#include "core/gimpcontainer.h" #include "core/gimpcontext.h" #include "core/gimpdrawable.h" #include "core/gimpdrawable-bucket-fill.h" @@ -38,9 +39,6 @@ #include "paint-funcs/paint-funcs.h" -#include "tools/gimpbucketfilltool.h" -#include "tools/tool_manager.h" - #include "gimpdisplay.h" #include "gimpdisplayshell.h" #include "gimpdisplayshell-dnd.h" @@ -178,8 +176,9 @@ gimp_display_shell_bucket_fill (GimpImage *gimage, return; /* Get the bucket fill context */ - tool_info = tool_manager_get_info_by_type (gimage->gimp, - GIMP_TYPE_BUCKET_FILL_TOOL); + tool_info = (GimpToolInfo *) + gimp_container_get_child_by_name (gimage->gimp->tool_info_list, + "gimp:bucket_fill_tool"); if (tool_info && tool_info->context) { diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c index e492e9989f..c868aaa302 100644 --- a/app/display/gimpdisplayshell-draw.c +++ b/app/display/gimpdisplayshell-draw.c @@ -34,6 +34,7 @@ #include "core/gimpcontext.h" #include "core/gimpcontainer.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" @@ -47,6 +48,8 @@ #include "gui/info-window.h" +#include "tools/tools-types.h" + #include "tools/tool_manager.h" #include "gimpdisplay.h" @@ -99,7 +102,6 @@ static void gimp_display_shell_format_title (GimpDisplayShell *gdisp, gint title_len); static void gimp_display_shell_update_icon (GimpDisplayShell *gdisp); -static gboolean gimp_display_shell_update_icon_timer (gpointer data); static gboolean gimp_display_shell_update_icon_invoker (gpointer data); static void gimp_display_shell_update_icon_scheduler (GimpImage *gimage, gpointer data); @@ -210,11 +212,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->scroll_gc = NULL; - shell->icon = NULL; - shell->iconmask = NULL; - shell->iconsize = 32; - shell->icon_needs_update = FALSE; - shell->icon_timeout_id = 0; + shell->icon_size = 32; shell->icon_idle_id = 0; shell->current_cursor = (GdkCursorType) -1; @@ -275,30 +273,12 @@ gimp_display_shell_destroy (GtkObject *object) shell->scroll_gc = NULL; } - if (shell->icon_timeout_id) - { - g_source_remove (shell->icon_timeout_id); - shell->icon_timeout_id = 0; - } - if (shell->icon_idle_id) { g_source_remove (shell->icon_idle_id); shell->icon_idle_id = 0; } - if (shell->icon) - { - gdk_drawable_unref (shell->icon); - shell->icon = NULL; - } - - if (shell->iconmask) - { - gdk_drawable_unref (shell->iconmask); - shell->iconmask = NULL; - } - if (shell->padding_gc) { g_object_unref (G_OBJECT (shell->padding_gc)); @@ -830,7 +810,7 @@ gimp_display_shell_close (GimpDisplayShell *shell, { gchar *basename; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); gimp_display_shell_close_warning_dialog (shell, basename); @@ -960,6 +940,8 @@ gimp_display_shell_set_menu_sensitivity (GimpDisplayShell *shell) #define SET_ACTIVE(menu,condition) \ gimp_menu_item_set_active ("/" menu, (condition) != 0) +#define SET_LABEL(menu,label) \ + gimp_menu_item_set_label ("/" menu, (label)) #define SET_SENSITIVE(menu,condition) \ gimp_menu_item_set_sensitive ("/" menu, (condition) != 0) @@ -973,21 +955,30 @@ gimp_display_shell_set_menu_sensitivity (GimpDisplayShell *shell) SET_SENSITIVE ("Edit/Buffer", gdisp); if (gdisp) { - /* Interactive tools such as CURVES, COLOR_BALANCE, LEVELS disable */ - /* undo to fake some kind of atomic behaviour. G. R. Osgood #14072 */ + gchar *undo_name = NULL; + gchar *redo_name = NULL; if (gimp_image_undo_is_enabled (gimage)) - { - /* If undo/redo stacks are empty, disable respective menu */ + { + undo_name = (gchar *) undo_get_undo_name (gimage); + redo_name = (gchar *) undo_get_redo_name (gimage); + } + + if (undo_name) + undo_name = g_strdup_printf (_("Undo %s"), gettext (undo_name)); + + if (redo_name) + redo_name = g_strdup_printf (_("Redo %s"), gettext (redo_name)); + + SET_LABEL ("Edit/Undo", undo_name ? undo_name : _("Undo")); + SET_LABEL ("Edit/Redo", redo_name ? redo_name : _("Redo")); + + SET_SENSITIVE ("Edit/Undo", undo_name); + SET_SENSITIVE ("Edit/Redo", redo_name); + + g_free (undo_name); + g_free (redo_name); - SET_SENSITIVE ("Edit/Undo", undo_get_undo_name (gimage)); - SET_SENSITIVE ("Edit/Redo", undo_get_redo_name (gimage)); - } - else - { - SET_SENSITIVE ("Edit/Undo", FALSE); - SET_SENSITIVE ("Edit/Redo", FALSE); - } SET_SENSITIVE ("Edit/Cut", lp); SET_SENSITIVE ("Edit/Copy", lp); SET_SENSITIVE ("Edit/Buffer/Cut Named...", lp); @@ -1081,6 +1072,7 @@ gimp_display_shell_set_menu_sensitivity (GimpDisplayShell *shell) SET_SENSITIVE ("Script-Fu", gdisp && lp); #undef SET_ACTIVE +#undef SET_LABEL #undef SET_SENSITIVE plug_in_set_menu_sensitivity (type); @@ -2123,161 +2115,32 @@ gimp_display_shell_draw_cursor (GimpDisplayShell *shell) static void gimp_display_shell_update_icon (GimpDisplayShell *shell) { - GtkStyle *style; - GdkGC *icongc, *iconmaskgc; - GdkColormap *colormap; - GdkColor black, white; - gboolean success; - - TempBuf *icondata; - guchar *data; - gint width, height; - gdouble factor; + GdkPixbuf *pixbuf; + gint width, height; + gdouble factor; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); - if (! shell->icon) - { - shell->icon = gdk_pixmap_new (GTK_WIDGET (shell)->window, - shell->iconsize, - shell->iconsize, - -1); - shell->iconmask = gdk_pixmap_new (NULL, - shell->iconsize, - shell->iconsize, - 1); - } - - icongc = gdk_gc_new (shell->icon); - iconmaskgc = gdk_gc_new (shell->iconmask); - colormap = gdk_colormap_get_system (); /* or gdk_rgb_get_colormap () */ - - white.red = 255; - white.green = 255; - white.blue = 255; - gdk_colormap_alloc_colors (colormap, &white, 1, FALSE, TRUE, &success); - - black.red = 0; - black.green = 0; - black.blue = 0; - gdk_colormap_alloc_colors (colormap, &black, 1, FALSE, TRUE, &success); - - if (! shell->icon_needs_update) - return; - - style = gtk_widget_get_style (GTK_WIDGET (shell)); - - factor = ((gfloat) gimp_image_get_height (shell->gdisp->gimage)) / - gimp_image_get_width (shell->gdisp->gimage); + factor = ((gdouble) gimp_image_get_height (shell->gdisp->gimage) / + (gdouble) gimp_image_get_width (shell->gdisp->gimage)); if (factor >= 1) { - height = MAX (shell->iconsize, 1); - width = MAX (((gfloat) shell->iconsize) / factor, 1); + height = MAX (shell->icon_size, 1); + width = MAX (((gdouble) shell->icon_size) / factor, 1); } else { - height = MAX (((gfloat) shell->iconsize) * factor, 1); - width = MAX (shell->iconsize, 1); + height = MAX (((gdouble) shell->icon_size) * factor, 1); + width = MAX (shell->icon_size, 1); } - icondata = gimp_viewable_get_new_preview (GIMP_VIEWABLE (shell->gdisp->gimage), - width, height); - data = temp_buf_data (icondata); + pixbuf = gimp_viewable_get_new_preview_pixbuf (GIMP_VIEWABLE (shell->gdisp->gimage), + width, height); - /* Set up an icon mask */ - gdk_gc_set_foreground (iconmaskgc, &black); - gdk_draw_rectangle (shell->iconmask, iconmaskgc, TRUE, 0, 0, - shell->iconsize, - shell->iconsize); - - gdk_gc_set_foreground (iconmaskgc, &white); - gdk_draw_rectangle (shell->iconmask, iconmaskgc, TRUE, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height); + gtk_window_set_icon (GTK_WINDOW (shell), pixbuf); - /* This is an ugly bad hack. There should be a clean way to get - * a preview in a specified depth with a nicely rendered - * checkerboard if no alpha channel is requested. - * We ignore the alpha channel for now. Also the aspect ratio is - * incorrect. - * - * Currently the icons are updated when you press the "menu" button in - * the top left corner of the window. Of course this should go in an - * idle routine. - */ - if (icondata->bytes == 1) - { - gdk_draw_gray_image (shell->icon, - icongc, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height, - GDK_RGB_DITHER_MAX, - data, - icondata->width * icondata->bytes); - gdk_window_set_icon (GTK_WIDGET (shell)->window, - NULL, shell->icon, shell->iconmask); - } - else if (icondata->bytes == 3) - { - gdk_draw_rgb_image (shell->icon, - icongc, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height, - GDK_RGB_DITHER_MAX, - data, - icondata->width * icondata->bytes); - gdk_window_set_icon (GTK_WIDGET (shell)->window, - NULL, shell->icon, shell->iconmask); - } - else if (icondata->bytes == 4) - { - gdk_draw_rgb_32_image (shell->icon, - icongc, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height, - GDK_RGB_DITHER_MAX, - data, - icondata->width * icondata->bytes); - gdk_window_set_icon (GTK_WIDGET (shell)->window, - NULL, shell->icon, shell->iconmask); - } - else - { - g_printerr ("%s: falling back to default", G_STRLOC); - } - - shell->icon_needs_update = FALSE; - - gdk_gc_unref (icongc); - gdk_gc_unref (iconmaskgc); - - temp_buf_free (icondata); -} - -/* this timer is necessary to check if the icon is invalid and if yes - * adds the update function to the idle loop - */ -static gboolean -gimp_display_shell_update_icon_timer (gpointer data) -{ - GimpDisplayShell *shell; - - shell = GIMP_DISPLAY_SHELL (data); - - if (shell->icon_needs_update && ! shell->icon_idle_id) - shell->icon_idle_id = g_idle_add (gimp_display_shell_update_icon_invoker, - shell); - - return TRUE; + g_object_unref (G_OBJECT (pixbuf)); } /* Just a dumb invoker for gdisplay_update_icon () @@ -2289,10 +2152,10 @@ gimp_display_shell_update_icon_invoker (gpointer data) shell = GIMP_DISPLAY_SHELL (data); - gimp_display_shell_update_icon (shell); - shell->icon_idle_id = 0; + gimp_display_shell_update_icon (shell); + return FALSE; } @@ -2307,20 +2170,15 @@ gimp_display_shell_update_icon_scheduler (GimpImage *gimage, shell = GIMP_DISPLAY_SHELL (data); - shell->icon_needs_update = TRUE; - - if (! shell->icon_timeout_id) + if (shell->icon_idle_id) { - shell->icon_timeout_id = g_timeout_add (7500, - gimp_display_shell_update_icon_timer, - shell); - - if (! shell->icon_idle_id) - { - shell->icon_idle_id = g_idle_add (gimp_display_shell_update_icon_invoker, - shell); - } + g_source_remove (shell->icon_idle_id); } + + shell->icon_idle_id = g_idle_add_full (G_PRIORITY_LOW, + gimp_display_shell_update_icon_invoker, + shell, + NULL); } static int print (char *, int, int, const char *, ...) G_GNUC_PRINTF (4, 5); @@ -2398,7 +2256,8 @@ gimp_display_shell_format_title (GimpDisplayShell *shell, { gchar *basename; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = + g_path_get_basename (gimp_image_get_filename (gimage)); i += print (title, title_len, i, "%s", basename); @@ -2407,7 +2266,7 @@ gimp_display_shell_format_title (GimpDisplayShell *shell, break; case 'F': /* full filename */ - i += print (title, title_len, i, "%s", gimp_image_filename (gimage)); + i += print (title, title_len, i, "%s", gimp_image_get_filename (gimage)); break; case 'p': /* PDB id */ diff --git a/app/display/gimpdisplayshell-draw.h b/app/display/gimpdisplayshell-draw.h index 0182096298..caf8f274a8 100644 --- a/app/display/gimpdisplayshell-draw.h +++ b/app/display/gimpdisplayshell-draw.h @@ -80,6 +80,7 @@ struct _GimpDisplayShell GtkWidget *hrule; /* rulers */ GtkWidget *vrule; GtkWidget *origin; /* origin button */ + GtkWidget *statusarea; /* status area hbox */ GtkWidget *statusbar; /* statusbar */ GtkWidget *progressbar; /* progressbar */ @@ -90,11 +91,7 @@ struct _GimpDisplayShell GdkGC *scroll_gc; /* GC for scrolling */ - GdkPixmap *icon; /* Pixmap for the icon */ - GdkBitmap *iconmask; /* Bitmap for the icon mask */ - guint iconsize; /* size of the icon pixmap */ - gboolean icon_needs_update; /* Do we need to render a new icon? */ - guint icon_timeout_id; /* ID of the timeout-function */ + gint icon_size; /* size of the icon pixmap */ guint icon_idle_id; /* ID of the idle-function */ GdkCursorType current_cursor; /* Currently installed main cursor */ diff --git a/app/display/gimpdisplayshell-render.c b/app/display/gimpdisplayshell-render.c index 2931892858..055d7703b7 100644 --- a/app/display/gimpdisplayshell-render.c +++ b/app/display/gimpdisplayshell-render.c @@ -281,7 +281,7 @@ render_image_indexed (RenderInfo *info) gfloat error; gfloat step; - cmap = gimp_image_cmap (info->gdisp->gimage); + cmap = gimp_image_get_colormap (info->gdisp->gimage); y = info->y; ye = info->y + info->h; @@ -355,7 +355,7 @@ render_image_indexed_a (RenderInfo *info) gfloat error; gfloat step; - cmap = gimp_image_cmap (info->gdisp->gimage); + cmap = gimp_image_get_colormap (info->gdisp->gimage); alpha = info->alpha; y = info->y; diff --git a/app/display/gimpdisplayshell-scale.c b/app/display/gimpdisplayshell-scale.c index a2bdf18394..087a2bc722 100644 --- a/app/display/gimpdisplayshell-scale.c +++ b/app/display/gimpdisplayshell-scale.c @@ -28,7 +28,8 @@ #include "core/gimpimage.h" -#include "tools/gimptool.h" +#include "tools/tools-types.h" + #include "tools/tool_manager.h" #include "gimpdisplay.h" diff --git a/app/display/gimpdisplayshell-scroll.c b/app/display/gimpdisplayshell-scroll.c index 23d7043809..1e5d506950 100644 --- a/app/display/gimpdisplayshell-scroll.c +++ b/app/display/gimpdisplayshell-scroll.c @@ -26,7 +26,8 @@ #include "core/gimpimage.h" -#include "tools/gimptool.h" +#include "tools/tools-types.h" + #include "tools/tool_manager.h" #include "gimpdisplay.h" diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index e492e9989f..c868aaa302 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -34,6 +34,7 @@ #include "core/gimpcontext.h" #include "core/gimpcontainer.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" @@ -47,6 +48,8 @@ #include "gui/info-window.h" +#include "tools/tools-types.h" + #include "tools/tool_manager.h" #include "gimpdisplay.h" @@ -99,7 +102,6 @@ static void gimp_display_shell_format_title (GimpDisplayShell *gdisp, gint title_len); static void gimp_display_shell_update_icon (GimpDisplayShell *gdisp); -static gboolean gimp_display_shell_update_icon_timer (gpointer data); static gboolean gimp_display_shell_update_icon_invoker (gpointer data); static void gimp_display_shell_update_icon_scheduler (GimpImage *gimage, gpointer data); @@ -210,11 +212,7 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->scroll_gc = NULL; - shell->icon = NULL; - shell->iconmask = NULL; - shell->iconsize = 32; - shell->icon_needs_update = FALSE; - shell->icon_timeout_id = 0; + shell->icon_size = 32; shell->icon_idle_id = 0; shell->current_cursor = (GdkCursorType) -1; @@ -275,30 +273,12 @@ gimp_display_shell_destroy (GtkObject *object) shell->scroll_gc = NULL; } - if (shell->icon_timeout_id) - { - g_source_remove (shell->icon_timeout_id); - shell->icon_timeout_id = 0; - } - if (shell->icon_idle_id) { g_source_remove (shell->icon_idle_id); shell->icon_idle_id = 0; } - if (shell->icon) - { - gdk_drawable_unref (shell->icon); - shell->icon = NULL; - } - - if (shell->iconmask) - { - gdk_drawable_unref (shell->iconmask); - shell->iconmask = NULL; - } - if (shell->padding_gc) { g_object_unref (G_OBJECT (shell->padding_gc)); @@ -830,7 +810,7 @@ gimp_display_shell_close (GimpDisplayShell *shell, { gchar *basename; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); gimp_display_shell_close_warning_dialog (shell, basename); @@ -960,6 +940,8 @@ gimp_display_shell_set_menu_sensitivity (GimpDisplayShell *shell) #define SET_ACTIVE(menu,condition) \ gimp_menu_item_set_active ("/" menu, (condition) != 0) +#define SET_LABEL(menu,label) \ + gimp_menu_item_set_label ("/" menu, (label)) #define SET_SENSITIVE(menu,condition) \ gimp_menu_item_set_sensitive ("/" menu, (condition) != 0) @@ -973,21 +955,30 @@ gimp_display_shell_set_menu_sensitivity (GimpDisplayShell *shell) SET_SENSITIVE ("Edit/Buffer", gdisp); if (gdisp) { - /* Interactive tools such as CURVES, COLOR_BALANCE, LEVELS disable */ - /* undo to fake some kind of atomic behaviour. G. R. Osgood #14072 */ + gchar *undo_name = NULL; + gchar *redo_name = NULL; if (gimp_image_undo_is_enabled (gimage)) - { - /* If undo/redo stacks are empty, disable respective menu */ + { + undo_name = (gchar *) undo_get_undo_name (gimage); + redo_name = (gchar *) undo_get_redo_name (gimage); + } + + if (undo_name) + undo_name = g_strdup_printf (_("Undo %s"), gettext (undo_name)); + + if (redo_name) + redo_name = g_strdup_printf (_("Redo %s"), gettext (redo_name)); + + SET_LABEL ("Edit/Undo", undo_name ? undo_name : _("Undo")); + SET_LABEL ("Edit/Redo", redo_name ? redo_name : _("Redo")); + + SET_SENSITIVE ("Edit/Undo", undo_name); + SET_SENSITIVE ("Edit/Redo", redo_name); + + g_free (undo_name); + g_free (redo_name); - SET_SENSITIVE ("Edit/Undo", undo_get_undo_name (gimage)); - SET_SENSITIVE ("Edit/Redo", undo_get_redo_name (gimage)); - } - else - { - SET_SENSITIVE ("Edit/Undo", FALSE); - SET_SENSITIVE ("Edit/Redo", FALSE); - } SET_SENSITIVE ("Edit/Cut", lp); SET_SENSITIVE ("Edit/Copy", lp); SET_SENSITIVE ("Edit/Buffer/Cut Named...", lp); @@ -1081,6 +1072,7 @@ gimp_display_shell_set_menu_sensitivity (GimpDisplayShell *shell) SET_SENSITIVE ("Script-Fu", gdisp && lp); #undef SET_ACTIVE +#undef SET_LABEL #undef SET_SENSITIVE plug_in_set_menu_sensitivity (type); @@ -2123,161 +2115,32 @@ gimp_display_shell_draw_cursor (GimpDisplayShell *shell) static void gimp_display_shell_update_icon (GimpDisplayShell *shell) { - GtkStyle *style; - GdkGC *icongc, *iconmaskgc; - GdkColormap *colormap; - GdkColor black, white; - gboolean success; - - TempBuf *icondata; - guchar *data; - gint width, height; - gdouble factor; + GdkPixbuf *pixbuf; + gint width, height; + gdouble factor; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); - if (! shell->icon) - { - shell->icon = gdk_pixmap_new (GTK_WIDGET (shell)->window, - shell->iconsize, - shell->iconsize, - -1); - shell->iconmask = gdk_pixmap_new (NULL, - shell->iconsize, - shell->iconsize, - 1); - } - - icongc = gdk_gc_new (shell->icon); - iconmaskgc = gdk_gc_new (shell->iconmask); - colormap = gdk_colormap_get_system (); /* or gdk_rgb_get_colormap () */ - - white.red = 255; - white.green = 255; - white.blue = 255; - gdk_colormap_alloc_colors (colormap, &white, 1, FALSE, TRUE, &success); - - black.red = 0; - black.green = 0; - black.blue = 0; - gdk_colormap_alloc_colors (colormap, &black, 1, FALSE, TRUE, &success); - - if (! shell->icon_needs_update) - return; - - style = gtk_widget_get_style (GTK_WIDGET (shell)); - - factor = ((gfloat) gimp_image_get_height (shell->gdisp->gimage)) / - gimp_image_get_width (shell->gdisp->gimage); + factor = ((gdouble) gimp_image_get_height (shell->gdisp->gimage) / + (gdouble) gimp_image_get_width (shell->gdisp->gimage)); if (factor >= 1) { - height = MAX (shell->iconsize, 1); - width = MAX (((gfloat) shell->iconsize) / factor, 1); + height = MAX (shell->icon_size, 1); + width = MAX (((gdouble) shell->icon_size) / factor, 1); } else { - height = MAX (((gfloat) shell->iconsize) * factor, 1); - width = MAX (shell->iconsize, 1); + height = MAX (((gdouble) shell->icon_size) * factor, 1); + width = MAX (shell->icon_size, 1); } - icondata = gimp_viewable_get_new_preview (GIMP_VIEWABLE (shell->gdisp->gimage), - width, height); - data = temp_buf_data (icondata); + pixbuf = gimp_viewable_get_new_preview_pixbuf (GIMP_VIEWABLE (shell->gdisp->gimage), + width, height); - /* Set up an icon mask */ - gdk_gc_set_foreground (iconmaskgc, &black); - gdk_draw_rectangle (shell->iconmask, iconmaskgc, TRUE, 0, 0, - shell->iconsize, - shell->iconsize); - - gdk_gc_set_foreground (iconmaskgc, &white); - gdk_draw_rectangle (shell->iconmask, iconmaskgc, TRUE, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height); + gtk_window_set_icon (GTK_WINDOW (shell), pixbuf); - /* This is an ugly bad hack. There should be a clean way to get - * a preview in a specified depth with a nicely rendered - * checkerboard if no alpha channel is requested. - * We ignore the alpha channel for now. Also the aspect ratio is - * incorrect. - * - * Currently the icons are updated when you press the "menu" button in - * the top left corner of the window. Of course this should go in an - * idle routine. - */ - if (icondata->bytes == 1) - { - gdk_draw_gray_image (shell->icon, - icongc, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height, - GDK_RGB_DITHER_MAX, - data, - icondata->width * icondata->bytes); - gdk_window_set_icon (GTK_WIDGET (shell)->window, - NULL, shell->icon, shell->iconmask); - } - else if (icondata->bytes == 3) - { - gdk_draw_rgb_image (shell->icon, - icongc, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height, - GDK_RGB_DITHER_MAX, - data, - icondata->width * icondata->bytes); - gdk_window_set_icon (GTK_WIDGET (shell)->window, - NULL, shell->icon, shell->iconmask); - } - else if (icondata->bytes == 4) - { - gdk_draw_rgb_32_image (shell->icon, - icongc, - (shell->iconsize - icondata->width) / 2, - (shell->iconsize - icondata->height) / 2, - icondata->width, - icondata->height, - GDK_RGB_DITHER_MAX, - data, - icondata->width * icondata->bytes); - gdk_window_set_icon (GTK_WIDGET (shell)->window, - NULL, shell->icon, shell->iconmask); - } - else - { - g_printerr ("%s: falling back to default", G_STRLOC); - } - - shell->icon_needs_update = FALSE; - - gdk_gc_unref (icongc); - gdk_gc_unref (iconmaskgc); - - temp_buf_free (icondata); -} - -/* this timer is necessary to check if the icon is invalid and if yes - * adds the update function to the idle loop - */ -static gboolean -gimp_display_shell_update_icon_timer (gpointer data) -{ - GimpDisplayShell *shell; - - shell = GIMP_DISPLAY_SHELL (data); - - if (shell->icon_needs_update && ! shell->icon_idle_id) - shell->icon_idle_id = g_idle_add (gimp_display_shell_update_icon_invoker, - shell); - - return TRUE; + g_object_unref (G_OBJECT (pixbuf)); } /* Just a dumb invoker for gdisplay_update_icon () @@ -2289,10 +2152,10 @@ gimp_display_shell_update_icon_invoker (gpointer data) shell = GIMP_DISPLAY_SHELL (data); - gimp_display_shell_update_icon (shell); - shell->icon_idle_id = 0; + gimp_display_shell_update_icon (shell); + return FALSE; } @@ -2307,20 +2170,15 @@ gimp_display_shell_update_icon_scheduler (GimpImage *gimage, shell = GIMP_DISPLAY_SHELL (data); - shell->icon_needs_update = TRUE; - - if (! shell->icon_timeout_id) + if (shell->icon_idle_id) { - shell->icon_timeout_id = g_timeout_add (7500, - gimp_display_shell_update_icon_timer, - shell); - - if (! shell->icon_idle_id) - { - shell->icon_idle_id = g_idle_add (gimp_display_shell_update_icon_invoker, - shell); - } + g_source_remove (shell->icon_idle_id); } + + shell->icon_idle_id = g_idle_add_full (G_PRIORITY_LOW, + gimp_display_shell_update_icon_invoker, + shell, + NULL); } static int print (char *, int, int, const char *, ...) G_GNUC_PRINTF (4, 5); @@ -2398,7 +2256,8 @@ gimp_display_shell_format_title (GimpDisplayShell *shell, { gchar *basename; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = + g_path_get_basename (gimp_image_get_filename (gimage)); i += print (title, title_len, i, "%s", basename); @@ -2407,7 +2266,7 @@ gimp_display_shell_format_title (GimpDisplayShell *shell, break; case 'F': /* full filename */ - i += print (title, title_len, i, "%s", gimp_image_filename (gimage)); + i += print (title, title_len, i, "%s", gimp_image_get_filename (gimage)); break; case 'p': /* PDB id */ diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h index 0182096298..caf8f274a8 100644 --- a/app/display/gimpdisplayshell.h +++ b/app/display/gimpdisplayshell.h @@ -80,6 +80,7 @@ struct _GimpDisplayShell GtkWidget *hrule; /* rulers */ GtkWidget *vrule; GtkWidget *origin; /* origin button */ + GtkWidget *statusarea; /* status area hbox */ GtkWidget *statusbar; /* statusbar */ GtkWidget *progressbar; /* progressbar */ @@ -90,11 +91,7 @@ struct _GimpDisplayShell GdkGC *scroll_gc; /* GC for scrolling */ - GdkPixmap *icon; /* Pixmap for the icon */ - GdkBitmap *iconmask; /* Bitmap for the icon mask */ - guint iconsize; /* size of the icon pixmap */ - gboolean icon_needs_update; /* Do we need to render a new icon? */ - guint icon_timeout_id; /* ID of the timeout-function */ + gint icon_size; /* size of the icon pixmap */ guint icon_idle_id; /* ID of the idle-function */ GdkCursorType current_cursor; /* Currently installed main cursor */ diff --git a/app/display/gimpnavigationeditor.c b/app/display/gimpnavigationeditor.c index b6205093be..624d99727c 100644 --- a/app/display/gimpnavigationeditor.c +++ b/app/display/gimpnavigationeditor.c @@ -662,7 +662,7 @@ nav_dialog_title (GimpDisplay *gdisp) gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gdisp->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gdisp->gimage)); title = g_strdup_printf (_("Navigation: %s-%d.%d"), basename, diff --git a/app/display/gimpnavigationview.c b/app/display/gimpnavigationview.c index b6205093be..624d99727c 100644 --- a/app/display/gimpnavigationview.c +++ b/app/display/gimpnavigationview.c @@ -662,7 +662,7 @@ nav_dialog_title (GimpDisplay *gdisp) gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gdisp->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gdisp->gimage)); title = g_strdup_printf (_("Navigation: %s-%d.%d"), basename, diff --git a/app/gui/gui-types.h b/app/gui/gui-types.h index 172a5ce13c..e2131aa6a8 100644 --- a/app/gui/gui-types.h +++ b/app/gui/gui-types.h @@ -20,8 +20,7 @@ #define __GUI_TYPES_H__ -#include "widgets/widgets-types.h" -#include "display/display-types.h" +#include "tools/tools-types.h" typedef struct _ColorNotebook ColorNotebook; diff --git a/app/gui/image-commands.c b/app/gui/image-commands.c index d2f6b4fa3d..6c07c7632f 100644 --- a/app/gui/image-commands.c +++ b/app/gui/image-commands.c @@ -31,6 +31,8 @@ #include "core/gimpdrawable-equalize.h" #include "core/gimpimage.h" #include "core/gimpimage-duplicate.h" +#include "core/gimpimage-resize.h" +#include "core/gimpimage-scale.h" #include "pdb/procedural_db.h" diff --git a/app/gui/info-window.c b/app/gui/info-window.c index e63f82c9b5..5425c17b32 100644 --- a/app/gui/info-window.c +++ b/app/gui/info-window.c @@ -374,7 +374,7 @@ info_window_title (GimpDisplay *gdisp) gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gdisp->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gdisp->gimage)); title = g_strdup_printf (_("Info: %s-%d.%d"), basename, diff --git a/app/gui/layers-commands.c b/app/gui/layers-commands.c index ff50ec7b73..8ca4d9a538 100644 --- a/app/gui/layers-commands.c +++ b/app/gui/layers-commands.c @@ -33,6 +33,7 @@ #include "core/gimp.h" #include "core/gimpimage.h" #include "core/gimpimage-mask.h" +#include "core/gimpimage-merge.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" #include "core/gimplist.h" diff --git a/app/gui/palette-import-dialog.c b/app/gui/palette-import-dialog.c index 58b1b2f3b1..3ba91db2c8 100644 --- a/app/gui/palette-import-dialog.c +++ b/app/gui/palette-import-dialog.c @@ -258,7 +258,8 @@ palette_import_image_sel_callback (GtkWidget *widget, gimage = GIMP_IMAGE (data); palette_import_update_image_preview (gimage); - basename = g_path_get_basename (gimp_image_filename (import_dialog->gimage)); + basename = + g_path_get_basename (gimp_image_get_filename (import_dialog->gimage)); lab = g_strdup_printf ("%s-%d", basename, @@ -278,7 +279,7 @@ palette_import_image_menu_add (GimpImage *gimage) gchar *basename; gchar *lab; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); lab = g_strdup_printf ("%s-%d", basename, @@ -389,7 +390,7 @@ palette_import_image_menu_activate (ImportDialog *import_dialog, gchar *lab; basename = - g_path_get_basename (gimp_image_filename (import_dialog->gimage)); + g_path_get_basename (gimp_image_get_filename (import_dialog->gimage)); lab = g_strdup_printf ("%s-%d", basename, @@ -405,7 +406,7 @@ palette_import_image_menu_activate (ImportDialog *import_dialog, } g_slist_free (list); - basename = g_path_get_basename (gimp_image_filename (import_dialog->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (import_dialog->gimage)); lab = g_strdup_printf ("%s-%d", basename, diff --git a/app/gui/plug-in-commands.c b/app/gui/plug-in-commands.c index b5a352ecaa..e85060d12b 100644 --- a/app/gui/plug-in-commands.c +++ b/app/gui/plug-in-commands.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/gui/plug-in-menus.c b/app/gui/plug-in-menus.c index b5a352ecaa..e85060d12b 100644 --- a/app/gui/plug-in-menus.c +++ b/app/gui/plug-in-menus.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/menus/plug-in-menus.c b/app/menus/plug-in-menus.c index b5a352ecaa..e85060d12b 100644 --- a/app/menus/plug-in-menus.c +++ b/app/menus/plug-in-menus.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/nav_window.c b/app/nav_window.c index b6205093be..624d99727c 100644 --- a/app/nav_window.c +++ b/app/nav_window.c @@ -662,7 +662,7 @@ nav_dialog_title (GimpDisplay *gdisp) gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gdisp->gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gdisp->gimage)); title = g_strdup_printf (_("Navigation: %s-%d.%d"), basename, diff --git a/app/paint-funcs/Makefile.am b/app/paint-funcs/Makefile.am index dc24f091ac..13ff5c0911 100644 --- a/app/paint-funcs/Makefile.am +++ b/app/paint-funcs/Makefile.am @@ -10,6 +10,7 @@ mmx_sources = endif libapppaint_funcs_a_SOURCES = @STRIP_BEGIN@ \ + paint-funcs-types.h \ paint-funcs.c \ paint-funcs.h \ paint-funcs-generic.h \ diff --git a/app/paint-funcs/paint-funcs-types.h b/app/paint-funcs/paint-funcs-types.h new file mode 100644 index 0000000000..c0ce2f1868 --- /dev/null +++ b/app/paint-funcs/paint-funcs-types.h @@ -0,0 +1,77 @@ +/* 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. + */ + +#ifndef __PAINT_FUNCS_TYPES_H__ +#define __PAINT_FUNCS_TYPES_H__ + + +#include "base/base-types.h" + + +/* Opacities */ +#define TRANSPARENT_OPACITY 0 +#define OPAQUE_OPACITY 255 + + +/* Lay down the groundwork for layer construction... + * This includes background images for indexed or non-alpha + * images, floating selections, selective display of intensity + * channels, and display of arbitrary mask channels + */ +typedef enum /*< skip >*/ +{ + INITIAL_CHANNEL_MASK = 0, + INITIAL_CHANNEL_SELECTION, + INITIAL_INDEXED, + INITIAL_INDEXED_ALPHA, + INITIAL_INTENSITY, + INITIAL_INTENSITY_ALPHA, +} InitialMode; + +/* Combine two source regions with the help of an optional mask + * region into a destination region. This is used for constructing + * layer projections, and for applying image patches to an image + */ +typedef enum /*< skip >*/ +{ + NO_COMBINATION = 0, + COMBINE_INDEXED_INDEXED, + COMBINE_INDEXED_INDEXED_A, + COMBINE_INDEXED_A_INDEXED_A, + COMBINE_INTEN_A_INDEXED_A, + COMBINE_INTEN_A_CHANNEL_MASK, + COMBINE_INTEN_A_CHANNEL_SELECTION, + COMBINE_INTEN_INTEN, + COMBINE_INTEN_INTEN_A, + COMBINE_INTEN_A_INTEN, + COMBINE_INTEN_A_INTEN_A, + + /* Non-conventional combination modes */ + BEHIND_INTEN, + BEHIND_INDEXED, + REPLACE_INTEN, + REPLACE_INDEXED, + ERASE_INTEN, + ERASE_INDEXED, + ANTI_ERASE_INTEN, + ANTI_ERASE_INDEXED, + COLOR_ERASE_INTEN, +} CombinationMode; + + +#endif /* __PAINT_FUNCS_TYPES_H__ */ diff --git a/app/paint-funcs/paint-funcs.c b/app/paint-funcs/paint-funcs.c index aec43ba38a..cc9492c207 100644 --- a/app/paint-funcs/paint-funcs.c +++ b/app/paint-funcs/paint-funcs.c @@ -27,7 +27,7 @@ #include "libgimpcolor/gimpcolor.h" #include "libgimpmath/gimpmath.h" -#include "base/base-types.h" +#include "paint-funcs-types.h" #include "base/base-config.h" #include "base/pixel-processor.h" diff --git a/app/paint-funcs/paint-funcs.h b/app/paint-funcs/paint-funcs.h index d3578b917a..ebb8ccdcc5 100644 --- a/app/paint-funcs/paint-funcs.h +++ b/app/paint-funcs/paint-funcs.h @@ -341,54 +341,6 @@ void combine_mask_and_region (PixelRegion *, PixelRegion *, guint); /* Copy a gray image to an intensity-alpha region */ void copy_gray_to_region (PixelRegion *, PixelRegion *); -/* Lay down the groundwork for layer construction... - * This includes background images for indexed or non-alpha - * images, floating selections, selective display of intensity - * channels, and display of arbitrary mask channels - */ -typedef enum /*< skip >*/ -{ -INITIAL_CHANNEL_MASK = 0, -INITIAL_CHANNEL_SELECTION, -INITIAL_INDEXED, -INITIAL_INDEXED_ALPHA, -INITIAL_INTENSITY, -INITIAL_INTENSITY_ALPHA, -} InitialMode; - -/* Combine two source regions with the help of an optional mask - * region into a destination region. This is used for constructing - * layer projections, and for applying image patches to an image - */ -typedef enum /*< skip >*/ -{ - NO_COMBINATION = 0, - COMBINE_INDEXED_INDEXED, - COMBINE_INDEXED_INDEXED_A, - COMBINE_INDEXED_A_INDEXED_A, - COMBINE_INTEN_A_INDEXED_A, - COMBINE_INTEN_A_CHANNEL_MASK, - COMBINE_INTEN_A_CHANNEL_SELECTION, - COMBINE_INTEN_INTEN, - COMBINE_INTEN_INTEN_A, - COMBINE_INTEN_A_INTEN, - COMBINE_INTEN_A_INTEN_A, - - /* Non-conventional combination modes */ - BEHIND_INTEN, - BEHIND_INDEXED, - REPLACE_INTEN, - REPLACE_INDEXED, - ERASE_INTEN, - ERASE_INDEXED, - ANTI_ERASE_INTEN, - ANTI_ERASE_INDEXED, - COLOR_ERASE_INTEN, -} CombinationMode; - -/* Opacities */ -#define TRANSPARENT_OPACITY 0 -#define OPAQUE_OPACITY 255 void initial_region (PixelRegion *, PixelRegion *, PixelRegion *, guchar *, diff --git a/app/path.c b/app/path.c index 7974704963..b0cd4a77a1 100644 --- a/app/path.c +++ b/app/path.c @@ -26,7 +26,7 @@ #include "libgimpmath/gimpmath.h" -#include "display/display-types.h" +#include "tools/tools-types.h" #include "core/gimpimage.h" diff --git a/app/pdb/guides_cmds.c b/app/pdb/guides_cmds.c index ce830bf885..fbf0af2b29 100644 --- a/app/pdb/guides_cmds.c +++ b/app/pdb/guides_cmds.c @@ -29,6 +29,7 @@ #include "procedural_db.h" #include "core/core-types.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage.h" #include "undo.h" diff --git a/app/pdb/image_cmds.c b/app/pdb/image_cmds.c index b3d6c3e59c..cc78da715e 100644 --- a/app/pdb/image_cmds.c +++ b/app/pdb/image_cmds.c @@ -37,6 +37,9 @@ #include "core/gimpdrawable.h" #include "core/gimpimage-crop.h" #include "core/gimpimage-duplicate.h" +#include "core/gimpimage-merge.h" +#include "core/gimpimage-resize.h" +#include "core/gimpimage-scale.h" #include "core/gimpimage.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" @@ -49,13 +52,15 @@ static ProcRecord image_list_proc; static ProcRecord image_new_proc; +static ProcRecord image_delete_proc; +static ProcRecord image_base_type_proc; static ProcRecord image_resize_proc; static ProcRecord image_scale_proc; static ProcRecord image_crop_proc; -static ProcRecord image_delete_proc; static ProcRecord image_free_shadow_proc; static ProcRecord image_get_layers_proc; static ProcRecord image_get_channels_proc; +static ProcRecord image_active_drawable_proc; static ProcRecord image_unset_active_channel_proc; static ProcRecord image_pick_correlate_layer_proc; static ProcRecord image_raise_layer_proc; @@ -73,8 +78,6 @@ static ProcRecord image_raise_channel_proc; static ProcRecord image_lower_channel_proc; static ProcRecord image_add_channel_proc; static ProcRecord image_remove_channel_proc; -static ProcRecord image_active_drawable_proc; -static ProcRecord image_base_type_proc; static ProcRecord image_get_cmap_proc; static ProcRecord image_set_cmap_proc; static ProcRecord image_undo_is_enabled_proc; @@ -114,13 +117,15 @@ register_image_procs (Gimp *gimp) { procedural_db_register (gimp, &image_list_proc); procedural_db_register (gimp, &image_new_proc); + procedural_db_register (gimp, &image_delete_proc); + procedural_db_register (gimp, &image_base_type_proc); procedural_db_register (gimp, &image_resize_proc); procedural_db_register (gimp, &image_scale_proc); procedural_db_register (gimp, &image_crop_proc); - procedural_db_register (gimp, &image_delete_proc); procedural_db_register (gimp, &image_free_shadow_proc); procedural_db_register (gimp, &image_get_layers_proc); procedural_db_register (gimp, &image_get_channels_proc); + procedural_db_register (gimp, &image_active_drawable_proc); procedural_db_register (gimp, &image_unset_active_channel_proc); procedural_db_register (gimp, &image_pick_correlate_layer_proc); procedural_db_register (gimp, &image_raise_layer_proc); @@ -138,8 +143,6 @@ register_image_procs (Gimp *gimp) procedural_db_register (gimp, &image_lower_channel_proc); procedural_db_register (gimp, &image_add_channel_proc); procedural_db_register (gimp, &image_remove_channel_proc); - procedural_db_register (gimp, &image_active_drawable_proc); - procedural_db_register (gimp, &image_base_type_proc); procedural_db_register (gimp, &image_get_cmap_proc); procedural_db_register (gimp, &image_set_cmap_proc); procedural_db_register (gimp, &image_undo_is_enabled_proc); @@ -321,6 +324,112 @@ static ProcRecord image_new_proc = { { image_new_invoker } } }; +static Argument * +image_delete_invoker (Gimp *gimp, + Argument *args) +{ + gboolean success = TRUE; + GimpImage *gimage; + + gimage = gimp_image_get_by_ID (gimp, args[0].value.pdb_int); + if (gimage == NULL) + success = FALSE; + + if (success) + { + if (gimage->disp_count == 0) + { + g_object_unref (G_OBJECT (gimage)); + success = TRUE; + } + } + + return procedural_db_return_args (&image_delete_proc, success); +} + +static ProcArg image_delete_inargs[] = +{ + { + GIMP_PDB_IMAGE, + "image", + "The image" + } +}; + +static ProcRecord image_delete_proc = +{ + "gimp_image_delete", + "Delete the specified image.", + "If there are no displays associated with this image it will be deleted. This means that you can not delete an image through the PDB that was created by the user. If the associated display was however created through the PDB and you know the display ID, you may delete the display. Removal of the last associated display will then delete the image.", + "Spencer Kimball & Peter Mattis", + "Spencer Kimball & Peter Mattis", + "1995-1996", + GIMP_INTERNAL, + 1, + image_delete_inargs, + 0, + NULL, + { { image_delete_invoker } } +}; + +static Argument * +image_base_type_invoker (Gimp *gimp, + Argument *args) +{ + gboolean success = TRUE; + Argument *return_args; + GimpImage *gimage; + gint32 base_type = 0; + + gimage = gimp_image_get_by_ID (gimp, args[0].value.pdb_int); + if (gimage == NULL) + success = FALSE; + + if (success) + base_type = gimp_image_base_type (gimage); + + return_args = procedural_db_return_args (&image_base_type_proc, success); + + if (success) + return_args[1].value.pdb_int = base_type; + + return return_args; +} + +static ProcArg image_base_type_inargs[] = +{ + { + GIMP_PDB_IMAGE, + "image", + "The image" + } +}; + +static ProcArg image_base_type_outargs[] = +{ + { + GIMP_PDB_INT32, + "base_type", + "The image's base type: { RGB (0), GRAY (1), INDEXED (2) }" + } +}; + +static ProcRecord image_base_type_proc = +{ + "gimp_image_base_type", + "Get the base type of the image.", + "This procedure returns the image's base type. Layers in the image must be of this subtype, but can have an optional alpha channel.", + "Spencer Kimball & Peter Mattis", + "Spencer Kimball & Peter Mattis", + "1995-1996", + GIMP_INTERNAL, + 1, + image_base_type_inargs, + 1, + image_base_type_outargs, + { { image_base_type_invoker } } +}; + static Argument * image_resize_invoker (Gimp *gimp, Argument *args) @@ -555,54 +664,6 @@ static ProcRecord image_crop_proc = { { image_crop_invoker } } }; -static Argument * -image_delete_invoker (Gimp *gimp, - Argument *args) -{ - gboolean success = TRUE; - GimpImage *gimage; - - gimage = gimp_image_get_by_ID (gimp, args[0].value.pdb_int); - if (gimage == NULL) - success = FALSE; - - if (success) - { - if (gimage->disp_count == 0) - { - g_object_unref (G_OBJECT (gimage)); - success = TRUE; - } - } - - return procedural_db_return_args (&image_delete_proc, success); -} - -static ProcArg image_delete_inargs[] = -{ - { - GIMP_PDB_IMAGE, - "image", - "The image" - } -}; - -static ProcRecord image_delete_proc = -{ - "gimp_image_delete", - "Delete the specified image.", - "If there are no displays associated with this image it will be deleted. This means that you can not delete an image through the PDB that was created by the user. If the associated display was however created through the PDB and you know the display ID, you may delete the display. Removal of the last associated display will then delete the image.", - "Spencer Kimball & Peter Mattis", - "Spencer Kimball & Peter Mattis", - "1995-1996", - GIMP_INTERNAL, - 1, - image_delete_inargs, - 0, - NULL, - { { image_delete_invoker } } -}; - static Argument * image_free_shadow_invoker (Gimp *gimp, Argument *args) @@ -803,6 +864,64 @@ static ProcRecord image_get_channels_proc = { { image_get_channels_invoker } } }; +static Argument * +image_active_drawable_invoker (Gimp *gimp, + Argument *args) +{ + gboolean success = TRUE; + Argument *return_args; + GimpImage *gimage; + GimpDrawable *drawable = NULL; + + gimage = gimp_image_get_by_ID (gimp, args[0].value.pdb_int); + if (gimage == NULL) + success = FALSE; + + if (success) + success = (drawable = gimp_image_active_drawable (gimage)) != NULL; + + return_args = procedural_db_return_args (&image_active_drawable_proc, success); + + if (success) + return_args[1].value.pdb_int = gimp_drawable_get_ID (GIMP_DRAWABLE (drawable)); + + return return_args; +} + +static ProcArg image_active_drawable_inargs[] = +{ + { + GIMP_PDB_IMAGE, + "image", + "The image" + } +}; + +static ProcArg image_active_drawable_outargs[] = +{ + { + GIMP_PDB_DRAWABLE, + "drawable", + "The active drawable" + } +}; + +static ProcRecord image_active_drawable_proc = +{ + "gimp_image_active_drawable", + "Get the image's active drawable", + "This procedure returns the ID of the image's active drawable. This can be either a layer, a channel, or a layer mask. The active drawable is specified by the active image channel. If that is -1, then by the active image layer. If the active image layer has a layer mask and the layer mask is in edit mode, then the layer mask is the active drawable.", + "Spencer Kimball & Peter Mattis", + "Spencer Kimball & Peter Mattis", + "1995-1996", + GIMP_INTERNAL, + 1, + image_active_drawable_inargs, + 1, + image_active_drawable_outargs, + { { image_active_drawable_invoker } } +}; + static Argument * image_unset_active_channel_invoker (Gimp *gimp, Argument *args) @@ -1796,122 +1915,6 @@ static ProcRecord image_remove_channel_proc = { { image_remove_channel_invoker } } }; -static Argument * -image_active_drawable_invoker (Gimp *gimp, - Argument *args) -{ - gboolean success = TRUE; - Argument *return_args; - GimpImage *gimage; - GimpDrawable *drawable = NULL; - - gimage = gimp_image_get_by_ID (gimp, args[0].value.pdb_int); - if (gimage == NULL) - success = FALSE; - - if (success) - success = (drawable = gimp_image_active_drawable (gimage)) != NULL; - - return_args = procedural_db_return_args (&image_active_drawable_proc, success); - - if (success) - return_args[1].value.pdb_int = gimp_drawable_get_ID (GIMP_DRAWABLE (drawable)); - - return return_args; -} - -static ProcArg image_active_drawable_inargs[] = -{ - { - GIMP_PDB_IMAGE, - "image", - "The image" - } -}; - -static ProcArg image_active_drawable_outargs[] = -{ - { - GIMP_PDB_DRAWABLE, - "drawable", - "The active drawable" - } -}; - -static ProcRecord image_active_drawable_proc = -{ - "gimp_image_active_drawable", - "Get the image's active drawable", - "This procedure returns the ID of the image's active drawable. This can be either a layer, a channel, or a layer mask. The active drawable is specified by the active image channel. If that is -1, then by the active image layer. If the active image layer has a layer mask and the layer mask is in edit mode, then the layer mask is the active drawable.", - "Spencer Kimball & Peter Mattis", - "Spencer Kimball & Peter Mattis", - "1995-1996", - GIMP_INTERNAL, - 1, - image_active_drawable_inargs, - 1, - image_active_drawable_outargs, - { { image_active_drawable_invoker } } -}; - -static Argument * -image_base_type_invoker (Gimp *gimp, - Argument *args) -{ - gboolean success = TRUE; - Argument *return_args; - GimpImage *gimage; - gint32 base_type = 0; - - gimage = gimp_image_get_by_ID (gimp, args[0].value.pdb_int); - if (gimage == NULL) - success = FALSE; - - if (success) - base_type = gimp_image_base_type (gimage); - - return_args = procedural_db_return_args (&image_base_type_proc, success); - - if (success) - return_args[1].value.pdb_int = base_type; - - return return_args; -} - -static ProcArg image_base_type_inargs[] = -{ - { - GIMP_PDB_IMAGE, - "image", - "The image" - } -}; - -static ProcArg image_base_type_outargs[] = -{ - { - GIMP_PDB_INT32, - "base_type", - "The image's base type: { RGB (0), GRAY (1), INDEXED (2) }" - } -}; - -static ProcRecord image_base_type_proc = -{ - "gimp_image_base_type", - "Get the base type of the image.", - "This procedure returns the image's base type. Layers in the image must be of this subtype, but can have an optional alpha channel.", - "Spencer Kimball & Peter Mattis", - "Spencer Kimball & Peter Mattis", - "1995-1996", - GIMP_INTERNAL, - 1, - image_base_type_inargs, - 1, - image_base_type_outargs, - { { image_base_type_invoker } } -}; - static Argument * image_get_cmap_invoker (Gimp *gimp, Argument *args) @@ -1930,7 +1933,7 @@ image_get_cmap_invoker (Gimp *gimp, { num_bytes = gimage->num_cols * 3; cmap = g_new (guint8, num_bytes); - memcpy (cmap, gimp_image_cmap (gimage), num_bytes); + memcpy (cmap, gimp_image_get_colormap (gimage), num_bytes); } return_args = procedural_db_return_args (&image_get_cmap_proc, success); @@ -2012,8 +2015,7 @@ image_set_cmap_invoker (Gimp *gimp, gimage->num_cols = num_bytes / 3; - /* A colormap alteration affects the whole image */ - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + gimp_image_colormap_changed (gimage, -1); } return procedural_db_return_args (&image_set_cmap_proc, success); @@ -3499,7 +3501,7 @@ image_get_filename_invoker (Gimp *gimp, return_args = procedural_db_return_args (&image_get_filename_proc, success); if (success) - return_args[1].value.pdb_pointer = g_strdup (gimp_image_filename (gimage)); + return_args[1].value.pdb_pointer = g_strdup (gimp_image_get_filename (gimage)); return return_args; } diff --git a/app/plug-in/gimpplugin-message.c b/app/plug-in/gimpplugin-message.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimpplugin-message.c +++ b/app/plug-in/gimpplugin-message.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/gimpplugin-progress.c b/app/plug-in/gimpplugin-progress.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimpplugin-progress.c +++ b/app/plug-in/gimpplugin-progress.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/gimpplugin.c b/app/plug-in/gimpplugin.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimpplugin.c +++ b/app/plug-in/gimpplugin.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/gimppluginmanager-call.c b/app/plug-in/gimppluginmanager-call.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimppluginmanager-call.c +++ b/app/plug-in/gimppluginmanager-call.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/gimppluginmanager-run.c b/app/plug-in/gimppluginmanager-run.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimppluginmanager-run.c +++ b/app/plug-in/gimppluginmanager-run.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/gimppluginmanager.c b/app/plug-in/gimppluginmanager.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimppluginmanager.c +++ b/app/plug-in/gimppluginmanager.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/gimppluginshm.c b/app/plug-in/gimppluginshm.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/gimppluginshm.c +++ b/app/plug-in/gimppluginshm.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in-def.c b/app/plug-in/plug-in-def.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in-def.c +++ b/app/plug-in/plug-in-def.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in-message.c b/app/plug-in/plug-in-message.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in-message.c +++ b/app/plug-in/plug-in-message.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in-params.c b/app/plug-in/plug-in-params.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in-params.c +++ b/app/plug-in/plug-in-params.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in-progress.c b/app/plug-in/plug-in-progress.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in-progress.c +++ b/app/plug-in/plug-in-progress.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in-run.c b/app/plug-in/plug-in-run.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in-run.c +++ b/app/plug-in/plug-in-run.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in-shm.c b/app/plug-in/plug-in-shm.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in-shm.c +++ b/app/plug-in/plug-in-shm.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-in.c b/app/plug-in/plug-in.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-in.c +++ b/app/plug-in/plug-in.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug-in/plug-ins.c b/app/plug-in/plug-ins.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug-in/plug-ins.c +++ b/app/plug-in/plug-ins.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/plug_in.c b/app/plug_in.c index b5a352ecaa..e85060d12b 100644 --- a/app/plug_in.c +++ b/app/plug_in.c @@ -1485,6 +1485,23 @@ plug_in_set_menu_sensitivity (GimpImageType type) if (last_plug_in && (last_plug_in == &(proc_def->db_info))) { + gchar *basename; + gchar *repeat; + gchar *reshow; + + basename = g_path_get_basename (proc_def->menu_path); + + repeat = g_strdup_printf (_("Repeat \"%s\""), basename); + reshow = g_strdup_printf (_("Re-show \"%s\""), basename); + + g_free (basename); + + gimp_menu_item_set_label ("/Filters/Repeat Last", repeat); + gimp_menu_item_set_label ("/Filters/Re-Show Last", reshow); + + g_free (repeat); + g_free (reshow); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", sensitive); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", @@ -1493,8 +1510,13 @@ plug_in_set_menu_sensitivity (GimpImageType type) } } - if (!last_plug_in) + if (! last_plug_in) { + gimp_menu_item_set_label ("/Filters/Repeat Last", + _("Repeat Last")); + gimp_menu_item_set_label ("/Filters/Re-Show Last", + _("Re-Show Last")); + gimp_menu_item_set_sensitive ("/Filters/Repeat Last", FALSE); gimp_menu_item_set_sensitive ("/Filters/Re-Show Last", FALSE); } diff --git a/app/tools/gimpbycolorselecttool.c b/app/tools/gimpbycolorselecttool.c index 957e8df676..4405a142b8 100644 --- a/app/tools/gimpbycolorselecttool.c +++ b/app/tools/gimpbycolorselecttool.c @@ -731,7 +731,7 @@ by_color_select_draw (ByColorDialog *bcd, gtk_widget_draw (bcd->preview, NULL); /* Update the gimage label to reflect the displayed gimage name */ - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); gtk_label_set_text (GTK_LABEL (bcd->gimage_name), basename); diff --git a/app/tools/gimpeditselectiontool.c b/app/tools/gimpeditselectiontool.c index 0927fefc7e..0a9ebf6974 100644 --- a/app/tools/gimpeditselectiontool.c +++ b/app/tools/gimpeditselectiontool.c @@ -33,6 +33,7 @@ #include "core/gimpdrawable.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" #include "core/gimplayer.h" #include "core/gimplist.h" diff --git a/app/tools/gimpmeasuretool.c b/app/tools/gimpmeasuretool.c index e796174fa8..88442e3f0c 100644 --- a/app/tools/gimpmeasuretool.c +++ b/app/tools/gimpmeasuretool.c @@ -33,6 +33,7 @@ #include "gui/gui-types.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimptoolinfo.h" #include "display/gimpdisplay.h" diff --git a/app/tools/gimpmovetool.c b/app/tools/gimpmovetool.c index 53645e30a5..53cb8e4b79 100644 --- a/app/tools/gimpmovetool.c +++ b/app/tools/gimpmovetool.c @@ -27,6 +27,7 @@ #include "tools-types.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" #include "core/gimplayer.h" #include "core/gimptoolinfo.h" diff --git a/app/tools/tools-types.h b/app/tools/tools-types.h index 587a1b85fd..10d3806159 100644 --- a/app/tools/tools-types.h +++ b/app/tools/tools-types.h @@ -20,9 +20,6 @@ #define __TOOLS_TYPES_H__ -#include "core/core-types.h" - -#include "widgets/widgets-types.h" #include "display/display-types.h" diff --git a/app/undo.c b/app/undo.c index f0184430e9..150b7c1d84 100644 --- a/app/undo.c +++ b/app/undo.c @@ -39,6 +39,7 @@ #include "core/gimpcontext.h" #include "core/gimpcoreconfig.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimpimage-mask.h" #include "core/gimpimage-projection.h" #include "core/gimplayer.h" diff --git a/app/undo_history.c b/app/undo_history.c index caaae1c71d..1f4f188f81 100644 --- a/app/undo_history.c +++ b/app/undo_history.c @@ -455,7 +455,7 @@ undo_history_gimage_rename_callback (GimpImage *gimage, gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); title = g_strdup_printf (_("Undo History: %s"), basename); @@ -806,7 +806,7 @@ undo_history_new (GimpImage *gimage) gchar *basename; gchar *title; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); title = g_strdup_printf (_("Undo History: %s"), basename); diff --git a/app/widgets/gimpbrushfactoryview.c b/app/widgets/gimpbrushfactoryview.c index fdca0ed2e1..50488646b7 100644 --- a/app/widgets/gimpbrushfactoryview.c +++ b/app/widgets/gimpbrushfactoryview.c @@ -137,9 +137,8 @@ gimp_brush_factory_view_destroy (GtkObject *object) if (view->spacing_changed_handler_id) { - gimp_container_remove_handler - (GIMP_CONTAINER_EDITOR (view)->view->container, - view->spacing_changed_handler_id); + gimp_container_remove_handler (GIMP_CONTAINER_EDITOR (view)->view->container, + view->spacing_changed_handler_id); view->spacing_changed_handler_id = 0; } @@ -187,10 +186,10 @@ gimp_brush_factory_view_new (GimpViewType view_type, editor = GIMP_CONTAINER_EDITOR (factory_view); - gimp_container_add_handler - (editor->view->container, "spacing_changed", - G_CALLBACK (gimp_brush_factory_view_spacing_changed), - factory_view); + factory_view->spacing_changed_handler_id = + gimp_container_add_handler (editor->view->container, "spacing_changed", + G_CALLBACK (gimp_brush_factory_view_spacing_changed), + factory_view); return GTK_WIDGET (factory_view); } diff --git a/app/widgets/gimpcontainerview-utils.c b/app/widgets/gimpcontainerview-utils.c index 5ccb113e7e..973ed199db 100644 --- a/app/widgets/gimpcontainerview-utils.c +++ b/app/widgets/gimpcontainerview-utils.c @@ -214,7 +214,7 @@ gimp_container_view_image_name_func (GtkWidget *widget, gchar *basename; gchar *retval; - basename = g_path_get_basename (gimp_image_filename (gimage)); + basename = g_path_get_basename (gimp_image_get_filename (gimage)); retval = g_strdup_printf ("%s-%d", basename, @@ -223,7 +223,7 @@ gimp_container_view_image_name_func (GtkWidget *widget, g_free (basename); if (tooltip) - *tooltip = g_strdup (gimp_image_filename (gimage)); + *tooltip = g_strdup (gimp_image_get_filename (gimage)); return retval; } diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h index a9ca5fb475..9cf74370df 100644 --- a/app/widgets/widgets-types.h +++ b/app/widgets/widgets-types.h @@ -22,6 +22,8 @@ #include "libgimpwidgets/gimpwidgetstypes.h" +#include "core/core-types.h" + #include "display/display-types.h" diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c index ed625c2556..3d4d8c6a20 100644 --- a/app/xcf/xcf-load.c +++ b/app/xcf/xcf-load.c @@ -38,6 +38,7 @@ #include "core/gimpcoreconfig.h" #include "core/gimpdrawable.h" #include "core/gimpimage.h" +#include "core/gimpimage-guides.h" #include "core/gimplayer.h" #include "core/gimplayermask.h" #include "core/gimpparasitelist.h" diff --git a/libgimp/gimpimage_pdb.c b/libgimp/gimpimage_pdb.c index 2456007f85..23788857e2 100644 --- a/libgimp/gimpimage_pdb.c +++ b/libgimp/gimpimage_pdb.c @@ -103,6 +103,71 @@ gimp_image_new (gint width, return image_ID; } +/** + * gimp_image_delete: + * @image_ID: The image. + * + * Delete the specified image. + * + * If there are no displays associated with this image it will be + * deleted. This means that you can not delete an image through the PDB + * that was created by the user. If the associated display was however + * created through the PDB and you know the display ID, you may delete + * the display. Removal of the last associated display will then delete + * the image. + * + * Returns: TRUE on success. + */ +gboolean +gimp_image_delete (gint32 image_ID) +{ + GimpParam *return_vals; + gint nreturn_vals; + gboolean success = TRUE; + + return_vals = gimp_run_procedure ("gimp_image_delete", + &nreturn_vals, + GIMP_PDB_IMAGE, image_ID, + GIMP_PDB_END); + + success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS; + + gimp_destroy_params (return_vals, nreturn_vals); + + return success; +} + +/** + * gimp_image_base_type: + * @image_ID: The image. + * + * Get the base type of the image. + * + * This procedure returns the image's base type. Layers in the image + * must be of this subtype, but can have an optional alpha channel. + * + * Returns: The image's base type. + */ +GimpImageBaseType +gimp_image_base_type (gint32 image_ID) +{ + GimpParam *return_vals; + gint nreturn_vals; + GimpImageBaseType base_type = 0; + + return_vals = gimp_run_procedure ("gimp_image_base_type", + &nreturn_vals, + GIMP_PDB_IMAGE, image_ID, + GIMP_PDB_END); + + if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) + base_type = return_vals[1].data.d_int32; + + gimp_destroy_params (return_vals, nreturn_vals); + + return base_type; +} + /** * gimp_image_resize: * @image_ID: The image. @@ -239,40 +304,6 @@ gimp_image_crop (gint32 image_ID, return success; } -/** - * gimp_image_delete: - * @image_ID: The image. - * - * Delete the specified image. - * - * If there are no displays associated with this image it will be - * deleted. This means that you can not delete an image through the PDB - * that was created by the user. If the associated display was however - * created through the PDB and you know the display ID, you may delete - * the display. Removal of the last associated display will then delete - * the image. - * - * Returns: TRUE on success. - */ -gboolean -gimp_image_delete (gint32 image_ID) -{ - GimpParam *return_vals; - gint nreturn_vals; - gboolean success = TRUE; - - return_vals = gimp_run_procedure ("gimp_image_delete", - &nreturn_vals, - GIMP_PDB_IMAGE, image_ID, - GIMP_PDB_END); - - success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS; - - gimp_destroy_params (return_vals, nreturn_vals); - - return success; -} - /** * gimp_image_free_shadow: * @image_ID: The image. @@ -385,6 +416,41 @@ gimp_image_get_channels (gint32 image_ID, return channel_ids; } +/** + * gimp_image_active_drawable: + * @image_ID: The image. + * + * Get the image's active drawable + * + * This procedure returns the ID of the image's active drawable. This + * can be either a layer, a channel, or a layer mask. The active + * drawable is specified by the active image channel. If that is -1, + * then by the active image layer. If the active image layer has a + * layer mask and the layer mask is in edit mode, then the layer mask + * is the active drawable. + * + * Returns: The active drawable. + */ +gint32 +gimp_image_active_drawable (gint32 image_ID) +{ + GimpParam *return_vals; + gint nreturn_vals; + gint32 drawable_ID = -1; + + return_vals = gimp_run_procedure ("gimp_image_active_drawable", + &nreturn_vals, + GIMP_PDB_IMAGE, image_ID, + GIMP_PDB_END); + + if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) + drawable_ID = return_vals[1].data.d_drawable; + + gimp_destroy_params (return_vals, nreturn_vals); + + return drawable_ID; +} + /** * gimp_image_unset_active_channel: * @image_ID: The image. @@ -996,72 +1062,6 @@ gimp_image_remove_channel (gint32 image_ID, return success; } -/** - * gimp_image_active_drawable: - * @image_ID: The image. - * - * Get the image's active drawable - * - * This procedure returns the ID of the image's active drawable. This - * can be either a layer, a channel, or a layer mask. The active - * drawable is specified by the active image channel. If that is -1, - * then by the active image layer. If the active image layer has a - * layer mask and the layer mask is in edit mode, then the layer mask - * is the active drawable. - * - * Returns: The active drawable. - */ -gint32 -gimp_image_active_drawable (gint32 image_ID) -{ - GimpParam *return_vals; - gint nreturn_vals; - gint32 drawable_ID = -1; - - return_vals = gimp_run_procedure ("gimp_image_active_drawable", - &nreturn_vals, - GIMP_PDB_IMAGE, image_ID, - GIMP_PDB_END); - - if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) - drawable_ID = return_vals[1].data.d_drawable; - - gimp_destroy_params (return_vals, nreturn_vals); - - return drawable_ID; -} - -/** - * gimp_image_base_type: - * @image_ID: The image. - * - * Get the base type of the image. - * - * This procedure returns the image's base type. Layers in the image - * must be of this subtype, but can have an optional alpha channel. - * - * Returns: The image's base type. - */ -GimpImageBaseType -gimp_image_base_type (gint32 image_ID) -{ - GimpParam *return_vals; - gint nreturn_vals; - GimpImageBaseType base_type = 0; - - return_vals = gimp_run_procedure ("gimp_image_base_type", - &nreturn_vals, - GIMP_PDB_IMAGE, image_ID, - GIMP_PDB_END); - - if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) - base_type = return_vals[1].data.d_int32; - - gimp_destroy_params (return_vals, nreturn_vals); - - return base_type; -} - /** * _gimp_image_get_cmap: * @image_ID: The image. diff --git a/libgimp/gimpimage_pdb.h b/libgimp/gimpimage_pdb.h index 4767923d8e..095810773e 100644 --- a/libgimp/gimpimage_pdb.h +++ b/libgimp/gimpimage_pdb.h @@ -33,6 +33,8 @@ gint* gimp_image_list (gint *num_i gint32 gimp_image_new (gint width, gint height, GimpImageBaseType type); +gboolean gimp_image_delete (gint32 image_ID); +GimpImageBaseType gimp_image_base_type (gint32 image_ID); gboolean gimp_image_resize (gint32 image_ID, gint new_width, gint new_height, @@ -46,12 +48,12 @@ gboolean gimp_image_crop (gint32 image gint new_height, gint offx, gint offy); -gboolean gimp_image_delete (gint32 image_ID); gboolean gimp_image_free_shadow (gint32 image_ID); gint* gimp_image_get_layers (gint32 image_ID, gint *num_layers); gint* gimp_image_get_channels (gint32 image_ID, gint *num_channels); +gint32 gimp_image_active_drawable (gint32 image_ID); gboolean gimp_image_unset_active_channel (gint32 image_ID); gint32 gimp_image_pick_correlate_layer (gint32 image_ID, gint x, @@ -90,8 +92,6 @@ gboolean gimp_image_add_channel (gint32 image gint position); gboolean gimp_image_remove_channel (gint32 image_ID, gint32 channel_ID); -gint32 gimp_image_active_drawable (gint32 image_ID); -GimpImageBaseType gimp_image_base_type (gint32 image_ID); guint8* _gimp_image_get_cmap (gint32 image_ID, gint *num_bytes); gboolean _gimp_image_set_cmap (gint32 image_ID, diff --git a/tools/pdbgen/pdb/guides.pdb b/tools/pdbgen/pdb/guides.pdb index bc82f20719..8bc73b44e9 100644 --- a/tools/pdbgen/pdb/guides.pdb +++ b/tools/pdbgen/pdb/guides.pdb @@ -292,6 +292,8 @@ CODE ); } +@headers = qw("core/gimpimage-guides.h"); + @procs = qw(image_add_hguide image_add_vguide image_delete_guide image_find_next_guide image_get_guide_orientation image_get_guide_position); diff --git a/tools/pdbgen/pdb/image.pdb b/tools/pdbgen/pdb/image.pdb index 0c853fd3d8..70d1815cfa 100644 --- a/tools/pdbgen/pdb/image.pdb +++ b/tools/pdbgen/pdb/image.pdb @@ -292,6 +292,7 @@ HELP } %invoke = ( + headers => [ qw("core/gimpimage-resize.h") ], code => <<'CODE' { gimp_image_resize (gimage, new_width, new_height, offx, offy); @@ -319,6 +320,7 @@ HELP &new_dim_args; %invoke = ( + headers => [ qw("core/gimpimage-scale.h") ], code => <<'CODE' { gimp_image_scale (gimage, new_width, new_height, NULL, NULL); @@ -519,6 +521,7 @@ HELP ); %invoke = ( + headers => [ qw("core/gimpimage-merge.h") ], code => <<'CODE' { layer = gimp_image_merge_visible_layers (gimage, merge_type); @@ -557,6 +560,7 @@ HELP ); %invoke = ( + headers => [ qw("core/gimpimage-merge.h") ], code => <<'CODE' { layer = gimp_image_merge_down (gimage, merge_layer, merge_type); @@ -587,6 +591,7 @@ HELP ); %invoke = ( + headers => [ qw("core/gimpimage-merge.h") ], code => 'success = (layer = gimp_image_flatten (gimage)) != NULL;' ); } @@ -825,7 +830,7 @@ HELP { num_bytes = gimage->num_cols * 3; cmap = g_new (guint8, num_bytes); - memcpy (cmap, gimp_image_cmap (gimage), num_bytes); + memcpy (cmap, gimp_image_get_colormap (gimage), num_bytes); } CODE ); @@ -862,8 +867,7 @@ HELP gimage->num_cols = num_bytes / 3; - /* A colormap alteration affects the whole image */ - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + gimp_image_colormap_changed (gimage, -1); } CODE ); @@ -1214,7 +1218,6 @@ CODE2 -- if it was loaded or has since been saved. Otherwise, returns NULL. HELP - $outargs[0]->{alias} =~ s/get_//; CODE &image_accessors('resolution', 'float', 'resolution', 0, @@ -1515,18 +1518,22 @@ gimlist_cb (gpointer im, } CODE -unshift @procs, qw(image_list image_new image_resize image_scale image_crop - image_delete - image_free_shadow image_get_layers image_get_channels - image_unset_active_channel image_pick_correlate_layer +unshift @procs, qw(image_list image_new image_delete image_base_type + image_resize image_scale image_crop + image_free_shadow + image_get_layers image_get_channels + image_active_drawable image_unset_active_channel + image_pick_correlate_layer image_raise_layer image_lower_layer image_raise_layer_to_top - image_lower_layer_to_bottom image_merge_visible_layers - image_merge_down image_flatten image_add_layer - image_remove_layer image_add_layer_mask - image_remove_layer_mask image_raise_channel - image_lower_channel image_add_channel image_remove_channel - image_active_drawable image_base_type image_get_cmap - image_set_cmap image_undo_is_enabled image_undo_enable + image_lower_layer_to_bottom + image_merge_visible_layers image_merge_down + image_flatten + image_add_layer image_remove_layer + image_add_layer_mask image_remove_layer_mask + image_raise_channel image_lower_channel + image_add_channel image_remove_channel + image_get_cmap image_set_cmap + image_undo_is_enabled image_undo_enable image_undo_disable image_undo_freeze image_undo_thaw image_clean_all image_floating_selection image_floating_sel_attached_to image_thumbnail