home *** CD-ROM | disk | FTP | other *** search
- /* LIBGIMP - The GIMP Library
- * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
- *
- * gimpexport.c
- * Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
- #include "config.h"
-
- #include <gtk/gtk.h>
-
- #include "gimp.h"
- #include "gimpui.h"
-
- #include "libgimp-intl.h"
-
-
- typedef void (* ExportFunc) (gint32 imageID,
- gint32 *drawable_ID);
-
-
- /* the export action structure */
- typedef struct
- {
- ExportFunc default_action;
- ExportFunc alt_action;
- gchar *reason;
- gchar *possibilities[2];
- gint choice;
- } ExportAction;
-
-
- /* the functions that do the actual export */
-
- static void
- export_merge (gint32 image_ID,
- gint32 *drawable_ID)
- {
- gint32 nlayers;
- gint32 nvisible = 0;
- gint32 i;
- gint32 *layers;
- gint32 visible = *drawable_ID;
- gint32 merged;
-
- layers = gimp_image_get_layers (image_ID, &nlayers);
- for (i = 0; i < nlayers; i++)
- {
- if (gimp_drawable_visible (layers[i]))
- {
- nvisible++;
- visible = layers[i];
- }
- }
-
- if (nvisible == 1 && *drawable_ID != visible)
- *drawable_ID = visible;
-
- if (nvisible > 1)
- {
- g_free (layers);
- merged = gimp_image_merge_visible_layers (image_ID, GIMP_CLIP_TO_IMAGE);
-
- if (merged != -1)
- *drawable_ID = merged;
- else
- return; /* shouldn't happen */
-
- layers = gimp_image_get_layers (image_ID, &nlayers);
- }
-
- /* remove any remaining (invisible) layers */
- for (i = 0; i < nlayers; i++)
- {
- if (layers[i] != *drawable_ID)
- gimp_image_remove_layer (image_ID, layers[i]);
- }
- g_free (layers);
- }
-
- static void
- export_flatten (gint32 image_ID,
- gint32 *drawable_ID)
- {
- gint32 flattened;
-
- flattened = gimp_image_flatten (image_ID);
-
- if (flattened != -1)
- *drawable_ID = flattened;
- }
-
- static void
- export_convert_rgb (gint32 image_ID,
- gint32 *drawable_ID)
- {
- gimp_image_convert_rgb (image_ID);
- }
-
- static void
- export_convert_grayscale (gint32 image_ID,
- gint32 *drawable_ID)
- {
- gimp_image_convert_grayscale (image_ID);
- }
-
- static void
- export_convert_indexed (gint32 image_ID,
- gint32 *drawable_ID)
- {
- gint32 nlayers;
-
- /* check alpha */
- g_free (gimp_image_get_layers (image_ID, &nlayers));
- if (nlayers > 1 || gimp_drawable_has_alpha (*drawable_ID))
- gimp_image_convert_indexed (image_ID, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 255, FALSE, FALSE, "");
- else
- gimp_image_convert_indexed (image_ID, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 256, FALSE, FALSE, "");
- }
-
- static void
- export_add_alpha (gint32 image_ID,
- gint32 *drawable_ID)
- {
- gint32 nlayers;
- gint32 i;
- gint32 *layers;
-
- layers = gimp_image_get_layers (image_ID, &nlayers);
- for (i = 0; i < nlayers; i++)
- {
- if (!gimp_drawable_has_alpha (layers[i]))
- gimp_layer_add_alpha (layers[i]);
- }
- g_free (layers);
- }
-
-
- /* a set of predefined actions */
-
- static ExportAction export_action_merge =
- {
- export_merge,
- NULL,
- N_("can't handle layers"),
- { N_("Merge Visible Layers"), NULL },
- 0
- };
-
- static ExportAction export_action_animate_or_merge =
- {
- export_merge,
- NULL,
- N_("can only handle layers as animation frames"),
- { N_("Merge Visible Layers"), N_("Save as Animation")},
- 0
- };
-
- static ExportAction export_action_animate_or_flatten =
- {
- export_flatten,
- NULL,
- N_("can only handle layers as animation frames"),
- { N_("Flatten Image"), N_("Save as Animation") },
- 0
- };
-
- static ExportAction export_action_merge_flat =
- {
- export_flatten,
- NULL,
- N_("can't handle layers"),
- { N_("Flatten Image"), NULL },
- 0
- };
-
- static ExportAction export_action_flatten =
- {
- export_flatten,
- NULL,
- N_("can't handle transparency"),
- { N_("Flatten Image"), NULL },
- 0
- };
-
- static ExportAction export_action_convert_rgb =
- {
- export_convert_rgb,
- NULL,
- N_("can only handle RGB images"),
- { N_("Convert to RGB"), NULL },
- 0
- };
-
- static ExportAction export_action_convert_grayscale =
- {
- export_convert_grayscale,
- NULL,
- N_("can only handle grayscale images"),
- { N_("Convert to Grayscale"), NULL },
- 0
- };
-
- static ExportAction export_action_convert_indexed =
- {
- export_convert_indexed,
- NULL,
- N_("can only handle indexed images"),
- { N_("Convert to Indexed using default settings\n"
- "(Do it manually to tune the result)"), NULL },
- 0
- };
-
- static ExportAction export_action_convert_rgb_or_grayscale =
- {
- export_convert_rgb,
- export_convert_grayscale,
- N_("can only handle RGB or grayscale images"),
- { N_("Convert to RGB"), N_("Convert to Grayscale")},
- 0
- };
-
- static ExportAction export_action_convert_rgb_or_indexed =
- {
- export_convert_rgb,
- export_convert_indexed,
- N_("can only handle RGB or indexed images"),
- { N_("Convert to RGB"), N_("Convert to Indexed using default settings\n"
- "(Do it manually to tune the result)")},
- 0
- };
-
- static ExportAction export_action_convert_indexed_or_grayscale =
- {
- export_convert_indexed,
- export_convert_grayscale,
- N_("can only handle grayscale or indexed images"),
- { N_("Convert to Indexed using default settings\n"
- "(Do it manually to tune the result)"),
- N_("Convert to Grayscale") },
- 0
- };
-
- static ExportAction export_action_add_alpha =
- {
- export_add_alpha,
- NULL,
- N_("needs an alpha channel"),
- { N_("Add Alpha Channel"), NULL},
- 0
- };
-
-
- /* dialog functions */
-
- static GtkWidget *dialog = NULL;
- static GimpExportReturnType dialog_return = GIMP_EXPORT_CANCEL;
-
- static void
- export_export_callback (GtkWidget *widget,
- gpointer data)
- {
- gtk_widget_destroy (dialog);
- dialog_return = GIMP_EXPORT_EXPORT;
- }
-
- static void
- export_skip_callback (GtkWidget *widget,
- gpointer data)
- {
- gtk_widget_destroy (dialog);
- dialog_return = GIMP_EXPORT_IGNORE;
- }
-
- static void
- export_cancel_callback (GtkWidget *widget,
- gpointer data)
- {
- dialog_return = GIMP_EXPORT_CANCEL;
- dialog = NULL;
- gtk_main_quit ();
- }
-
- static void
- export_toggle_callback (GtkWidget *widget,
- gpointer data)
- {
- gint *choice = (gint*)data;
-
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
- *choice = 0;
- else
- *choice = 1;
- }
-
- static gint
- export_dialog (GSList *actions,
- const gchar *format)
- {
- GtkWidget *frame;
- GtkWidget *vbox;
- GtkWidget *hbox;
- GtkWidget *button;
- GtkWidget *label;
- GSList *list;
- gchar *text;
- ExportAction *action;
-
- dialog_return = GIMP_EXPORT_CANCEL;
- g_return_val_if_fail (actions != NULL && format != NULL, dialog_return);
-
- /*
- * Plug-ins have called gtk_init () before calling gimp_export ().
- * Otherwise bad things will happen now!!
- */
-
- /* the dialog */
- dialog = gimp_dialog_new (_("Export File"), "export_file",
- gimp_standard_help_func, "dialogs/export_file.html",
- GTK_WIN_POS_MOUSE,
- FALSE, FALSE, FALSE,
-
- _("Export"), export_export_callback,
- NULL, NULL, NULL, TRUE, FALSE,
- _("Ignore"), export_skip_callback,
- NULL, NULL, NULL, FALSE, FALSE,
- _("Cancel"), gtk_widget_destroy,
- NULL, 1, NULL, FALSE, TRUE,
-
- NULL);
-
- gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
- GTK_SIGNAL_FUNC (export_cancel_callback),
- NULL);
-
- /* the headline */
- vbox = gtk_vbox_new (FALSE, 6);
- gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
- gtk_widget_show (vbox);
-
- label = gtk_label_new (_("Your image should be exported before it "
- "can be saved for the following reasons:"));
- gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
- gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- for (list = actions; list; list = list->next)
- {
- action = (ExportAction *) (list->data);
-
- text = g_strdup_printf ("%s %s", format, gettext (action->reason));
- frame = gtk_frame_new (text);
- g_free (text);
- gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
-
- hbox = gtk_hbox_new (FALSE, 4);
- gtk_container_add (GTK_CONTAINER (frame), hbox);
- gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
-
- if (action->possibilities[0] && action->possibilities[1])
- {
- GSList *radio_group = NULL;
-
- button = gtk_radio_button_new_with_label (radio_group,
- gettext (action->possibilities[0]));
- gtk_label_set_justify (GTK_LABEL (GTK_BIN (button)->child), GTK_JUSTIFY_LEFT);
- radio_group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- gtk_signal_connect (GTK_OBJECT (button), "toggled",
- GTK_SIGNAL_FUNC (export_toggle_callback),
- &action->choice);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
- gtk_widget_show (button);
-
- button = gtk_radio_button_new_with_label (radio_group,
- gettext (action->possibilities[1]));
- gtk_label_set_justify (GTK_LABEL (GTK_BIN (button)->child), GTK_JUSTIFY_LEFT);
- radio_group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- gtk_widget_show (button);
- }
- else if (action->possibilities[0])
- {
- label = gtk_label_new (gettext (action->possibilities[0]));
- gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
- gtk_widget_show (label);
- action->choice = 0;
- }
- else if (action->possibilities[1])
- {
- label = gtk_label_new (gettext (action->possibilities[1]));
- gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
- gtk_widget_show (label);
- action->choice = 1;
- }
- gtk_widget_show (hbox);
- gtk_widget_show (frame);
- }
-
- /* the footline */
- label = gtk_label_new (_("The export conversion won't modify your original image."));
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- gtk_widget_show (dialog);
- gtk_main ();
-
- return dialog_return;
- }
-
- /**
- * gimp_export_image:
- * @image_ID: Pointer to the image_ID.
- * @drawable_ID: Pointer to the drawable_ID.
- * @format_name: The (short) name of the image_format (e.g. JPEG or GIF).
- * @capabilities: What can the image_format do?
- *
- * Takes an image and a drawable to be saved together with a
- * description of the capabilities of the image_format. If the
- * type of image doesn't match the capabilities of the format
- * a dialog is opened that informs the user that the image has
- * to be exported and offers to do the necessary conversions.
- *
- * If the user chooses to export the image, a copy is created.
- * This copy is then converted, the image_ID and drawable_ID
- * are changed to point to the new image and the procedure returns
- * GIMP_EXPORT_EXPORT. The save_plugin has to take care of deleting the
- * created image using gimp_image_delete() when it has saved it.
- *
- * If the user chooses to Ignore the export problem, the image_ID
- * and drawable_ID is not altered, GIMP_EXPORT_IGNORE is returned and
- * the save_plugin should try to save the original image. If the
- * user chooses Cancel, GIMP_EXPORT_CANCEL is returned and the
- * save_plugin should quit itself with status #STATUS_CANCEL.
- *
- * Returns: An enum of #GimpExportReturnType describing the user_action.
- **/
- GimpExportReturnType
- gimp_export_image (gint32 *image_ID,
- gint32 *drawable_ID,
- const gchar *format_name,
- GimpExportCapabilities capabilities)
- {
- GSList *actions = NULL;
- GSList *list;
- GimpImageBaseType type;
- gint32 i;
- gint32 nlayers;
- gint32* layers;
- gboolean added_flatten = FALSE;
- gboolean background_has_alpha = TRUE;
- ExportAction *action;
-
- g_return_val_if_fail (*image_ID > -1 && *drawable_ID > -1, FALSE);
-
- /* do some sanity checks */
- if (capabilities & GIMP_EXPORT_NEEDS_ALPHA)
- capabilities |= GIMP_EXPORT_CAN_HANDLE_ALPHA ;
- if (capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION)
- capabilities |= GIMP_EXPORT_CAN_HANDLE_LAYERS;
-
- /* check alpha */
- layers = gimp_image_get_layers (*image_ID, &nlayers);
- for (i = 0; i < nlayers; i++)
- {
- if (gimp_drawable_has_alpha (layers[i]))
- {
-
- if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_ALPHA ) )
- {
- actions = g_slist_prepend (actions, &export_action_flatten);
- added_flatten = TRUE;
- break;
- }
- }
- else
- {
- /* If this is the last layer, it's visible and has no alpha
- channel, then the image has a "flat" background */
- if (i == nlayers - 1 && gimp_layer_get_visible(layers[i]))
- background_has_alpha = FALSE;
-
- if (capabilities & GIMP_EXPORT_NEEDS_ALPHA)
- {
- actions = g_slist_prepend (actions, &export_action_add_alpha);
- break;
- }
- }
- }
- g_free (layers);
-
- /* check multiple layers */
- if (!added_flatten && nlayers > 1)
- {
- if (capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION)
- {
- if (background_has_alpha || capabilities & GIMP_EXPORT_NEEDS_ALPHA)
- actions = g_slist_prepend (actions, &export_action_animate_or_merge);
- else
- actions = g_slist_prepend (actions, &export_action_animate_or_flatten);
- }
- else if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS))
- {
- if (background_has_alpha || capabilities & GIMP_EXPORT_NEEDS_ALPHA)
- actions = g_slist_prepend (actions, &export_action_merge);
- else
- actions = g_slist_prepend (actions, &export_action_merge_flat);
- }
- }
-
- /* check the image type */
- type = gimp_image_base_type (*image_ID);
- switch (type)
- {
- case GIMP_RGB:
- if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_RGB) )
- {
- if ((capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED) && (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY))
- actions = g_slist_prepend (actions, &export_action_convert_indexed_or_grayscale);
- else if (capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED)
- actions = g_slist_prepend (actions, &export_action_convert_indexed);
- else if (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY)
- actions = g_slist_prepend (actions, &export_action_convert_grayscale);
- }
- break;
- case GIMP_GRAY:
- if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY) )
- {
- if ((capabilities & GIMP_EXPORT_CAN_HANDLE_RGB) && (capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED))
- actions = g_slist_prepend (actions, &export_action_convert_rgb_or_indexed);
- else if (capabilities & GIMP_EXPORT_CAN_HANDLE_RGB)
- actions = g_slist_prepend (actions, &export_action_convert_rgb);
- else if (capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED)
- actions = g_slist_prepend (actions, &export_action_convert_indexed);
- }
- break;
- case GIMP_INDEXED:
- if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED) )
- {
- if ((capabilities & GIMP_EXPORT_CAN_HANDLE_RGB) && (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY))
- actions = g_slist_prepend (actions, &export_action_convert_rgb_or_grayscale);
- else if (capabilities & GIMP_EXPORT_CAN_HANDLE_RGB)
- actions = g_slist_prepend (actions, &export_action_convert_rgb);
- else if (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY)
- actions = g_slist_prepend (actions, &export_action_convert_grayscale);
- }
- break;
- }
-
- if (actions)
- {
- actions = g_slist_reverse (actions);
- dialog_return = export_dialog (actions, format_name);
- }
- else
- dialog_return = GIMP_EXPORT_IGNORE;
-
- if (dialog_return == GIMP_EXPORT_EXPORT)
- {
- *image_ID = gimp_image_duplicate (*image_ID);
- *drawable_ID = gimp_image_get_active_layer (*image_ID);
- gimp_image_undo_disable (*image_ID);
- for (list = actions; list; list = list->next)
- {
- action = (ExportAction*)(list->data);
- if (action->choice == 0 && action->default_action)
- action->default_action (*image_ID, drawable_ID);
- else if (action->choice == 1 && action->alt_action)
- action->alt_action (*image_ID, drawable_ID);
- }
- }
- g_slist_free (actions);
-
- return dialog_return;
- }
-