[gimp] app, libgimp, plug-ins: move Orientation metadata handling into core.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app, libgimp, plug-ins: move Orientation metadata handling into core.
- Date: Thu, 24 Sep 2020 10:54:30 +0000 (UTC)
commit 67e2e1b5bb5bfe072fee9dab1314613d1129cdc1
Author: Jehan <jehan girinstud io>
Date: Wed Sep 23 19:59:09 2020 +0200
app, libgimp, plug-ins: move Orientation metadata handling into core.
Orientation is now handled by core code, just next to profile conversion
handling.
One of the first consequence is that we don't need to have a non-GUI
version gimp_image_metadata_load_finish_batch() in libgimp, next to a
GUI version of the gimp_image_metadata_load_finish() function in
libgimpui. This makes for simpler API.
Also a plug-in which wishes to get access to the rotation dialog
provided by GIMP without loading ligimpui/GTK+ (for whatever reason)
will still have the feature.
The main advantage is that the "Don't ask me again" feature is now
handled by a settings in `Preferences > Image Import & Export` as the
"Metadata rotation policy". Until now it was saved as a global parasite,
which made it virtually non-editable once you checked it once (no easy
way to edit parasites except by scripts). So say you refused the
rotation once while checking "Don't ask again", and GIMP will forever
discard the rotation metadata without giving you a sane way to change
your mind. Of course, I could have passed the settings to plug-ins
through the PDB, but I find it a lot better to simply handle such
settings core-side.
The dialog code is basically the same as an app/dialogs/ as it was in
libgimp, with the minor improvement that it now takes the scale ratio
into account (basically the maximum thumbnail size will be bigger on
higher density displays).
Only downside of the move to the core is that this rotation dialog is
raised only when you open an image from the core, not as a PDB call. So
a plug-in which makes say a "file-jpeg-load" PDB call, even in
INTERACTIVE run mode, won't have rotation processed. Note that this was
already the same for embedded color profile conversion. This can be
wanted or not. Anyway some additional libgimp calls might be of interest
to explicitly call the core dialogs.
app/config/gimpdialogconfig.c | 15 ++
app/config/gimpdialogconfig.h | 3 +-
app/config/gimprc-blurbs.h | 3 +
app/core/core-enums.c | 31 +++
app/core/core-enums.h | 12 +
app/core/gimp-gui.c | 17 ++
app/core/gimp-gui.h | 12 +
app/core/gimpimage-rotate.c | 130 ++++++++-
app/core/gimpimage-rotate.h | 12 +-
app/dialogs/Makefile.am | 1 +
app/dialogs/meson.build | 1 +
app/dialogs/metadata-rotation-import-dialog.c | 282 ++++++++++++++++++++
app/dialogs/metadata-rotation-import-dialog.h | 31 +++
app/dialogs/preferences-dialog.c | 3 +
app/file/file-import.c | 2 +
app/gui/gui-vtable.c | 17 ++
libgimp/Makefile.gi | 2 -
libgimp/gimpimagemetadata-interactive.c | 369 --------------------------
libgimp/gimpimagemetadata-interactive.h | 36 ---
libgimp/gimpimagemetadata.c | 31 +--
libgimp/gimpimagemetadata.h | 8 +-
libgimp/gimpui.h | 1 -
libgimp/meson.build | 2 -
plug-ins/common/file-heif.c | 3 +-
plug-ins/common/file-jp2-load.c | 3 +-
plug-ins/common/file-png.c | 3 +-
plug-ins/file-exr/file-exr.c | 2 +-
plug-ins/file-jpeg/jpeg.c | 6 +-
plug-ins/file-psd/psd.c | 6 +-
plug-ins/file-tiff/file-tiff.c | 3 +-
plug-ins/file-webp/file-webp-load.c | 3 +-
po-libgimp/POTFILES.in | 1 -
32 files changed, 578 insertions(+), 473 deletions(-)
---
diff --git a/app/config/gimpdialogconfig.c b/app/config/gimpdialogconfig.c
index ca13737784..4162526b0e 100644
--- a/app/config/gimpdialogconfig.c
+++ b/app/config/gimpdialogconfig.c
@@ -47,6 +47,7 @@ enum
PROP_GIMP,
PROP_COLOR_PROFILE_POLICY,
+ PROP_METADATA_ROTATION_POLICY,
PROP_COLOR_PROFILE_PATH,
@@ -176,6 +177,14 @@ gimp_dialog_config_class_init (GimpDialogConfigClass *klass)
GIMP_COLOR_PROFILE_POLICY_ASK,
GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_PROP_ENUM (object_class, PROP_METADATA_ROTATION_POLICY,
+ "metadata-rotation-policy",
+ "Metadata rotation policy",
+ METADATA_ROTATION_POLICY_BLURB,
+ GIMP_TYPE_METADATA_ROTATION_POLICY,
+ GIMP_METADATA_ROTATION_POLICY_ASK,
+ GIMP_PARAM_STATIC_STRINGS);
+
GIMP_CONFIG_PROP_PATH (object_class, PROP_COLOR_PROFILE_PATH,
"color-profile-path",
"Default color profile folder path",
@@ -604,6 +613,9 @@ gimp_dialog_config_set_property (GObject *object,
case PROP_COLOR_PROFILE_POLICY:
config->color_profile_policy = g_value_get_enum (value);
break;
+ case PROP_METADATA_ROTATION_POLICY:
+ config->metadata_rotation_policy = g_value_get_enum (value);
+ break;
case PROP_COLOR_PROFILE_PATH:
if (config->color_profile_path)
@@ -804,6 +816,9 @@ gimp_dialog_config_get_property (GObject *object,
case PROP_COLOR_PROFILE_POLICY:
g_value_set_enum (value, config->color_profile_policy);
break;
+ case PROP_METADATA_ROTATION_POLICY:
+ g_value_set_enum (value, config->metadata_rotation_policy);
+ break;
case PROP_COLOR_PROFILE_PATH:
g_value_set_string (value, config->color_profile_path);
diff --git a/app/config/gimpdialogconfig.h b/app/config/gimpdialogconfig.h
index 1053f6d339..882576199b 100644
--- a/app/config/gimpdialogconfig.h
+++ b/app/config/gimpdialogconfig.h
@@ -44,7 +44,8 @@ struct _GimpDialogConfig
{
GimpGuiConfig parent_instance;
- GimpColorProfilePolicy color_profile_policy;
+ GimpColorProfilePolicy color_profile_policy;
+ GimpMetadataRotationPolicy metadata_rotation_policy;
gchar *color_profile_path;
diff --git a/app/config/gimprc-blurbs.h b/app/config/gimprc-blurbs.h
index 7f20b3739b..507b59234b 100644
--- a/app/config/gimprc-blurbs.h
+++ b/app/config/gimprc-blurbs.h
@@ -281,6 +281,9 @@ _("Speed of marching ants in the selection outline. This value is in " \
_("GIMP will warn the user if an attempt is made to create an image that " \
"would take more memory than the size specified here.")
+#define METADATA_ROTATION_POLICY_BLURB \
+_("How to handle \"Orientation\" metadata when opening a file.")
+
#define MODULE_PATH_BLURB \
"Sets the module search path."
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index e86fe391fe..f172793174 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -919,6 +919,37 @@ gimp_message_severity_get_type (void)
return type;
}
+GType
+gimp_metadata_rotation_policy_get_type (void)
+{
+ static const GEnumValue values[] =
+ {
+ { GIMP_METADATA_ROTATION_POLICY_ASK, "GIMP_METADATA_ROTATION_POLICY_ASK", "ask" },
+ { GIMP_METADATA_ROTATION_POLICY_KEEP, "GIMP_METADATA_ROTATION_POLICY_KEEP", "keep" },
+ { GIMP_METADATA_ROTATION_POLICY_ROTATE, "GIMP_METADATA_ROTATION_POLICY_ROTATE", "rotate" },
+ { 0, NULL, NULL }
+ };
+
+ static const GimpEnumDesc descs[] =
+ {
+ { GIMP_METADATA_ROTATION_POLICY_ASK, NC_("metadata-rotation-policy", "Ask what to do"), NULL },
+ { GIMP_METADATA_ROTATION_POLICY_KEEP, NC_("metadata-rotation-policy", "Discard metadata without
rotating"), NULL },
+ { GIMP_METADATA_ROTATION_POLICY_ROTATE, NC_("metadata-rotation-policy", "Rotate the image then discard
metadata"), NULL },
+ { 0, NULL, NULL }
+ };
+
+ static GType type = 0;
+
+ if (G_UNLIKELY (! type))
+ {
+ type = g_enum_register_static ("GimpMetadataRotationPolicy", values);
+ gimp_type_set_translation_context (type, "metadata-rotation-policy");
+ gimp_enum_set_value_descriptions (type, descs);
+ }
+
+ return type;
+}
+
GType
gimp_paste_type_get_type (void)
{
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index 2b988c1ed7..7a8424cba3 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -419,6 +419,18 @@ typedef enum /*< pdb-skip >*/
} GimpMessageSeverity;
+#define GIMP_TYPE_METADATA_ROTATION_POLICY (gimp_metadata_rotation_policy_get_type ())
+
+GType gimp_metadata_rotation_policy_get_type (void) G_GNUC_CONST;
+
+typedef enum /*< pdb-skip >*/
+{
+ GIMP_METADATA_ROTATION_POLICY_ASK, /*< desc="Ask what to do" >*/
+ GIMP_METADATA_ROTATION_POLICY_KEEP, /*< desc="Discard metadata without rotating" >*/
+ GIMP_METADATA_ROTATION_POLICY_ROTATE /*< desc="Rotate the image then discard metadata" >*/
+} GimpMetadataRotationPolicy;
+
+
#define GIMP_TYPE_PASTE_TYPE (gimp_paste_type_get_type ())
GType gimp_paste_type_get_type (void) G_GNUC_CONST;
diff --git a/app/core/gimp-gui.c b/app/core/gimp-gui.c
index 42786b8786..f89df788b7 100644
--- a/app/core/gimp-gui.c
+++ b/app/core/gimp-gui.c
@@ -65,6 +65,7 @@ gimp_gui_init (Gimp *gimp)
gimp->gui.recent_list_load = NULL;
gimp->gui.get_mount_operation = NULL;
gimp->gui.query_profile_policy = NULL;
+ gimp->gui.query_rotation_policy = NULL;
}
void
@@ -536,3 +537,19 @@ gimp_query_profile_policy (Gimp *gimp,
return GIMP_COLOR_PROFILE_POLICY_KEEP;
}
+
+GimpMetadataRotationPolicy
+gimp_query_rotation_policy (Gimp *gimp,
+ GimpImage *image,
+ GimpContext *context,
+ gboolean *dont_ask)
+{
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), GIMP_METADATA_ROTATION_POLICY_ROTATE);
+ g_return_val_if_fail (GIMP_IS_IMAGE (image), GIMP_METADATA_ROTATION_POLICY_ROTATE);
+ g_return_val_if_fail (GIMP_IS_CONTEXT (context), GIMP_METADATA_ROTATION_POLICY_ROTATE);
+
+ if (gimp->gui.query_rotation_policy)
+ return gimp->gui.query_rotation_policy (gimp, image, context, dont_ask);
+
+ return GIMP_METADATA_ROTATION_POLICY_ROTATE;
+}
diff --git a/app/core/gimp-gui.h b/app/core/gimp-gui.h
index f9a465f0d7..ac16fc3f64 100644
--- a/app/core/gimp-gui.h
+++ b/app/core/gimp-gui.h
@@ -103,6 +103,12 @@ struct _GimpGui
GimpColorRenderingIntent *intent,
gboolean *bpc,
gboolean *dont_ask);
+
+ GimpMetadataRotationPolicy
+ (* query_rotation_policy) (Gimp *gimp,
+ GimpImage *image,
+ GimpContext *context,
+ gboolean *dont_ask);
};
@@ -196,5 +202,11 @@ GimpColorProfilePolicy
gboolean *bpc,
gboolean *dont_ask);
+GimpMetadataRotationPolicy
+ gimp_query_rotation_policy (Gimp *gimp,
+ GimpImage *image,
+ GimpContext *context,
+ gboolean *dont_ask);
+
#endif /* __GIMP_GUI_H__ */
diff --git a/app/core/gimpimage-rotate.c b/app/core/gimpimage-rotate.c
index 682319f9a9..36e8dbf792 100644
--- a/app/core/gimpimage-rotate.c
+++ b/app/core/gimpimage-rotate.c
@@ -19,9 +19,12 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
+#include <gexiv2/gexiv2.h>
#include "core-types.h"
+#include "config/gimpdialogconfig.h"
+
#include "vectors/gimpvectors.h"
#include "gimp.h"
@@ -29,6 +32,8 @@
#include "gimpcontext.h"
#include "gimpguide.h"
#include "gimpimage.h"
+#include "gimpimage-flip.h"
+#include "gimpimage-metadata.h"
#include "gimpimage-rotate.h"
#include "gimpimage-guides.h"
#include "gimpimage-sample-points.h"
@@ -41,17 +46,24 @@
#include "gimpsamplepoint.h"
-static void gimp_image_rotate_item_offset (GimpImage *image,
- GimpRotationType rotate_type,
- GimpItem *item,
- gint off_x,
- gint off_y);
-static void gimp_image_rotate_guides (GimpImage *image,
- GimpRotationType rotate_type);
-static void gimp_image_rotate_sample_points (GimpImage *image,
- GimpRotationType rotate_type);
+static void gimp_image_rotate_item_offset (GimpImage *image,
+ GimpRotationType rotate_type,
+ GimpItem *item,
+ gint off_x,
+ gint off_y);
+static void gimp_image_rotate_guides (GimpImage *image,
+ GimpRotationType rotate_type);
+static void gimp_image_rotate_sample_points (GimpImage *image,
+ GimpRotationType rotate_type);
+
+static void gimp_image_metadata_rotate (GimpImage *image,
+ GimpContext *context,
+ GExiv2Orientation orientation,
+ GimpProgress *progress);
+/* Public Functions */
+
void
gimp_image_rotate (GimpImage *image,
GimpContext *context,
@@ -214,6 +226,59 @@ gimp_image_rotate (GimpImage *image,
gimp_unset_busy (image->gimp);
}
+void
+gimp_image_import_rotation_metadata (GimpImage *image,
+ GimpContext *context,
+ GimpProgress *progress,
+ gboolean interactive)
+{
+ GimpMetadata *metadata;
+
+ g_return_if_fail (GIMP_IS_IMAGE (image));
+ g_return_if_fail (GIMP_IS_CONTEXT (context));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+
+ metadata = gimp_image_get_metadata (image);
+
+ if (metadata)
+ {
+ GimpMetadataRotationPolicy policy;
+
+ policy = GIMP_DIALOG_CONFIG (image->gimp->config)->metadata_rotation_policy;
+ if (policy == GIMP_METADATA_ROTATION_POLICY_ASK)
+ {
+ if (interactive)
+ {
+ gboolean dont_ask = FALSE;
+
+ policy = gimp_query_rotation_policy (image->gimp, image,
+ context, &dont_ask);
+
+ if (dont_ask)
+ {
+ g_object_set (G_OBJECT (image->gimp->config),
+ "metadata-rotation-policy", policy,
+ NULL);
+ }
+ }
+ else
+ {
+ policy = GIMP_METADATA_ROTATION_POLICY_ROTATE;
+ }
+ }
+
+ if (policy == GIMP_METADATA_ROTATION_POLICY_ROTATE)
+ gimp_image_metadata_rotate (image, context,
+ gexiv2_metadata_get_orientation (GEXIV2_METADATA (metadata)),
+ progress);
+
+ gexiv2_metadata_set_orientation (GEXIV2_METADATA (metadata),
+ GEXIV2_ORIENTATION_NORMAL);
+ }
+}
+
+
+/* Private Functions */
static void
gimp_image_rotate_item_offset (GimpImage *image,
@@ -375,3 +440,50 @@ gimp_image_rotate_sample_points (GimpImage *image,
}
}
}
+
+static void
+gimp_image_metadata_rotate (GimpImage *image,
+ GimpContext *context,
+ GExiv2Orientation orientation,
+ GimpProgress *progress)
+{
+ switch (orientation)
+ {
+ case GEXIV2_ORIENTATION_UNSPECIFIED:
+ case GEXIV2_ORIENTATION_NORMAL: /* standard orientation, do nothing */
+ break;
+
+ case GEXIV2_ORIENTATION_HFLIP:
+ gimp_image_flip (image, context, GIMP_ORIENTATION_HORIZONTAL, progress);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_180:
+ gimp_image_rotate (image, context, GIMP_ROTATE_180, progress);
+ break;
+
+ case GEXIV2_ORIENTATION_VFLIP:
+ gimp_image_flip (image, context, GIMP_ORIENTATION_VERTICAL, progress);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_90_HFLIP: /* flipped diagonally around '\' */
+ gimp_image_rotate (image, context, GIMP_ROTATE_90, progress);
+ gimp_image_flip (image, context, GIMP_ORIENTATION_HORIZONTAL, progress);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_90: /* 90 CW */
+ gimp_image_rotate (image, context, GIMP_ROTATE_90, progress);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_90_VFLIP: /* flipped diagonally around '/' */
+ gimp_image_rotate (image, context, GIMP_ROTATE_90, progress);
+ gimp_image_flip (image, context, GIMP_ORIENTATION_VERTICAL, progress);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_270: /* 90 CCW */
+ gimp_image_rotate (image, context, GIMP_ROTATE_270, progress);
+ break;
+
+ default: /* shouldn't happen */
+ break;
+ }
+}
diff --git a/app/core/gimpimage-rotate.h b/app/core/gimpimage-rotate.h
index cad0de858a..7a8f812ac6 100644
--- a/app/core/gimpimage-rotate.h
+++ b/app/core/gimpimage-rotate.h
@@ -19,10 +19,14 @@
#define __GIMP_IMAGE_ROTATE_H__
-void gimp_image_rotate (GimpImage *image,
- GimpContext *context,
- GimpRotationType rotate_type,
- GimpProgress *progress);
+void gimp_image_rotate (GimpImage *image,
+ GimpContext *context,
+ GimpRotationType rotate_type,
+ GimpProgress *progress);
+void gimp_image_import_rotation_metadata (GimpImage *image,
+ GimpContext *context,
+ GimpProgress *progress,
+ gboolean interactive);
#endif /* __GIMP_IMAGE_ROTATE_H__ */
diff --git a/app/dialogs/Makefile.am b/app/dialogs/Makefile.am
index 61c2959f9e..2875d63347 100644
--- a/app/dialogs/Makefile.am
+++ b/app/dialogs/Makefile.am
@@ -67,6 +67,7 @@ libappdialogs_a_sources = \
layer-options-dialog.h \
lebl-dialog.c \
lebl-dialog.h \
+ metadata-rotation-import-dialog.c \
module-dialog.c \
module-dialog.h \
palette-import-dialog.c \
diff --git a/app/dialogs/meson.build b/app/dialogs/meson.build
index c6281767c4..d934dadecf 100644
--- a/app/dialogs/meson.build
+++ b/app/dialogs/meson.build
@@ -25,6 +25,7 @@ libappdialogs_sources = [
'layer-add-mask-dialog.c',
'layer-options-dialog.c',
'lebl-dialog.c',
+ 'metadata-rotation-import-dialog.c',
'module-dialog.c',
'palette-import-dialog.c',
'preferences-dialog-utils.c',
diff --git a/app/dialogs/metadata-rotation-import-dialog.c b/app/dialogs/metadata-rotation-import-dialog.c
new file mode 100644
index 0000000000..ec5f0461d2
--- /dev/null
+++ b/app/dialogs/metadata-rotation-import-dialog.c
@@ -0,0 +1,282 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * metadata-rotation-import-dialog.h
+ * Copyright (C) 2020 Jehan
+ *
+ * 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 <gexiv2/gexiv2.h>
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "dialogs-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-metadata.h"
+#include "core/gimppickable.h"
+
+#include "widgets/gimphelp-ids.h"
+#include "widgets/gimpviewabledialog.h"
+#include "widgets/gimpwidgets-constructors.h"
+
+#include "metadata-rotation-import-dialog.h"
+
+#include "gimp-intl.h"
+
+
+static GimpMetadataRotationPolicy gimp_image_metadata_rotate_dialog (GimpImage *image,
+ GimpContext *context,
+ GExiv2Orientation orientation,
+ gboolean *dont_ask);
+static GdkPixbuf * gimp_image_metadata_rotate_pixbuf (GdkPixbuf *pixbuf,
+ GExiv2Orientation orientation);
+
+
+/* public functions */
+
+GimpMetadataRotationPolicy
+metadata_rotation_import_dialog_run (GimpImage *image,
+ GimpContext *context,
+ GtkWidget *parent,
+ gboolean *dont_ask)
+{
+ GimpMetadata *metadata;
+ GExiv2Orientation orientation;
+
+ metadata = gimp_image_get_metadata (image);
+ orientation = gexiv2_metadata_get_orientation (GEXIV2_METADATA (metadata));
+
+ if (orientation <= GEXIV2_ORIENTATION_NORMAL ||
+ orientation > GEXIV2_ORIENTATION_MAX)
+ return GIMP_METADATA_ROTATION_POLICY_KEEP;
+
+ return gimp_image_metadata_rotate_dialog (image, context, orientation, dont_ask);
+}
+
+static GimpMetadataRotationPolicy
+gimp_image_metadata_rotate_dialog (GimpImage *image,
+ GimpContext *context,
+ GExiv2Orientation orientation,
+ gboolean *dont_ask)
+{
+ GtkWidget *dialog;
+ GtkWidget *main_vbox;
+ GtkWidget *vbox;
+ GtkWidget *label;
+ GtkWidget *toggle;
+ const gchar *name;
+ gchar *title;
+ GdkPixbuf *pixbuf;
+ gint width;
+ gint scale_factor;
+ gint height;
+ gint response;
+
+ name = gimp_image_get_display_name (image);
+ title = g_strdup_printf (_("Rotate %s?"), name);
+
+ dialog = gimp_dialog_new (title, "gimp-metadata-rotate-dialog",
+ NULL, 0, NULL, NULL,
+
+ _("_Keep Original"), GTK_RESPONSE_CANCEL,
+ _("_Rotate"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ g_free (title);
+
+ gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ main_vbox, FALSE, FALSE, 0);
+ gtk_widget_show (main_vbox);
+
+ scale_factor = gtk_widget_get_scale_factor (main_vbox);
+ width = gimp_image_get_width (image);
+ height = gimp_image_get_height (image);
+
+#define MAX_THUMBNAIL_SIZE (128 * scale_factor)
+ if (width > MAX_THUMBNAIL_SIZE || height > MAX_THUMBNAIL_SIZE)
+ {
+ /* Adjust the width/height ratio to a maximum size (relative to
+ * current display scale factor.
+ */
+ if (width > height)
+ {
+ height = MAX_THUMBNAIL_SIZE * height / width;
+ width = MAX_THUMBNAIL_SIZE;
+ }
+ else
+ {
+ width = MAX_THUMBNAIL_SIZE * width / height;
+ height = MAX_THUMBNAIL_SIZE;
+ }
+ }
+
+ gimp_pickable_flush (GIMP_PICKABLE (image));
+ pixbuf = gimp_viewable_get_pixbuf (GIMP_VIEWABLE (image), context,
+ width, height);
+ if (pixbuf)
+ {
+ GdkPixbuf *rotated;
+ GtkWidget *hbox;
+ GtkWidget *image;
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ label = gtk_label_new (_("Original"));
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
+ gimp_label_set_attributes (GTK_LABEL (label),
+ PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
+ -1);
+ gtk_box_pack_end (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ gtk_box_pack_end (GTK_BOX (vbox), image, FALSE, FALSE, 0);
+ gtk_widget_show (image);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ label = gtk_label_new (_("Rotated"));
+ gimp_label_set_attributes (GTK_LABEL (label),
+ PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
+ -1);
+ gtk_box_pack_end (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ rotated = gimp_image_metadata_rotate_pixbuf (pixbuf, orientation);
+
+ image = gtk_image_new_from_pixbuf (rotated);
+ g_object_unref (rotated);
+
+ gtk_box_pack_end (GTK_BOX (vbox), image, FALSE, FALSE, 0);
+ gtk_widget_show (image);
+ }
+
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", _("This image contains Exif orientation "
+ "metadata."),
+ "wrap", TRUE,
+ "justify", GTK_JUSTIFY_LEFT,
+ "xalign", 0.0,
+ "yalign", 0.5,
+ NULL);
+ gimp_label_set_attributes (GTK_LABEL (label),
+ PANGO_ATTR_SCALE, PANGO_SCALE_LARGE,
+ PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
+ -1);
+ gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", _("Would you like to rotate the image?"),
+ "wrap", TRUE,
+ "justify", GTK_JUSTIFY_LEFT,
+ "xalign", 0.0,
+ "yalign", 0.5,
+ NULL);
+ gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("_Don't ask me again"));
+ gtk_box_pack_end (GTK_BOX (main_vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE);
+ gtk_widget_show (toggle);
+
+ response = gimp_dialog_run (GIMP_DIALOG (dialog));
+ *dont_ask = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)));
+
+ gtk_widget_destroy (dialog);
+
+ return (response == GTK_RESPONSE_OK) ? GIMP_METADATA_ROTATION_POLICY_ROTATE :
GIMP_COLOR_PROFILE_POLICY_KEEP;
+}
+
+static GdkPixbuf *
+gimp_image_metadata_rotate_pixbuf (GdkPixbuf *pixbuf,
+ GExiv2Orientation orientation)
+{
+ GdkPixbuf *rotated = NULL;
+ GdkPixbuf *temp;
+
+ switch (orientation)
+ {
+ case GEXIV2_ORIENTATION_UNSPECIFIED:
+ case GEXIV2_ORIENTATION_NORMAL: /* standard orientation, do nothing */
+ rotated = g_object_ref (pixbuf);
+ break;
+
+ case GEXIV2_ORIENTATION_HFLIP:
+ rotated = gdk_pixbuf_flip (pixbuf, TRUE);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_180:
+ rotated = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
+ break;
+
+ case GEXIV2_ORIENTATION_VFLIP:
+ rotated = gdk_pixbuf_flip (pixbuf, FALSE);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_90_HFLIP: /* flipped diagonally around '\' */
+ temp = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
+ rotated = gdk_pixbuf_flip (temp, TRUE);
+ g_object_unref (temp);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_90: /* 90 CW */
+ rotated = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_90_VFLIP: /* flipped diagonally around '/' */
+ temp = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
+ rotated = gdk_pixbuf_flip (temp, FALSE);
+ g_object_unref (temp);
+ break;
+
+ case GEXIV2_ORIENTATION_ROT_270: /* 90 CCW */
+ rotated = gdk_pixbuf_rotate_simple (pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
+ break;
+
+ default: /* shouldn't happen */
+ break;
+ }
+
+ return rotated;
+}
diff --git a/app/dialogs/metadata-rotation-import-dialog.h b/app/dialogs/metadata-rotation-import-dialog.h
new file mode 100644
index 0000000000..9cb0210a46
--- /dev/null
+++ b/app/dialogs/metadata-rotation-import-dialog.h
@@ -0,0 +1,31 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * metadata-rotation-import-dialog.h
+ * Copyright (C) 2020 Jehan
+ *
+ * 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/>.
+ */
+
+#ifndef __METADATA_ROTATION_IMPORT_DIALOG_H__
+#define __METADATA_ROTATION_IMPORT_DIALOG_H__
+
+
+GimpMetadataRotationPolicy metadata_rotation_import_dialog_run (GimpImage *image,
+ GimpContext *context,
+ GtkWidget *parent,
+ gboolean *dont_ask);
+
+
+#endif /* __METADATA_ROTATION_IMPORT_DIALOG_H__*/
diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c
index f008a70d01..d26293e919 100644
--- a/app/dialogs/preferences-dialog.c
+++ b/app/dialogs/preferences-dialog.c
@@ -1518,6 +1518,9 @@ prefs_dialog_new (Gimp *gimp,
button = prefs_enum_combo_box_add (object, "color-profile-policy", 0, 0,
_("Color _profile policy:"),
GTK_GRID (grid), 0, size_group);
+ button = prefs_enum_combo_box_add (object, "metadata-rotation-policy", 0, 0,
+ _("Metadata _rotation policy:"),
+ GTK_GRID (grid), 1, size_group);
/* Export Policies */
vbox2 = prefs_frame_new (_("Export Policies"),
diff --git a/app/file/file-import.c b/app/file/file-import.c
index 137b9520ba..1db1f6d0bf 100644
--- a/app/file/file-import.c
+++ b/app/file/file-import.c
@@ -31,6 +31,7 @@
#include "core/gimpimage.h"
#include "core/gimpimage-color-profile.h"
#include "core/gimpimage-convert-precision.h"
+#include "core/gimpimage-rotate.h"
#include "core/gimplayer.h"
#include "core/gimpprogress.h"
@@ -100,6 +101,7 @@ file_import_image (GimpImage *image,
}
gimp_image_import_color_profile (image, context, progress, interactive);
+ gimp_image_import_rotation_metadata (image, context, progress, interactive);
/* Remember the import source */
gimp_image_set_imported_file (image, file);
diff --git a/app/gui/gui-vtable.c b/app/gui/gui-vtable.c
index b585a19c38..3545db3bdd 100644
--- a/app/gui/gui-vtable.c
+++ b/app/gui/gui-vtable.c
@@ -100,6 +100,7 @@
#include "menus/menus.h"
#include "dialogs/color-profile-import-dialog.h"
+#include "dialogs/metadata-rotation-import-dialog.h"
#include "gui.h"
#include "gui-message.h"
@@ -179,6 +180,11 @@ static GimpColorProfilePolicy
GimpColorRenderingIntent *intent,
gboolean *bpc,
gboolean *dont_ask);
+static GimpMetadataRotationPolicy
+ gui_query_rotation_policy (Gimp *gimp,
+ GimpImage *image,
+ GimpContext *context,
+ gboolean *dont_ask);
/* public functions */
@@ -214,6 +220,7 @@ gui_vtable_init (Gimp *gimp)
gimp->gui.recent_list_load = gui_recent_list_load;
gimp->gui.get_mount_operation = gui_get_mount_operation;
gimp->gui.query_profile_policy = gui_query_profile_policy;
+ gimp->gui.query_rotation_policy = gui_query_rotation_policy;
}
@@ -906,3 +913,13 @@ gui_query_profile_policy (Gimp *gimp,
intent, bpc,
dont_ask);
}
+
+static GimpMetadataRotationPolicy
+gui_query_rotation_policy (Gimp *gimp,
+ GimpImage *image,
+ GimpContext *context,
+ gboolean *dont_ask)
+{
+ return metadata_rotation_import_dialog_run (image, context,
+ NULL, dont_ask);
+}
diff --git a/libgimp/Makefile.gi b/libgimp/Makefile.gi
index 4ad1e3eefc..2cf4510561 100644
--- a/libgimp/Makefile.gi
+++ b/libgimp/Makefile.gi
@@ -183,7 +183,6 @@ libgimpui_introspectable_headers = \
../libgimp/gimpfontselectbutton.h \
../libgimp/gimpgradientselectbutton.h \
../libgimp/gimpimagecombobox.h \
- ../libgimp/gimpimagemetadata-interactive.h \
../libgimp/gimpitemcombobox.h \
../libgimp/gimppaletteselectbutton.h \
../libgimp/gimppatternselectbutton.h \
@@ -204,7 +203,6 @@ libgimpui_introspectable = \
../libgimp/gimpfontselectbutton.c \
../libgimp/gimpgradientselectbutton.c \
../libgimp/gimpimagecombobox.c \
- ../libgimp/gimpimagemetadata-interactive.c \
../libgimp/gimpitemcombobox.c \
../libgimp/gimppaletteselectbutton.c \
../libgimp/gimppatternselectbutton.c \
diff --git a/libgimp/gimpimagemetadata.c b/libgimp/gimpimagemetadata.c
index be19ad0898..5542c922c2 100644
--- a/libgimp/gimpimagemetadata.c
+++ b/libgimp/gimpimagemetadata.c
@@ -51,8 +51,7 @@ static void gimp_image_metadata_rotate (GimpImage *image,
* @error: Return location for error
*
* Loads and returns metadata from @file to be passed into
- * gimp_image_metadata_load_finish() or
- * gimp_image_metadata_load_finish_batch().
+ * gimp_image_metadata_load_finish().
*
* Returns: (transfer full): The file's metadata.
*
@@ -82,7 +81,7 @@ gimp_image_metadata_load_prepare (GimpImage *image,
}
/**
- * gimp_image_metadata_load_finish_batch:
+ * gimp_image_metadata_load_finish:
* @image: The image
* @mime_type: The loaded file's mime-type
* @metadata: The metadata to set on the image
@@ -92,24 +91,13 @@ gimp_image_metadata_load_prepare (GimpImage *image,
* gimp_image_metadata_load_prepare() to the image, taking into account
* the passed @flags.
*
- * Some metadata may involve some image changes and are better asked for
- * confirmation. For instance the orientation metadata may be wrong at
- * times (because it depends usually on camera sensors and the rotated
- * image may not be what one expects). If the related flag is set (i.e.
- * GIMP_METADATA_LOAD_ORIENTATION for orientation), then the change will
- * be automatically executed (i.e. the image will be rotated) without
- * any human interaction.
- *
- * If you wish such edit to be queried interactively with dialogs, use
- * gimp_image_metadata_load_finish() instead, from libgimpui.
- *
* Since: 3.0
*/
void
-gimp_image_metadata_load_finish_batch (GimpImage *image,
- const gchar *mime_type,
- GimpMetadata *metadata,
- GimpMetadataLoadFlags flags)
+gimp_image_metadata_load_finish (GimpImage *image,
+ const gchar *mime_type,
+ GimpMetadata *metadata,
+ GimpMetadataLoadFlags flags)
{
g_return_if_fail (GIMP_IS_IMAGE (image));
g_return_if_fail (mime_type != NULL);
@@ -153,13 +141,10 @@ gimp_image_metadata_load_finish_batch (GimpImage *image,
}
}
- if (flags & GIMP_METADATA_LOAD_ORIENTATION)
+ if (! (flags & GIMP_METADATA_LOAD_ORIENTATION))
{
- gimp_image_metadata_rotate (image,
- gexiv2_metadata_get_orientation (GEXIV2_METADATA (metadata)));
-
gexiv2_metadata_set_orientation (GEXIV2_METADATA (metadata),
- GEXIV2_ORIENTATION_NORMAL);
+ GEXIV2_ORIENTATION_UNSPECIFIED);
}
if (flags & GIMP_METADATA_LOAD_COLORSPACE)
diff --git a/libgimp/gimpimagemetadata.h b/libgimp/gimpimagemetadata.h
index 8aac8f372b..1f7c5970da 100644
--- a/libgimp/gimpimagemetadata.h
+++ b/libgimp/gimpimagemetadata.h
@@ -35,10 +35,10 @@ GimpMetadata * gimp_image_metadata_load_prepare (GimpImage *image,
const gchar *mime_type,
GFile *file,
GError **error);
-void gimp_image_metadata_load_finish_batch (GimpImage *image,
- const gchar *mime_type,
- GimpMetadata *metadata,
- GimpMetadataLoadFlags flags);
+void gimp_image_metadata_load_finish (GimpImage *image,
+ const gchar *mime_type,
+ GimpMetadata *metadata,
+ GimpMetadataLoadFlags flags);
GimpMetadata * gimp_image_metadata_save_prepare (GimpImage *image,
const gchar *mime_type,
diff --git a/libgimp/gimpui.h b/libgimp/gimpui.h
index a4ac9e53aa..ab53ca5f26 100644
--- a/libgimp/gimpui.h
+++ b/libgimp/gimpui.h
@@ -36,7 +36,6 @@
#include <libgimp/gimpfontselectbutton.h>
#include <libgimp/gimpgradientselectbutton.h>
#include <libgimp/gimpimagecombobox.h>
-#include <libgimp/gimpimagemetadata-interactive.h>
#include <libgimp/gimpitemcombobox.h>
#include <libgimp/gimppaletteselectbutton.h>
#include <libgimp/gimppatternselectbutton.h>
diff --git a/libgimp/meson.build b/libgimp/meson.build
index 3245c44ba1..cc8fd319d8 100644
--- a/libgimp/meson.build
+++ b/libgimp/meson.build
@@ -235,7 +235,6 @@ libgimpui_sources_introspectable = [
'gimpfontselectbutton.c',
'gimpgradientselectbutton.c',
'gimpimagecombobox.c',
- 'gimpimagemetadata-interactive.c',
'gimpitemcombobox.c',
'gimppaletteselectbutton.c',
'gimppatternselectbutton.c',
@@ -266,7 +265,6 @@ libgimpui_headers_introspectable = [
'gimpfontselectbutton.h',
'gimpgradientselectbutton.h',
'gimpimagecombobox.h',
- 'gimpimagemetadata-interactive.h',
'gimpitemcombobox.h',
'gimppaletteselectbutton.h',
'gimppatternselectbutton.h',
diff --git a/plug-ins/common/file-heif.c b/plug-ins/common/file-heif.c
index 47fe1c4489..f27350ff49 100644
--- a/plug-ins/common/file-heif.c
+++ b/plug-ins/common/file-heif.c
@@ -1252,8 +1252,7 @@ load_image (GFile *file,
}
gimp_image_metadata_load_finish (image, "image/heif",
- metadata, flags,
- interactive);
+ metadata, flags);
}
}
diff --git a/plug-ins/common/file-jp2-load.c b/plug-ins/common/file-jp2-load.c
index ae30330637..1a7ce38e6a 100644
--- a/plug-ins/common/file-jp2-load.c
+++ b/plug-ins/common/file-jp2-load.c
@@ -333,8 +333,7 @@ jp2_load (GimpProcedure *procedure,
flags &= ~GIMP_METADATA_LOAD_COLORSPACE;
gimp_image_metadata_load_finish (image, "image/jp2",
- metadata, flags,
- interactive);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/plug-ins/common/file-png.c b/plug-ins/common/file-png.c
index 1de09a6ad8..0138d0fe97 100644
--- a/plug-ins/common/file-png.c
+++ b/plug-ins/common/file-png.c
@@ -382,8 +382,7 @@ png_load (GimpProcedure *procedure,
flags &= ~GIMP_METADATA_LOAD_COLORSPACE;
gimp_image_metadata_load_finish (image, "image/png",
- metadata, flags,
- interactive);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/plug-ins/file-exr/file-exr.c b/plug-ins/file-exr/file-exr.c
index faf5cc8c95..1bfe737486 100644
--- a/plug-ins/file-exr/file-exr.c
+++ b/plug-ins/file-exr/file-exr.c
@@ -358,7 +358,7 @@ load_image (GFile *file,
flags &= ~GIMP_METADATA_LOAD_COLORSPACE;
gimp_image_metadata_load_finish (image, "image/exr",
- metadata, flags, interactive);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/plug-ins/file-jpeg/jpeg.c b/plug-ins/file-jpeg/jpeg.c
index e74216e1df..8c5ec16b9f 100644
--- a/plug-ins/file-jpeg/jpeg.c
+++ b/plug-ins/file-jpeg/jpeg.c
@@ -274,7 +274,6 @@ jpeg_load (GimpProcedure *procedure,
{
GimpValueArray *return_vals;
GimpImage *image;
- gboolean interactive;
gboolean resolution_loaded = FALSE;
GError *error = NULL;
@@ -289,11 +288,9 @@ jpeg_load (GimpProcedure *procedure,
case GIMP_RUN_INTERACTIVE:
case GIMP_RUN_WITH_LAST_VALS:
gimp_ui_init (PLUG_IN_BINARY);
- interactive = TRUE;
break;
default:
- interactive = FALSE;
break;
}
@@ -315,8 +312,7 @@ jpeg_load (GimpProcedure *procedure,
flags &= ~GIMP_METADATA_LOAD_RESOLUTION;
gimp_image_metadata_load_finish (image, "image/jpeg",
- metadata, flags,
- interactive);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/plug-ins/file-psd/psd.c b/plug-ins/file-psd/psd.c
index 3fcbaa808d..a1e59670af 100644
--- a/plug-ins/file-psd/psd.c
+++ b/plug-ins/file-psd/psd.c
@@ -236,7 +236,6 @@ psd_load (GimpProcedure *procedure,
GimpValueArray *return_vals;
gboolean resolution_loaded = FALSE;
gboolean profile_loaded = FALSE;
- gboolean interactive;
GimpImage *image;
GimpMetadata *metadata;
GError *error = NULL;
@@ -249,10 +248,8 @@ psd_load (GimpProcedure *procedure,
case GIMP_RUN_INTERACTIVE:
case GIMP_RUN_WITH_LAST_VALS:
gimp_ui_init (PLUG_IN_BINARY);
- interactive = TRUE;
break;
default:
- interactive = FALSE;
break;
}
@@ -281,8 +278,7 @@ psd_load (GimpProcedure *procedure,
flags &= ~GIMP_METADATA_LOAD_COLORSPACE;
gimp_image_metadata_load_finish (image, "image/x-psd",
- metadata, flags,
- interactive);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/plug-ins/file-tiff/file-tiff.c b/plug-ins/file-tiff/file-tiff.c
index 53d59d3aea..9b9c6bbf15 100644
--- a/plug-ins/file-tiff/file-tiff.c
+++ b/plug-ins/file-tiff/file-tiff.c
@@ -307,8 +307,7 @@ tiff_load (GimpProcedure *procedure,
flags &= ~GIMP_METADATA_LOAD_COLORSPACE;
gimp_image_metadata_load_finish (image, "image/tiff",
- metadata, flags,
- run_mode == GIMP_RUN_INTERACTIVE);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/plug-ins/file-webp/file-webp-load.c b/plug-ins/file-webp/file-webp-load.c
index f27066cf63..d66e9dfb55 100644
--- a/plug-ins/file-webp/file-webp-load.c
+++ b/plug-ins/file-webp/file-webp-load.c
@@ -285,8 +285,7 @@ load_image (GFile *file,
flags &= ~GIMP_METADATA_LOAD_COLORSPACE;
gimp_image_metadata_load_finish (image, "image/webp",
- metadata, flags,
- interactive);
+ metadata, flags);
g_object_unref (metadata);
}
diff --git a/po-libgimp/POTFILES.in b/po-libgimp/POTFILES.in
index a5b8c11f4c..f091b3e181 100644
--- a/po-libgimp/POTFILES.in
+++ b/po-libgimp/POTFILES.in
@@ -9,7 +9,6 @@ libgimp/gimpexport.c
libgimp/gimpfontselectbutton.c
libgimp/gimpgradientselectbutton.c
libgimp/gimpimagemetadata.c
-libgimp/gimpimagemetadata-interactive.c
libgimp/gimpimagemetadata-save.c
libgimp/gimppaletteselectbutton.c
libgimp/gimppatternselectbutton.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]