mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-10-06 05:22:40 +02:00
This fixes all our GObject Introspection issues with GimpUnit which was both an enum and an int-derived type of user-defined units *completing* the enum values. GIR clearly didn't like this! Now GimpUnit is a proper class and units are unique objects, allowing to compare them with an identity test (i.e. `unit == gimp_unit_pixel ()` tells us if unit is the pixel unit or not), which makes it easy to use, just like with int, yet adding also methods, making for nicer introspected API. As an aside, this also fixes #10738, by having all the built-in units retrievable even if libgimpbase had not been properly initialized with gimp_base_init(). I haven't checked in details how GIR works to introspect, but it looks like it loads the library to inspect and runs functions, hence triggering some CRITICALS because virtual methods (supposed to be initialized with gimp_base_init() run by libgimp) are not set. This new code won't trigger any critical because the vtable method are now not necessary, at least for all built-in units. Note that GimpUnit is still in libgimpbase. It could have been moved to libgimp in order to avoid any virtual method table (since we need to keep core and libgimp side's units in sync, PDB is required), but too many libgimpwidgets widgets were already using GimpUnit. And technically most of GimpUnit logic doesn't require PDB (only the creation/sync part). This is one of the reasons why user-created GimpUnit list is handled and stored differently from other types of objects. Globally this simplifies the code a lot too and we don't need separate implementations of various utils for core and libgimp, which means less prone to errors.
1666 lines
59 KiB
C
1666 lines
59 KiB
C
/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gegl.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
#include "libgimpconfig/gimpconfig.h"
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "actions-types.h"
|
|
|
|
#include "config/gimpdialogconfig.h"
|
|
|
|
#include "gegl/gimp-babl.h"
|
|
|
|
#include "core/core-enums.h"
|
|
#include "core/gimp.h"
|
|
#include "core/gimpcontext.h"
|
|
#include "core/gimpimage.h"
|
|
#include "core/gimpimage-color-profile.h"
|
|
#include "core/gimpimage-convert-indexed.h"
|
|
#include "core/gimpimage-convert-precision.h"
|
|
#include "core/gimpimage-convert-type.h"
|
|
#include "core/gimpimage-crop.h"
|
|
#include "core/gimpimage-duplicate.h"
|
|
#include "core/gimpimage-flip.h"
|
|
#include "core/gimpimage-merge.h"
|
|
#include "core/gimpimage-resize.h"
|
|
#include "core/gimpimage-rotate.h"
|
|
#include "core/gimpimage-scale.h"
|
|
#include "core/gimpimage-undo.h"
|
|
#include "core/gimpitem.h"
|
|
#include "core/gimppickable.h"
|
|
#include "core/gimppickable-auto-shrink.h"
|
|
#include "core/gimpprogress.h"
|
|
|
|
#include "widgets/gimpdialogfactory.h"
|
|
#include "widgets/gimpdock.h"
|
|
#include "widgets/gimphelp-ids.h"
|
|
#include "widgets/gimpwidgets-utils.h"
|
|
|
|
#include "display/gimpdisplay.h"
|
|
#include "display/gimpdisplayshell.h"
|
|
|
|
#include "dialogs/dialogs.h"
|
|
#include "dialogs/color-profile-dialog.h"
|
|
#include "dialogs/convert-indexed-dialog.h"
|
|
#include "dialogs/convert-precision-dialog.h"
|
|
#include "dialogs/grid-dialog.h"
|
|
#include "dialogs/image-merge-layers-dialog.h"
|
|
#include "dialogs/image-new-dialog.h"
|
|
#include "dialogs/image-properties-dialog.h"
|
|
#include "dialogs/image-scale-dialog.h"
|
|
#include "dialogs/print-size-dialog.h"
|
|
#include "dialogs/resize-dialog.h"
|
|
|
|
#include "actions.h"
|
|
#include "image-commands.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static void image_convert_rgb_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data);
|
|
|
|
static void image_convert_gray_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data);
|
|
|
|
static void image_convert_indexed_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpConvertPaletteType palette_type,
|
|
gint max_colors,
|
|
gboolean remove_duplicates,
|
|
GimpConvertDitherType dither_type,
|
|
gboolean dither_alpha,
|
|
gboolean dither_text_layers,
|
|
GimpPalette *custom_palette,
|
|
gpointer user_data);
|
|
|
|
static void image_convert_precision_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpPrecision precision,
|
|
GeglDitherMethod layer_dither_method,
|
|
GeglDitherMethod text_layer_dither_method,
|
|
GeglDitherMethod mask_dither_method,
|
|
gpointer user_data);
|
|
|
|
static void image_profile_assign_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data);
|
|
|
|
static void image_profile_convert_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data);
|
|
|
|
static void image_resize_callback (GtkWidget *dialog,
|
|
GimpViewable *viewable,
|
|
GimpContext *context,
|
|
gint width,
|
|
gint height,
|
|
GimpUnit *unit,
|
|
gint offset_x,
|
|
gint offset_y,
|
|
gdouble xres,
|
|
gdouble yres,
|
|
GimpUnit *res_unit,
|
|
GimpFillType fill_type,
|
|
GimpItemSet layer_set,
|
|
gboolean resize_text_layers,
|
|
gpointer user_data);
|
|
|
|
static void image_print_size_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
gdouble xresolution,
|
|
gdouble yresolution,
|
|
GimpUnit *resolution_unit,
|
|
gpointer user_data);
|
|
|
|
static void image_scale_callback (GtkWidget *dialog,
|
|
GimpViewable *viewable,
|
|
gint width,
|
|
gint height,
|
|
GimpUnit *unit,
|
|
GimpInterpolationType interpolation,
|
|
gdouble xresolution,
|
|
gdouble yresolution,
|
|
GimpUnit *resolution_unit,
|
|
gpointer user_data);
|
|
|
|
static void image_merge_layers_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpContext *context,
|
|
GimpMergeType merge_type,
|
|
gboolean merge_active_group,
|
|
gboolean discard_invisible,
|
|
gpointer user_data);
|
|
|
|
static void image_softproof_profile_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data);
|
|
|
|
|
|
|
|
/* private variables */
|
|
|
|
static GimpUnit *image_resize_unit = NULL;
|
|
static GimpUnit *image_scale_unit = NULL;
|
|
static GimpInterpolationType image_scale_interp = -1;
|
|
static GimpPalette *image_convert_indexed_custom_palette = NULL;
|
|
|
|
|
|
/* public functions */
|
|
|
|
void
|
|
image_new_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GtkWidget *widget;
|
|
GtkWidget *dialog;
|
|
return_if_no_widget (widget, data);
|
|
|
|
dialog = gimp_dialog_factory_dialog_new (gimp_dialog_factory_get_singleton (),
|
|
gimp_widget_get_monitor (widget),
|
|
NULL /*ui_manager*/,
|
|
widget,
|
|
"gimp-image-new-dialog", -1, FALSE);
|
|
|
|
if (dialog)
|
|
{
|
|
GimpImage *image = action_data_get_image (data);
|
|
|
|
image_new_dialog_set (dialog, image, NULL);
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
}
|
|
|
|
void
|
|
image_duplicate_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GimpDisplayShell *shell;
|
|
GimpImage *new_image;
|
|
return_if_no_display (display, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
shell = gimp_display_get_shell (display);
|
|
|
|
new_image = gimp_image_duplicate (image);
|
|
|
|
gimp_create_display (new_image->gimp, new_image, shell->unit,
|
|
gimp_zoom_model_get_factor (shell->zoom),
|
|
G_OBJECT (gimp_widget_get_monitor (GTK_WIDGET (shell))));
|
|
|
|
g_object_unref (new_image);
|
|
}
|
|
|
|
void
|
|
image_convert_base_type_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
GimpDialogConfig *config;
|
|
GtkWidget *dialog;
|
|
GimpImageBaseType base_type;
|
|
GError *error = NULL;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
base_type = (GimpImageBaseType) g_variant_get_int32 (value);
|
|
|
|
if (base_type == gimp_image_get_base_type (image))
|
|
return;
|
|
|
|
#define CONVERT_TYPE_DIALOG_KEY "gimp-convert-type-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), CONVERT_TYPE_DIALOG_KEY);
|
|
|
|
if (dialog)
|
|
{
|
|
gtk_widget_destroy (dialog);
|
|
dialog = NULL;
|
|
}
|
|
|
|
config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
switch (base_type)
|
|
{
|
|
case GIMP_RGB:
|
|
case GIMP_GRAY:
|
|
if (gimp_image_get_color_profile (image))
|
|
{
|
|
ColorProfileDialogType dialog_type;
|
|
GimpColorProfileCallback callback;
|
|
GimpColorProfile *current_profile;
|
|
GimpColorProfile *default_profile;
|
|
GimpTRCType trc;
|
|
|
|
current_profile =
|
|
gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
|
|
trc = gimp_babl_trc (gimp_image_get_precision (image));
|
|
|
|
if (base_type == GIMP_RGB)
|
|
{
|
|
dialog_type = COLOR_PROFILE_DIALOG_CONVERT_TO_RGB;
|
|
callback = image_convert_rgb_callback;
|
|
|
|
default_profile = gimp_babl_get_builtin_color_profile (GIMP_RGB,
|
|
trc);
|
|
}
|
|
else
|
|
{
|
|
dialog_type = COLOR_PROFILE_DIALOG_CONVERT_TO_GRAY;
|
|
callback = image_convert_gray_callback;
|
|
|
|
default_profile = gimp_babl_get_builtin_color_profile (GIMP_GRAY,
|
|
trc);
|
|
}
|
|
|
|
dialog = color_profile_dialog_new (dialog_type,
|
|
image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
current_profile,
|
|
default_profile,
|
|
0, 0,
|
|
callback,
|
|
display);
|
|
}
|
|
else if (! gimp_image_convert_type (image, base_type, NULL, NULL, &error))
|
|
{
|
|
gimp_message_literal (image->gimp,
|
|
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
|
|
error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
break;
|
|
|
|
case GIMP_INDEXED:
|
|
dialog = convert_indexed_dialog_new (image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
config->image_convert_indexed_palette_type,
|
|
config->image_convert_indexed_max_colors,
|
|
config->image_convert_indexed_remove_duplicates,
|
|
config->image_convert_indexed_dither_type,
|
|
config->image_convert_indexed_dither_alpha,
|
|
config->image_convert_indexed_dither_text_layers,
|
|
image_convert_indexed_custom_palette,
|
|
image_convert_indexed_callback,
|
|
display);
|
|
break;
|
|
}
|
|
|
|
if (dialog)
|
|
{
|
|
dialogs_attach_dialog (G_OBJECT (image),
|
|
CONVERT_TYPE_DIALOG_KEY, dialog);
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
/* always flush, also when only the indexed dialog was shown, so
|
|
* the menu items get updated back to the current image type
|
|
*/
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_convert_precision_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
GimpDialogConfig *config;
|
|
GtkWidget *dialog;
|
|
GimpComponentType component_type;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
component_type = (GimpComponentType) g_variant_get_int32 (value);
|
|
|
|
if (component_type == gimp_image_get_component_type (image))
|
|
return;
|
|
|
|
#define CONVERT_PRECISION_DIALOG_KEY "gimp-convert-precision-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), CONVERT_PRECISION_DIALOG_KEY);
|
|
|
|
if (dialog)
|
|
{
|
|
gtk_widget_destroy (dialog);
|
|
dialog = NULL;
|
|
}
|
|
|
|
config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
dialog = convert_precision_dialog_new (image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
component_type,
|
|
config->image_convert_precision_layer_dither_method,
|
|
config->image_convert_precision_text_layer_dither_method,
|
|
config->image_convert_precision_channel_dither_method,
|
|
image_convert_precision_callback,
|
|
display);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image),
|
|
CONVERT_PRECISION_DIALOG_KEY, dialog);
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
|
|
/* see comment above */
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_convert_trc_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GimpTRCType trc_type;
|
|
GimpPrecision precision;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
|
|
trc_type = (GimpTRCType) g_variant_get_int32 (value);
|
|
|
|
if (trc_type == gimp_babl_format_get_trc (gimp_image_get_layer_format (image,
|
|
FALSE)))
|
|
return;
|
|
|
|
precision = gimp_babl_precision (gimp_image_get_component_type (image),
|
|
trc_type);
|
|
|
|
gimp_image_convert_precision (image, precision,
|
|
GEGL_DITHER_NONE,
|
|
GEGL_DITHER_NONE,
|
|
GEGL_DITHER_NONE,
|
|
GIMP_PROGRESS (display));
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_color_profile_use_srgb_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
gboolean use_srgb;
|
|
return_if_no_image (image, data);
|
|
|
|
use_srgb = g_variant_get_boolean (value);
|
|
|
|
if (use_srgb != gimp_image_get_use_srgb_profile (image, NULL))
|
|
{
|
|
gimp_image_set_use_srgb_profile (image, use_srgb);
|
|
gimp_image_flush (image);
|
|
}
|
|
}
|
|
|
|
void
|
|
image_color_profile_assign_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
GtkWidget *dialog;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
#define PROFILE_ASSIGN_DIALOG_KEY "gimp-profile-assign-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), PROFILE_ASSIGN_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpColorProfile *current_profile;
|
|
GimpColorProfile *default_profile;
|
|
|
|
current_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
default_profile = gimp_image_get_builtin_color_profile (image);
|
|
|
|
dialog = color_profile_dialog_new (COLOR_PROFILE_DIALOG_ASSIGN_PROFILE,
|
|
image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
current_profile,
|
|
default_profile,
|
|
0, 0,
|
|
image_profile_assign_callback,
|
|
display);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image),
|
|
PROFILE_ASSIGN_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_color_profile_convert_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
GtkWidget *dialog;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
#define PROFILE_CONVERT_DIALOG_KEY "gimp-profile-convert-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), PROFILE_CONVERT_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
GimpColorProfile *current_profile;
|
|
GimpColorProfile *default_profile;
|
|
|
|
current_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
default_profile = gimp_image_get_builtin_color_profile (image);
|
|
|
|
dialog = color_profile_dialog_new (COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE,
|
|
image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
current_profile,
|
|
default_profile,
|
|
config->image_convert_profile_intent,
|
|
config->image_convert_profile_bpc,
|
|
image_profile_convert_callback,
|
|
display);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image),
|
|
PROFILE_CONVERT_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_color_profile_discard_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
return_if_no_image (image, data);
|
|
|
|
gimp_image_assign_color_profile (image, NULL, NULL, NULL);
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
static void
|
|
image_profile_save_dialog_response (GtkWidget *dialog,
|
|
gint response_id,
|
|
GimpImage *image)
|
|
{
|
|
if (response_id == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
GimpColorProfile *profile;
|
|
GFile *file;
|
|
GError *error = NULL;
|
|
|
|
profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
|
|
|
if (! file)
|
|
return;
|
|
|
|
if (! gimp_color_profile_save_to_file (profile, file, &error))
|
|
{
|
|
gimp_message (image->gimp, NULL,
|
|
GIMP_MESSAGE_WARNING,
|
|
_("Saving color profile failed: %s"),
|
|
error->message);
|
|
g_clear_error (&error);
|
|
g_object_unref (file);
|
|
return;
|
|
}
|
|
|
|
g_object_unref (file);
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
void
|
|
image_color_profile_save_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
GtkWidget *dialog;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
#define PROFILE_SAVE_DIALOG_KEY "gimp-profile-save-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), PROFILE_SAVE_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GtkWindow *toplevel;
|
|
GimpColorProfile *profile;
|
|
gchar *basename;
|
|
|
|
toplevel = GTK_WINDOW (gtk_widget_get_toplevel (widget));
|
|
profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
|
|
dialog =
|
|
gimp_color_profile_chooser_dialog_new (_("Save Color Profile"),
|
|
toplevel,
|
|
GTK_FILE_CHOOSER_ACTION_SAVE);
|
|
|
|
gimp_color_profile_chooser_dialog_connect_path (dialog,
|
|
G_OBJECT (image->gimp->config),
|
|
"color-profile-path");
|
|
|
|
basename = g_strconcat (gimp_color_profile_get_label (profile),
|
|
".icc", NULL);
|
|
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), basename);
|
|
g_free (basename);
|
|
|
|
g_signal_connect (dialog, "response",
|
|
G_CALLBACK (image_profile_save_dialog_response),
|
|
image);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), PROFILE_SAVE_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_resize_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GtkWidget *widget;
|
|
GimpDisplay *display;
|
|
GtkWidget *dialog;
|
|
return_if_no_image (image, data);
|
|
return_if_no_widget (widget, data);
|
|
return_if_no_display (display, data);
|
|
|
|
#define RESIZE_DIALOG_KEY "gimp-resize-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), RESIZE_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
if (image_resize_unit != gimp_unit_percent ())
|
|
image_resize_unit = gimp_display_get_shell (display)->unit;
|
|
|
|
dialog = resize_dialog_new (GIMP_VIEWABLE (image),
|
|
action_data_get_context (data),
|
|
_("Set Image Canvas Size"),
|
|
"gimp-image-resize",
|
|
widget,
|
|
gimp_standard_help_func,
|
|
GIMP_HELP_IMAGE_RESIZE,
|
|
image_resize_unit,
|
|
config->image_resize_fill_type,
|
|
config->image_resize_layer_set,
|
|
config->image_resize_resize_text_layers,
|
|
image_resize_callback,
|
|
display);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), RESIZE_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_resize_to_layers_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GimpProgress *progress;
|
|
return_if_no_display (display, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (display), FALSE,
|
|
_("Resizing"));
|
|
|
|
gimp_image_resize_to_layers (image,
|
|
action_data_get_context (data),
|
|
NULL, NULL, NULL, NULL, progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_resize_to_selection_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GimpProgress *progress;
|
|
return_if_no_display (display, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (display), FALSE,
|
|
_("Resizing"));
|
|
|
|
gimp_image_resize_to_selection (image,
|
|
action_data_get_context (data),
|
|
progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_print_size_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GtkWidget *widget;
|
|
GtkWidget *dialog;
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
#define PRINT_SIZE_DIALOG_KEY "gimp-print-size-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), PRINT_SIZE_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
dialog = print_size_dialog_new (image,
|
|
action_data_get_context (data),
|
|
_("Set Image Print Resolution"),
|
|
"gimp-image-print-size",
|
|
widget,
|
|
gimp_standard_help_func,
|
|
GIMP_HELP_IMAGE_PRINT_SIZE,
|
|
image_print_size_callback,
|
|
NULL);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), PRINT_SIZE_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_scale_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GtkWidget *widget;
|
|
GtkWidget *dialog;
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
#define SCALE_DIALOG_KEY "gimp-scale-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), SCALE_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
if (image_scale_unit != gimp_unit_percent ())
|
|
image_scale_unit = gimp_display_get_shell (display)->unit;
|
|
|
|
if (image_scale_interp == -1)
|
|
image_scale_interp = display->gimp->config->interpolation_type;
|
|
|
|
dialog = image_scale_dialog_new (image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
image_scale_unit,
|
|
image_scale_interp,
|
|
image_scale_callback,
|
|
display);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), SCALE_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_flip_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GimpProgress *progress;
|
|
GimpOrientationType orientation;
|
|
return_if_no_display (display, data);
|
|
|
|
orientation = (GimpOrientationType) g_variant_get_int32 (value);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (display), FALSE,
|
|
_("Flipping"));
|
|
|
|
gimp_image_flip (image, action_data_get_context (data),
|
|
orientation, progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_rotate_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GimpProgress *progress;
|
|
GimpRotationType rotation;
|
|
return_if_no_display (display, data);
|
|
|
|
rotation = (GimpRotationType) g_variant_get_int32 (value);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (display), FALSE,
|
|
_("Rotating"));
|
|
|
|
gimp_image_rotate (image, action_data_get_context (data),
|
|
rotation, progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_crop_to_selection_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GtkWidget *widget;
|
|
gint x, y;
|
|
gint width, height;
|
|
return_if_no_image (image, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
if (! gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
|
|
&x, &y, &width, &height))
|
|
{
|
|
gimp_message_literal (image->gimp,
|
|
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
|
|
_("Cannot crop because the current selection "
|
|
"is empty."));
|
|
return;
|
|
}
|
|
|
|
gimp_image_crop (image,
|
|
action_data_get_context (data), GIMP_FILL_TRANSPARENT,
|
|
x, y, width, height, TRUE);
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_crop_to_content_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GtkWidget *widget;
|
|
gint x, y;
|
|
gint width, height;
|
|
return_if_no_image (image, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (image),
|
|
0, 0,
|
|
gimp_image_get_width (image),
|
|
gimp_image_get_height (image),
|
|
&x, &y, &width, &height))
|
|
{
|
|
case GIMP_AUTO_SHRINK_SHRINK:
|
|
gimp_image_crop (image,
|
|
action_data_get_context (data), GIMP_FILL_TRANSPARENT,
|
|
x, y, width, height, TRUE);
|
|
gimp_image_flush (image);
|
|
break;
|
|
|
|
case GIMP_AUTO_SHRINK_EMPTY:
|
|
gimp_message_literal (image->gimp,
|
|
G_OBJECT (widget), GIMP_MESSAGE_INFO,
|
|
_("Cannot crop because the image has no content."));
|
|
break;
|
|
|
|
case GIMP_AUTO_SHRINK_UNSHRINKABLE:
|
|
gimp_message_literal (image->gimp,
|
|
G_OBJECT (widget), GIMP_MESSAGE_INFO,
|
|
_("Cannot crop because the image is already "
|
|
"cropped to its content."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
image_merge_layers_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GtkWidget *dialog;
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
#define MERGE_LAYERS_DIALOG_KEY "gimp-merge-layers-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), MERGE_LAYERS_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
dialog = image_merge_layers_dialog_new (image,
|
|
action_data_get_context (data),
|
|
widget,
|
|
config->layer_merge_type,
|
|
config->layer_merge_active_group_only,
|
|
config->layer_merge_discard_invisible,
|
|
image_merge_layers_callback,
|
|
display);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), MERGE_LAYERS_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_merge_layers_last_vals_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GimpDialogConfig *config;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
|
|
config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
|
|
image_merge_layers_callback (NULL,
|
|
image,
|
|
action_data_get_context (data),
|
|
config->layer_merge_type,
|
|
config->layer_merge_active_group_only,
|
|
config->layer_merge_discard_invisible,
|
|
display);
|
|
}
|
|
|
|
void
|
|
image_flatten_image_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplay *display;
|
|
GtkWidget *widget;
|
|
GError *error = NULL;
|
|
return_if_no_image (image, data);
|
|
return_if_no_display (display, data);
|
|
return_if_no_widget (widget, data);
|
|
|
|
if (! gimp_image_flatten (image, action_data_get_context (data),
|
|
GIMP_PROGRESS (display), &error))
|
|
{
|
|
gimp_message_literal (image->gimp,
|
|
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
|
|
error->message);
|
|
g_clear_error (&error);
|
|
return;
|
|
}
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
void
|
|
image_configure_grid_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GtkWidget *dialog;
|
|
return_if_no_display (display, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
#define GRID_DIALOG_KEY "gimp-grid-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), GRID_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
|
|
dialog = grid_dialog_new (image,
|
|
action_data_get_context (data),
|
|
gtk_widget_get_toplevel (GTK_WIDGET (shell)));
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), GRID_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
void
|
|
image_properties_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpDisplay *display;
|
|
GimpImage *image;
|
|
GtkWidget *dialog;
|
|
return_if_no_display (display, data);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
#define PROPERTIES_DIALOG_KEY "gimp-image-properties-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (image), PROPERTIES_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
|
|
dialog = image_properties_dialog_new (image,
|
|
action_data_get_context (data),
|
|
gtk_widget_get_toplevel (GTK_WIDGET (shell)));
|
|
|
|
dialogs_attach_dialog (G_OBJECT (image), PROPERTIES_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
image_convert_rgb_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data)
|
|
{
|
|
GimpProgress *progress = user_data;
|
|
GError *error = NULL;
|
|
|
|
progress = gimp_progress_start (progress, FALSE,
|
|
_("Converting to RGB (%s)"),
|
|
gimp_color_profile_get_label (new_profile));
|
|
|
|
if (! gimp_image_convert_type (image, GIMP_RGB, new_profile,
|
|
progress, &error))
|
|
{
|
|
gimp_message (image->gimp, G_OBJECT (dialog),
|
|
GIMP_MESSAGE_ERROR,
|
|
"%s", error->message);
|
|
g_clear_error (&error);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
return;
|
|
}
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
image_convert_gray_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data)
|
|
{
|
|
GimpProgress *progress = user_data;
|
|
GError *error = NULL;
|
|
|
|
progress = gimp_progress_start (progress, FALSE,
|
|
_("Converting to grayscale (%s)"),
|
|
gimp_color_profile_get_label (new_profile));
|
|
|
|
if (! gimp_image_convert_type (image, GIMP_GRAY, new_profile,
|
|
progress, &error))
|
|
{
|
|
gimp_message (image->gimp, G_OBJECT (dialog),
|
|
GIMP_MESSAGE_ERROR,
|
|
"%s", error->message);
|
|
g_clear_error (&error);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
return;
|
|
}
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
image_convert_indexed_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpConvertPaletteType palette_type,
|
|
gint max_colors,
|
|
gboolean remove_duplicates,
|
|
GimpConvertDitherType dither_type,
|
|
gboolean dither_alpha,
|
|
gboolean dither_text_layers,
|
|
GimpPalette *custom_palette,
|
|
gpointer user_data)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
GimpDisplay *display = user_data;
|
|
GimpProgress *progress;
|
|
GError *error = NULL;
|
|
|
|
g_object_set (config,
|
|
"image-convert-indexed-palette-type", palette_type,
|
|
"image-convert-indexed-max-colors", max_colors,
|
|
"image-convert-indexed-remove-duplicates", remove_duplicates,
|
|
"image-convert-indexed-dither-type", dither_type,
|
|
"image-convert-indexed-dither-alpha", dither_alpha,
|
|
"image-convert-indexed-dither-text-layers", dither_text_layers,
|
|
NULL);
|
|
|
|
g_set_weak_pointer (&image_convert_indexed_custom_palette, custom_palette);
|
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (display), FALSE,
|
|
_("Converting to indexed colors"));
|
|
|
|
if (! gimp_image_convert_indexed (image,
|
|
config->image_convert_indexed_palette_type,
|
|
config->image_convert_indexed_max_colors,
|
|
config->image_convert_indexed_remove_duplicates,
|
|
config->image_convert_indexed_dither_type,
|
|
config->image_convert_indexed_dither_alpha,
|
|
config->image_convert_indexed_dither_text_layers,
|
|
image_convert_indexed_custom_palette,
|
|
progress,
|
|
&error))
|
|
{
|
|
gimp_message_literal (image->gimp, G_OBJECT (display),
|
|
GIMP_MESSAGE_WARNING, error->message);
|
|
g_clear_error (&error);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
return;
|
|
}
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
image_convert_precision_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpPrecision precision,
|
|
GeglDitherMethod layer_dither_method,
|
|
GeglDitherMethod text_layer_dither_method,
|
|
GeglDitherMethod channel_dither_method,
|
|
gpointer user_data)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
GimpProgress *progress = user_data;
|
|
const gchar *enum_desc;
|
|
const Babl *old_format;
|
|
const Babl *new_format;
|
|
gint old_bits;
|
|
gint new_bits;
|
|
|
|
g_object_set (config,
|
|
"image-convert-precision-layer-dither-method",
|
|
layer_dither_method,
|
|
"image-convert-precision-text-layer-dither-method",
|
|
text_layer_dither_method,
|
|
"image-convert-precision-channel-dither-method",
|
|
channel_dither_method,
|
|
NULL);
|
|
|
|
/* we do the same dither method checks here *and* in the dialog,
|
|
* because the dialog leaves the passed dither methods untouched if
|
|
* dithering is disabled and passes the original values to the
|
|
* callback, in order not to change the values saved in
|
|
* GimpDialogConfig.
|
|
*/
|
|
|
|
/* random formats with the right precision */
|
|
old_format = gimp_image_get_layer_format (image, FALSE);
|
|
new_format = gimp_babl_format (GIMP_RGB, precision, FALSE, NULL);
|
|
|
|
old_bits = (babl_format_get_bytes_per_pixel (old_format) * 8 /
|
|
babl_format_get_n_components (old_format));
|
|
new_bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
|
|
babl_format_get_n_components (new_format));
|
|
|
|
if (new_bits >= old_bits ||
|
|
new_bits > CONVERT_PRECISION_DIALOG_MAX_DITHER_BITS)
|
|
{
|
|
/* don't dither if we are converting to a higher bit depth,
|
|
* or to more than MAX_DITHER_BITS.
|
|
*/
|
|
layer_dither_method = GEGL_DITHER_NONE;
|
|
text_layer_dither_method = GEGL_DITHER_NONE;
|
|
channel_dither_method = GEGL_DITHER_NONE;
|
|
}
|
|
|
|
gimp_enum_get_value (GIMP_TYPE_PRECISION, precision,
|
|
NULL, NULL, &enum_desc, NULL);
|
|
|
|
progress = gimp_progress_start (progress, FALSE,
|
|
_("Converting image to %s"),
|
|
enum_desc);
|
|
|
|
gimp_image_convert_precision (image,
|
|
precision,
|
|
layer_dither_method,
|
|
text_layer_dither_method,
|
|
channel_dither_method,
|
|
progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
image_profile_assign_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
if (! gimp_image_assign_color_profile (image, new_profile, NULL, &error))
|
|
{
|
|
gimp_message (image->gimp, G_OBJECT (dialog),
|
|
GIMP_MESSAGE_ERROR,
|
|
"%s", error->message);
|
|
g_clear_error (&error);
|
|
|
|
return;
|
|
}
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
image_profile_convert_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
GimpProgress *progress = user_data;
|
|
GError *error = NULL;
|
|
|
|
g_object_set (config,
|
|
"image-convert-profile-intent", intent,
|
|
"image-convert-profile-black-point-compensation", bpc,
|
|
NULL);
|
|
|
|
progress = gimp_progress_start (progress, FALSE,
|
|
_("Converting to '%s'"),
|
|
gimp_color_profile_get_label (new_profile));
|
|
|
|
if (! gimp_image_convert_color_profile (image, new_profile,
|
|
config->image_convert_profile_intent,
|
|
config->image_convert_profile_bpc,
|
|
progress, &error))
|
|
{
|
|
gimp_message (image->gimp, G_OBJECT (dialog),
|
|
GIMP_MESSAGE_ERROR,
|
|
"%s", error->message);
|
|
g_clear_error (&error);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
return;
|
|
}
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
image_resize_callback (GtkWidget *dialog,
|
|
GimpViewable *viewable,
|
|
GimpContext *context,
|
|
gint width,
|
|
gint height,
|
|
GimpUnit *unit,
|
|
gint offset_x,
|
|
gint offset_y,
|
|
gdouble xres,
|
|
gdouble yres,
|
|
GimpUnit *res_unit,
|
|
GimpFillType fill_type,
|
|
GimpItemSet layer_set,
|
|
gboolean resize_text_layers,
|
|
gpointer user_data)
|
|
{
|
|
GimpDisplay *display = user_data;
|
|
|
|
image_resize_unit = unit;
|
|
|
|
if (width > 0 && height > 0)
|
|
{
|
|
GimpImage *image = GIMP_IMAGE (viewable);
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
GimpProgress *progress;
|
|
gdouble old_xres;
|
|
gdouble old_yres;
|
|
GimpUnit *old_res_unit;
|
|
gboolean update_resolution;
|
|
|
|
g_object_set (config,
|
|
"image-resize-fill-type", fill_type,
|
|
"image-resize-layer-set", layer_set,
|
|
"image-resize-resize-text-layers", resize_text_layers,
|
|
NULL);
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
if (width == gimp_image_get_width (image) &&
|
|
height == gimp_image_get_height (image))
|
|
return;
|
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (display), FALSE,
|
|
_("Resizing"));
|
|
|
|
gimp_image_get_resolution (image, &old_xres, &old_yres);
|
|
old_res_unit = gimp_image_get_unit (image);
|
|
|
|
update_resolution = xres != old_xres ||
|
|
yres != old_yres ||
|
|
res_unit != old_res_unit;
|
|
|
|
if (update_resolution)
|
|
{
|
|
gimp_image_undo_group_start (image,
|
|
GIMP_UNDO_GROUP_IMAGE_SCALE,
|
|
_("Change Canvas Size"));
|
|
gimp_image_set_resolution (image, xres, yres);
|
|
gimp_image_set_unit (image, res_unit);
|
|
}
|
|
|
|
gimp_image_resize_with_layers (image,
|
|
context, fill_type,
|
|
width, height,
|
|
offset_x, offset_y,
|
|
layer_set,
|
|
resize_text_layers,
|
|
progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
|
|
if (update_resolution)
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("Resize Error: "
|
|
"Both width and height must be greater than zero.");
|
|
}
|
|
}
|
|
|
|
static void
|
|
image_print_size_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
gdouble xresolution,
|
|
gdouble yresolution,
|
|
GimpUnit *resolution_unit,
|
|
gpointer data)
|
|
{
|
|
gdouble xres;
|
|
gdouble yres;
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
|
|
|
if (xresolution == xres &&
|
|
yresolution == yres &&
|
|
resolution_unit == gimp_image_get_unit (image))
|
|
return;
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_SCALE,
|
|
_("Change Print Size"));
|
|
|
|
gimp_image_set_resolution (image, xresolution, yresolution);
|
|
gimp_image_set_unit (image, resolution_unit);
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
|
|
static void
|
|
image_scale_callback (GtkWidget *dialog,
|
|
GimpViewable *viewable,
|
|
gint width,
|
|
gint height,
|
|
GimpUnit *unit,
|
|
GimpInterpolationType interpolation,
|
|
gdouble xresolution,
|
|
gdouble yresolution,
|
|
GimpUnit *resolution_unit,
|
|
gpointer user_data)
|
|
{
|
|
GimpProgress *progress = user_data;
|
|
GimpImage *image = GIMP_IMAGE (viewable);
|
|
gdouble xres;
|
|
gdouble yres;
|
|
|
|
image_scale_unit = unit;
|
|
image_scale_interp = interpolation;
|
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
|
|
|
if (width > 0 && height > 0)
|
|
{
|
|
gtk_widget_destroy (dialog);
|
|
|
|
if (width == gimp_image_get_width (image) &&
|
|
height == gimp_image_get_height (image) &&
|
|
xresolution == xres &&
|
|
yresolution == yres &&
|
|
resolution_unit == gimp_image_get_unit (image))
|
|
return;
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_SCALE,
|
|
_("Scale Image"));
|
|
|
|
gimp_image_set_resolution (image, xresolution, yresolution);
|
|
gimp_image_set_unit (image, resolution_unit);
|
|
|
|
if (width != gimp_image_get_width (image) ||
|
|
height != gimp_image_get_height (image))
|
|
{
|
|
progress = gimp_progress_start (progress, FALSE,
|
|
_("Scaling"));
|
|
|
|
gimp_image_scale (image, width, height, interpolation, progress);
|
|
|
|
if (progress)
|
|
gimp_progress_end (progress);
|
|
}
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
gimp_image_flush (image);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("Scale Error: "
|
|
"Both width and height must be greater than zero.");
|
|
}
|
|
}
|
|
|
|
static void
|
|
image_merge_layers_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpContext *context,
|
|
GimpMergeType merge_type,
|
|
gboolean merge_active_group,
|
|
gboolean discard_invisible,
|
|
gpointer user_data)
|
|
{
|
|
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
|
GimpDisplay *display = user_data;
|
|
|
|
g_object_set (config,
|
|
"layer-merge-type", merge_type,
|
|
"layer-merge-active-group-only", merge_active_group,
|
|
"layer-merge-discard-invisible", discard_invisible,
|
|
NULL);
|
|
|
|
gimp_image_merge_visible_layers (image,
|
|
context,
|
|
config->layer_merge_type,
|
|
config->layer_merge_active_group_only,
|
|
config->layer_merge_discard_invisible,
|
|
GIMP_PROGRESS (display));
|
|
|
|
gimp_image_flush (image);
|
|
|
|
g_clear_pointer (&dialog, gtk_widget_destroy);
|
|
}
|
|
|
|
void
|
|
image_softproof_profile_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplayShell *shell;
|
|
GtkWidget *dialog;
|
|
return_if_no_image (image, data);
|
|
return_if_no_shell (shell, data);
|
|
|
|
#define SOFTPROOF_PROFILE_DIALOG_KEY "gimp-softproof-profile-dialog"
|
|
|
|
dialog = dialogs_get_dialog (G_OBJECT (shell), SOFTPROOF_PROFILE_DIALOG_KEY);
|
|
|
|
if (! dialog)
|
|
{
|
|
GimpColorProfile *current_profile;
|
|
|
|
current_profile = gimp_image_get_simulation_profile (image);
|
|
|
|
dialog = color_profile_dialog_new (COLOR_PROFILE_DIALOG_SELECT_SOFTPROOF_PROFILE,
|
|
image,
|
|
action_data_get_context (data),
|
|
GTK_WIDGET (shell),
|
|
current_profile,
|
|
NULL,
|
|
0, 0,
|
|
image_softproof_profile_callback,
|
|
shell);
|
|
|
|
dialogs_attach_dialog (G_OBJECT (shell),
|
|
SOFTPROOF_PROFILE_DIALOG_KEY, dialog);
|
|
}
|
|
|
|
gtk_window_present (GTK_WINDOW (dialog));
|
|
}
|
|
|
|
static void
|
|
image_softproof_profile_callback (GtkWidget *dialog,
|
|
GimpImage *image,
|
|
GimpColorProfile *new_profile,
|
|
GFile *new_file,
|
|
GimpColorRenderingIntent intent,
|
|
gboolean bpc,
|
|
gpointer user_data)
|
|
{
|
|
GimpDisplayShell *shell = user_data;
|
|
|
|
/* Update image's simulation profile */
|
|
gimp_image_set_simulation_profile (image, new_profile);
|
|
gimp_color_managed_simulation_profile_changed (GIMP_COLOR_MANAGED (shell));
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
void
|
|
image_softproof_intent_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplayShell *shell;
|
|
GimpColorRenderingIntent intent;
|
|
return_if_no_image (image, data);
|
|
return_if_no_shell (shell, data);
|
|
|
|
intent = (GimpColorRenderingIntent) g_variant_get_int32 (value);
|
|
|
|
if (intent != gimp_image_get_simulation_intent (image))
|
|
{
|
|
gimp_image_set_simulation_intent (image, intent);
|
|
shell->color_config_set = TRUE;
|
|
gimp_color_managed_simulation_intent_changed (GIMP_COLOR_MANAGED (shell));
|
|
}
|
|
}
|
|
|
|
void
|
|
image_softproof_bpc_cmd_callback (GimpAction *action,
|
|
GVariant *value,
|
|
gpointer data)
|
|
{
|
|
GimpImage *image;
|
|
GimpDisplayShell *shell;
|
|
gboolean bpc;
|
|
return_if_no_image (image, data);
|
|
return_if_no_shell (shell, data);
|
|
|
|
bpc = g_variant_get_boolean (value);
|
|
|
|
if (bpc != gimp_image_get_simulation_bpc (image))
|
|
{
|
|
gimp_image_set_simulation_bpc (image, bpc);
|
|
shell->color_config_set = TRUE;
|
|
gimp_color_managed_simulation_bpc_changed (GIMP_COLOR_MANAGED (shell));
|
|
}
|
|
}
|