mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-04 17:59:37 +00:00
Completely rewrite metadata handling using gexiv2
Based on original patches from Hartmut Kuhse and modified by Michael Natterer. Changes include: - remove libexif dependency and add a hard dependency on gexiv2 - typedef GExiv2Metadata to GimpMetadata to avoid having to include gexiv2 globally - add basic GimpMetadata handling functions to libgimpbase - add image and image file specific metadata functions to libgimp, including the exif orientation image rotate dialog - port plug-ins to use the new APIs - port file-tiff-save's UI to GtkBuilder - add new plug-in "metadata" to view the image's metadata - keep metadata around as GimpImage member in the core - update the image's metadata on image size, resolution and precision changes - obsolete the old metadata parasites - migrate the old parasites to new GimpMetadata object on XCF load
This commit is contained in:
parent
c51ce66f1b
commit
21bed1e2fb
68 changed files with 4810 additions and 1572 deletions
|
@ -177,6 +177,7 @@ gimpconsoleldadd = \
|
||||||
$(CAIRO_LIBS) \
|
$(CAIRO_LIBS) \
|
||||||
$(GEGL_LIBS) \
|
$(GEGL_LIBS) \
|
||||||
$(GLIB_LIBS) \
|
$(GLIB_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
$(INTLLIBS) \
|
$(INTLLIBS) \
|
||||||
$(RT_LIBS)
|
$(RT_LIBS)
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,8 @@ test_config_LDADD = \
|
||||||
$(PANGOCAIRO_LIBS) \
|
$(PANGOCAIRO_LIBS) \
|
||||||
$(GDK_PIXBUF_LIBS) \
|
$(GDK_PIXBUF_LIBS) \
|
||||||
$(GEGL_LIBS) \
|
$(GEGL_LIBS) \
|
||||||
$(GLIB_LIBS)
|
$(GIO_LIBS) \
|
||||||
|
$(GEXIV2_LIBS)
|
||||||
|
|
||||||
CLEANFILES = $(EXTRA_PROGRAMS) foorc
|
CLEANFILES = $(EXTRA_PROGRAMS) foorc
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include "libgimpbase/gimpbase.h"
|
#include "libgimpbase/gimpbase.h"
|
||||||
#include "libgimpbase/gimpbase-private.h"
|
#include "libgimpbase/gimpbase-private.h"
|
||||||
|
|
|
@ -10,6 +10,7 @@ AM_CPPFLAGS = \
|
||||||
$(CAIRO_CFLAGS) \
|
$(CAIRO_CFLAGS) \
|
||||||
$(GEGL_CFLAGS) \
|
$(GEGL_CFLAGS) \
|
||||||
$(GDK_PIXBUF_CFLAGS) \
|
$(GDK_PIXBUF_CFLAGS) \
|
||||||
|
$(GEXIV2_CFLAGS) \
|
||||||
-I$(includedir)
|
-I$(includedir)
|
||||||
|
|
||||||
noinst_LIBRARIES = libappcore.a
|
noinst_LIBRARIES = libappcore.a
|
||||||
|
@ -219,6 +220,8 @@ libappcore_a_sources = \
|
||||||
gimpimage-item-list.h \
|
gimpimage-item-list.h \
|
||||||
gimpimage-merge.c \
|
gimpimage-merge.c \
|
||||||
gimpimage-merge.h \
|
gimpimage-merge.h \
|
||||||
|
gimpimage-metadata.c \
|
||||||
|
gimpimage-metadata.h \
|
||||||
gimpimage-new.c \
|
gimpimage-new.c \
|
||||||
gimpimage-new.h \
|
gimpimage-new.h \
|
||||||
gimpimage-pick-color.c \
|
gimpimage-pick-color.c \
|
||||||
|
|
|
@ -1115,6 +1115,7 @@ gimp_undo_type_get_type (void)
|
||||||
{ GIMP_UNDO_IMAGE_SIZE, "GIMP_UNDO_IMAGE_SIZE", "image-size" },
|
{ GIMP_UNDO_IMAGE_SIZE, "GIMP_UNDO_IMAGE_SIZE", "image-size" },
|
||||||
{ GIMP_UNDO_IMAGE_RESOLUTION, "GIMP_UNDO_IMAGE_RESOLUTION", "image-resolution" },
|
{ GIMP_UNDO_IMAGE_RESOLUTION, "GIMP_UNDO_IMAGE_RESOLUTION", "image-resolution" },
|
||||||
{ GIMP_UNDO_IMAGE_GRID, "GIMP_UNDO_IMAGE_GRID", "image-grid" },
|
{ GIMP_UNDO_IMAGE_GRID, "GIMP_UNDO_IMAGE_GRID", "image-grid" },
|
||||||
|
{ GIMP_UNDO_IMAGE_METADATA, "GIMP_UNDO_IMAGE_METADATA", "image-metadata" },
|
||||||
{ GIMP_UNDO_IMAGE_COLORMAP, "GIMP_UNDO_IMAGE_COLORMAP", "image-colormap" },
|
{ GIMP_UNDO_IMAGE_COLORMAP, "GIMP_UNDO_IMAGE_COLORMAP", "image-colormap" },
|
||||||
{ GIMP_UNDO_GUIDE, "GIMP_UNDO_GUIDE", "guide" },
|
{ GIMP_UNDO_GUIDE, "GIMP_UNDO_GUIDE", "guide" },
|
||||||
{ GIMP_UNDO_SAMPLE_POINT, "GIMP_UNDO_SAMPLE_POINT", "sample-point" },
|
{ GIMP_UNDO_SAMPLE_POINT, "GIMP_UNDO_SAMPLE_POINT", "sample-point" },
|
||||||
|
@ -1205,6 +1206,7 @@ gimp_undo_type_get_type (void)
|
||||||
{ GIMP_UNDO_IMAGE_SIZE, NC_("undo-type", "Image size"), NULL },
|
{ GIMP_UNDO_IMAGE_SIZE, NC_("undo-type", "Image size"), NULL },
|
||||||
{ GIMP_UNDO_IMAGE_RESOLUTION, NC_("undo-type", "Image resolution change"), NULL },
|
{ GIMP_UNDO_IMAGE_RESOLUTION, NC_("undo-type", "Image resolution change"), NULL },
|
||||||
{ GIMP_UNDO_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
|
{ GIMP_UNDO_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
|
||||||
|
{ GIMP_UNDO_IMAGE_METADATA, NC_("undo-type", "Change metadata"), NULL },
|
||||||
{ GIMP_UNDO_IMAGE_COLORMAP, NC_("undo-type", "Change indexed palette"), NULL },
|
{ GIMP_UNDO_IMAGE_COLORMAP, NC_("undo-type", "Change indexed palette"), NULL },
|
||||||
{ GIMP_UNDO_GUIDE, NC_("undo-type", "Guide"), NULL },
|
{ GIMP_UNDO_GUIDE, NC_("undo-type", "Guide"), NULL },
|
||||||
{ GIMP_UNDO_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
|
{ GIMP_UNDO_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
|
||||||
|
|
|
@ -530,6 +530,7 @@ typedef enum /*< pdb-skip >*/
|
||||||
GIMP_UNDO_IMAGE_SIZE, /*< desc="Image size" >*/
|
GIMP_UNDO_IMAGE_SIZE, /*< desc="Image size" >*/
|
||||||
GIMP_UNDO_IMAGE_RESOLUTION, /*< desc="Image resolution change" >*/
|
GIMP_UNDO_IMAGE_RESOLUTION, /*< desc="Image resolution change" >*/
|
||||||
GIMP_UNDO_IMAGE_GRID, /*< desc="Grid" >*/
|
GIMP_UNDO_IMAGE_GRID, /*< desc="Grid" >*/
|
||||||
|
GIMP_UNDO_IMAGE_METADATA, /*< desc="Change metadata" >*/
|
||||||
GIMP_UNDO_IMAGE_COLORMAP, /*< desc="Change indexed palette" >*/
|
GIMP_UNDO_IMAGE_COLORMAP, /*< desc="Change indexed palette" >*/
|
||||||
GIMP_UNDO_GUIDE, /*< desc="Guide" >*/
|
GIMP_UNDO_GUIDE, /*< desc="Guide" >*/
|
||||||
GIMP_UNDO_SAMPLE_POINT, /*< desc="Sample Point" >*/
|
GIMP_UNDO_SAMPLE_POINT, /*< desc="Sample Point" >*/
|
||||||
|
|
103
app/core/gimpimage-metadata.c
Normal file
103
app/core/gimpimage-metadata.c
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <gegl.h>
|
||||||
|
|
||||||
|
#include "libgimpbase/gimpbase.h"
|
||||||
|
|
||||||
|
#include "core-types.h"
|
||||||
|
|
||||||
|
#include "gimpimage.h"
|
||||||
|
#include "gimpimage-metadata.h"
|
||||||
|
#include "gimpimage-private.h"
|
||||||
|
#include "gimpimage-undo-push.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
|
||||||
|
|
||||||
|
GimpMetadata *
|
||||||
|
gimp_image_get_metadata (GimpImage *image)
|
||||||
|
{
|
||||||
|
GimpImagePrivate *private;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||||
|
|
||||||
|
private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||||
|
|
||||||
|
return private->metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_image_set_metadata (GimpImage *image,
|
||||||
|
GimpMetadata *metadata,
|
||||||
|
gboolean push_undo)
|
||||||
|
{
|
||||||
|
GimpImagePrivate *private;
|
||||||
|
|
||||||
|
g_return_if_fail (GIMP_IS_IMAGE (image));
|
||||||
|
|
||||||
|
private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||||
|
|
||||||
|
if (metadata != private->metadata)
|
||||||
|
{
|
||||||
|
if (push_undo)
|
||||||
|
gimp_image_undo_push_image_metadata (image, NULL);
|
||||||
|
|
||||||
|
if (private->metadata)
|
||||||
|
g_object_unref (private->metadata);
|
||||||
|
|
||||||
|
private->metadata = metadata;
|
||||||
|
|
||||||
|
if (private->metadata)
|
||||||
|
{
|
||||||
|
gdouble xres, yres;
|
||||||
|
|
||||||
|
g_object_ref (private->metadata);
|
||||||
|
|
||||||
|
gimp_metadata_set_pixel_size (metadata,
|
||||||
|
gimp_image_get_width (image),
|
||||||
|
gimp_image_get_height (image));
|
||||||
|
|
||||||
|
switch (gimp_image_get_component_type (image))
|
||||||
|
{
|
||||||
|
case GIMP_COMPONENT_TYPE_U8:
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIMP_COMPONENT_TYPE_U16:
|
||||||
|
case GIMP_COMPONENT_TYPE_HALF:
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIMP_COMPONENT_TYPE_U32:
|
||||||
|
case GIMP_COMPONENT_TYPE_FLOAT:
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 32);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_image_get_resolution (image, &xres, &yres);
|
||||||
|
gimp_metadata_set_resolution (metadata, xres, yres,
|
||||||
|
gimp_image_get_unit (image));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (image), "metadata");
|
||||||
|
}
|
||||||
|
}
|
28
app/core/gimpimage-metadata.h
Normal file
28
app/core/gimpimage-metadata.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GIMP_IMAGE_METADATA_H__
|
||||||
|
#define __GIMP_IMAGE_METADATA_H__
|
||||||
|
|
||||||
|
|
||||||
|
GimpMetadata * gimp_image_get_metadata (GimpImage *image);
|
||||||
|
void gimp_image_set_metadata (GimpImage *image,
|
||||||
|
GimpMetadata *metadata,
|
||||||
|
gboolean push_undo);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __GIMP_IMAGE_METADATA_H__ */
|
|
@ -55,6 +55,8 @@ struct _GimpImagePrivate
|
||||||
const Babl *babl_palette_rgb; /* palette's RGB Babl format */
|
const Babl *babl_palette_rgb; /* palette's RGB Babl format */
|
||||||
const Babl *babl_palette_rgba; /* palette's RGBA Babl format */
|
const Babl *babl_palette_rgba; /* palette's RGBA Babl format */
|
||||||
|
|
||||||
|
GimpMetadata *metadata; /* image's metadata */
|
||||||
|
|
||||||
gint dirty; /* dirty flag -- # of ops */
|
gint dirty; /* dirty flag -- # of ops */
|
||||||
guint dirty_time; /* time when image became dirty */
|
guint dirty_time; /* time when image became dirty */
|
||||||
gint export_dirty; /* 'dirty' but for export */
|
gint export_dirty; /* 'dirty' but for export */
|
||||||
|
|
|
@ -148,6 +148,18 @@ gimp_image_undo_push_image_colormap (GimpImage *image,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GimpUndo *
|
||||||
|
gimp_image_undo_push_image_metadata (GimpImage *image,
|
||||||
|
const gchar *undo_desc)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||||
|
|
||||||
|
return gimp_image_undo_push (image, GIMP_TYPE_IMAGE_UNDO,
|
||||||
|
GIMP_UNDO_IMAGE_METADATA, undo_desc,
|
||||||
|
GIMP_DIRTY_IMAGE_META,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
GimpUndo *
|
GimpUndo *
|
||||||
gimp_image_undo_push_image_parasite (GimpImage *image,
|
gimp_image_undo_push_image_parasite (GimpImage *image,
|
||||||
const gchar *undo_desc,
|
const gchar *undo_desc,
|
||||||
|
|
|
@ -38,6 +38,8 @@ GimpUndo * gimp_image_undo_push_image_grid (GimpImage *image,
|
||||||
GimpGrid *grid);
|
GimpGrid *grid);
|
||||||
GimpUndo * gimp_image_undo_push_image_colormap (GimpImage *image,
|
GimpUndo * gimp_image_undo_push_image_colormap (GimpImage *image,
|
||||||
const gchar *undo_desc);
|
const gchar *undo_desc);
|
||||||
|
GimpUndo * gimp_image_undo_push_image_metadata (GimpImage *image,
|
||||||
|
const gchar *undo_desc);
|
||||||
GimpUndo * gimp_image_undo_push_image_parasite (GimpImage *image,
|
GimpUndo * gimp_image_undo_push_image_parasite (GimpImage *image,
|
||||||
const gchar *undo_desc,
|
const gchar *undo_desc,
|
||||||
const GimpParasite *parasite);
|
const GimpParasite *parasite);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
#include <gegl.h>
|
#include <gegl.h>
|
||||||
|
#include <gexiv2/gexiv2.h>
|
||||||
|
|
||||||
#include "libgimpcolor/gimpcolor.h"
|
#include "libgimpcolor/gimpcolor.h"
|
||||||
#include "libgimpmath/gimpmath.h"
|
#include "libgimpmath/gimpmath.h"
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
#include "gimpimage.h"
|
#include "gimpimage.h"
|
||||||
#include "gimpimage-colormap.h"
|
#include "gimpimage-colormap.h"
|
||||||
#include "gimpimage-guides.h"
|
#include "gimpimage-guides.h"
|
||||||
|
#include "gimpimage-metadata.h"
|
||||||
#include "gimpimage-sample-points.h"
|
#include "gimpimage-sample-points.h"
|
||||||
#include "gimpimage-preview.h"
|
#include "gimpimage-preview.h"
|
||||||
#include "gimpimage-private.h"
|
#include "gimpimage-private.h"
|
||||||
|
@ -130,6 +132,7 @@ enum
|
||||||
PROP_HEIGHT,
|
PROP_HEIGHT,
|
||||||
PROP_BASE_TYPE,
|
PROP_BASE_TYPE,
|
||||||
PROP_PRECISION,
|
PROP_PRECISION,
|
||||||
|
PROP_METADATA,
|
||||||
PROP_BUFFER
|
PROP_BUFFER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,12 +168,14 @@ static gchar * gimp_image_get_description (GimpViewable *viewable,
|
||||||
|
|
||||||
static void gimp_image_real_mode_changed (GimpImage *image);
|
static void gimp_image_real_mode_changed (GimpImage *image);
|
||||||
static void gimp_image_real_precision_changed(GimpImage *image);
|
static void gimp_image_real_precision_changed(GimpImage *image);
|
||||||
|
static void gimp_image_real_resolution_changed(GimpImage *image);
|
||||||
static void gimp_image_real_size_changed_detailed
|
static void gimp_image_real_size_changed_detailed
|
||||||
(GimpImage *image,
|
(GimpImage *image,
|
||||||
gint previous_origin_x,
|
gint previous_origin_x,
|
||||||
gint previous_origin_y,
|
gint previous_origin_y,
|
||||||
gint previous_width,
|
gint previous_width,
|
||||||
gint previous_height);
|
gint previous_height);
|
||||||
|
static void gimp_image_real_unit_changed (GimpImage *image);
|
||||||
static void gimp_image_real_colormap_changed (GimpImage *image,
|
static void gimp_image_real_colormap_changed (GimpImage *image,
|
||||||
gint color_index);
|
gint color_index);
|
||||||
|
|
||||||
|
@ -552,9 +557,9 @@ gimp_image_class_init (GimpImageClass *klass)
|
||||||
klass->component_visibility_changed = NULL;
|
klass->component_visibility_changed = NULL;
|
||||||
klass->component_active_changed = NULL;
|
klass->component_active_changed = NULL;
|
||||||
klass->mask_changed = NULL;
|
klass->mask_changed = NULL;
|
||||||
klass->resolution_changed = NULL;
|
klass->resolution_changed = gimp_image_real_resolution_changed;
|
||||||
klass->size_changed_detailed = gimp_image_real_size_changed_detailed;
|
klass->size_changed_detailed = gimp_image_real_size_changed_detailed;
|
||||||
klass->unit_changed = NULL;
|
klass->unit_changed = gimp_image_real_unit_changed;
|
||||||
klass->quick_mask_changed = NULL;
|
klass->quick_mask_changed = NULL;
|
||||||
klass->selection_invalidate = NULL;
|
klass->selection_invalidate = NULL;
|
||||||
|
|
||||||
|
@ -610,6 +615,11 @@ gimp_image_class_init (GimpImageClass *klass)
|
||||||
GIMP_PARAM_READWRITE |
|
GIMP_PARAM_READWRITE |
|
||||||
G_PARAM_CONSTRUCT));
|
G_PARAM_CONSTRUCT));
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_METADATA,
|
||||||
|
g_param_spec_object ("metadata", NULL, NULL,
|
||||||
|
GEXIV2_TYPE_METADATA,
|
||||||
|
GIMP_PARAM_READABLE));
|
||||||
|
|
||||||
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
|
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (GimpImagePrivate));
|
g_type_class_add_private (klass, sizeof (GimpImagePrivate));
|
||||||
|
@ -667,6 +677,8 @@ gimp_image_init (GimpImage *image)
|
||||||
private->n_colors = 0;
|
private->n_colors = 0;
|
||||||
private->palette = NULL;
|
private->palette = NULL;
|
||||||
|
|
||||||
|
private->metadata = NULL;
|
||||||
|
|
||||||
private->dirty = 1;
|
private->dirty = 1;
|
||||||
private->dirty_time = 0;
|
private->dirty_time = 0;
|
||||||
private->undo_freeze_count = 0;
|
private->undo_freeze_count = 0;
|
||||||
|
@ -837,6 +849,7 @@ gimp_image_set_property (GObject *object,
|
||||||
case PROP_PRECISION:
|
case PROP_PRECISION:
|
||||||
private->precision = g_value_get_enum (value);
|
private->precision = g_value_get_enum (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_METADATA:
|
||||||
case PROP_BUFFER:
|
case PROP_BUFFER:
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
@ -873,6 +886,9 @@ gimp_image_get_property (GObject *object,
|
||||||
case PROP_PRECISION:
|
case PROP_PRECISION:
|
||||||
g_value_set_enum (value, private->precision);
|
g_value_set_enum (value, private->precision);
|
||||||
break;
|
break;
|
||||||
|
case PROP_METADATA:
|
||||||
|
g_value_set_object (value, gimp_image_get_metadata (image));
|
||||||
|
break;
|
||||||
case PROP_BUFFER:
|
case PROP_BUFFER:
|
||||||
g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image)));
|
g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image)));
|
||||||
break;
|
break;
|
||||||
|
@ -948,6 +964,12 @@ gimp_image_finalize (GObject *object)
|
||||||
if (private->colormap)
|
if (private->colormap)
|
||||||
gimp_image_colormap_free (image);
|
gimp_image_colormap_free (image);
|
||||||
|
|
||||||
|
if (private->metadata)
|
||||||
|
{
|
||||||
|
g_object_unref (private->metadata);
|
||||||
|
private->metadata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (private->layers)
|
if (private->layers)
|
||||||
{
|
{
|
||||||
g_object_unref (private->layers);
|
g_object_unref (private->layers);
|
||||||
|
@ -1128,9 +1150,10 @@ gimp_image_get_size (GimpViewable *viewable,
|
||||||
static void
|
static void
|
||||||
gimp_image_size_changed (GimpViewable *viewable)
|
gimp_image_size_changed (GimpViewable *viewable)
|
||||||
{
|
{
|
||||||
GimpImage *image = GIMP_IMAGE (viewable);
|
GimpImage *image = GIMP_IMAGE (viewable);
|
||||||
GList *all_items;
|
GimpMetadata *metadata;
|
||||||
GList *list;
|
GList *all_items;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed)
|
if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed)
|
||||||
GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable);
|
GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable);
|
||||||
|
@ -1155,6 +1178,12 @@ gimp_image_size_changed (GimpViewable *viewable)
|
||||||
|
|
||||||
gimp_viewable_size_changed (GIMP_VIEWABLE (gimp_image_get_mask (image)));
|
gimp_viewable_size_changed (GIMP_VIEWABLE (gimp_image_get_mask (image)));
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (image);
|
||||||
|
if (metadata)
|
||||||
|
gimp_metadata_set_pixel_size (metadata,
|
||||||
|
gimp_image_get_width (image),
|
||||||
|
gimp_image_get_height (image));
|
||||||
|
|
||||||
gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
|
gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,9 +1210,48 @@ gimp_image_real_mode_changed (GimpImage *image)
|
||||||
static void
|
static void
|
||||||
gimp_image_real_precision_changed (GimpImage *image)
|
gimp_image_real_precision_changed (GimpImage *image)
|
||||||
{
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (image);
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
switch (gimp_image_get_component_type (image))
|
||||||
|
{
|
||||||
|
case GIMP_COMPONENT_TYPE_U8:
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIMP_COMPONENT_TYPE_U16:
|
||||||
|
case GIMP_COMPONENT_TYPE_HALF:
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIMP_COMPONENT_TYPE_U32:
|
||||||
|
case GIMP_COMPONENT_TYPE_FLOAT:
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 32);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
|
gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_image_real_resolution_changed (GimpImage *image)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (image);
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
gdouble xres, yres;
|
||||||
|
|
||||||
|
gimp_image_get_resolution (image, &xres, &yres);
|
||||||
|
gimp_metadata_set_resolution (metadata, xres, yres,
|
||||||
|
gimp_image_get_unit (image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gimp_image_real_size_changed_detailed (GimpImage *image,
|
gimp_image_real_size_changed_detailed (GimpImage *image,
|
||||||
gint previous_origin_x,
|
gint previous_origin_x,
|
||||||
|
@ -1198,6 +1266,22 @@ gimp_image_real_size_changed_detailed (GimpImage *image,
|
||||||
gimp_viewable_size_changed (GIMP_VIEWABLE (image));
|
gimp_viewable_size_changed (GIMP_VIEWABLE (image));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_image_real_unit_changed (GimpImage *image)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (image);
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
gdouble xres, yres;
|
||||||
|
|
||||||
|
gimp_image_get_resolution (image, &xres, &yres);
|
||||||
|
gimp_metadata_set_resolution (metadata, xres, yres,
|
||||||
|
gimp_image_get_unit (image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gimp_image_real_colormap_changed (GimpImage *image,
|
gimp_image_real_colormap_changed (GimpImage *image,
|
||||||
gint color_index)
|
gint color_index)
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "gimpimage.h"
|
#include "gimpimage.h"
|
||||||
#include "gimpimage-colormap.h"
|
#include "gimpimage-colormap.h"
|
||||||
#include "gimpimage-grid.h"
|
#include "gimpimage-grid.h"
|
||||||
|
#include "gimpimage-metadata.h"
|
||||||
#include "gimpimage-private.h"
|
#include "gimpimage-private.h"
|
||||||
#include "gimpimageundo.h"
|
#include "gimpimageundo.h"
|
||||||
#include "gimpparasitelist.h"
|
#include "gimpparasitelist.h"
|
||||||
|
@ -186,6 +187,11 @@ gimp_image_undo_constructed (GObject *object)
|
||||||
GIMP_IMAGE_COLORMAP_SIZE);
|
GIMP_IMAGE_COLORMAP_SIZE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GIMP_UNDO_IMAGE_METADATA:
|
||||||
|
image_undo->metadata =
|
||||||
|
gimp_metadata_duplicate (gimp_image_get_metadata (image));
|
||||||
|
break;
|
||||||
|
|
||||||
case GIMP_UNDO_PARASITE_ATTACH:
|
case GIMP_UNDO_PARASITE_ATTACH:
|
||||||
case GIMP_UNDO_PARASITE_REMOVE:
|
case GIMP_UNDO_PARASITE_REMOVE:
|
||||||
g_assert (image_undo->parasite_name != NULL);
|
g_assert (image_undo->parasite_name != NULL);
|
||||||
|
@ -284,6 +290,9 @@ gimp_image_undo_get_memsize (GimpObject *object,
|
||||||
if (image_undo->colormap)
|
if (image_undo->colormap)
|
||||||
memsize += GIMP_IMAGE_COLORMAP_SIZE;
|
memsize += GIMP_IMAGE_COLORMAP_SIZE;
|
||||||
|
|
||||||
|
if (image_undo->metadata)
|
||||||
|
memsize += gimp_g_object_get_memsize (G_OBJECT (image_undo->metadata));
|
||||||
|
|
||||||
memsize += gimp_object_get_memsize (GIMP_OBJECT (image_undo->grid),
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (image_undo->grid),
|
||||||
gui_size);
|
gui_size);
|
||||||
memsize += gimp_string_get_memsize (image_undo->parasite_name);
|
memsize += gimp_string_get_memsize (image_undo->parasite_name);
|
||||||
|
@ -447,6 +456,20 @@ gimp_image_undo_pop (GimpUndo *undo,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GIMP_UNDO_IMAGE_METADATA:
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_metadata_duplicate (gimp_image_get_metadata (image));
|
||||||
|
|
||||||
|
gimp_image_set_metadata (image, image_undo->metadata, FALSE);
|
||||||
|
|
||||||
|
if (image_undo->metadata)
|
||||||
|
g_object_unref (image_undo->metadata);
|
||||||
|
image_undo->metadata = metadata;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case GIMP_UNDO_PARASITE_ATTACH:
|
case GIMP_UNDO_PARASITE_ATTACH:
|
||||||
case GIMP_UNDO_PARASITE_REMOVE:
|
case GIMP_UNDO_PARASITE_REMOVE:
|
||||||
{
|
{
|
||||||
|
@ -495,6 +518,12 @@ gimp_image_undo_free (GimpUndo *undo,
|
||||||
image_undo->colormap = NULL;
|
image_undo->colormap = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (image_undo->metadata)
|
||||||
|
{
|
||||||
|
g_free (image_undo->metadata);
|
||||||
|
image_undo->metadata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (image_undo->parasite_name)
|
if (image_undo->parasite_name)
|
||||||
{
|
{
|
||||||
g_free (image_undo->parasite_name);
|
g_free (image_undo->parasite_name);
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct _GimpImageUndo
|
||||||
GimpGrid *grid;
|
GimpGrid *grid;
|
||||||
gint num_colors;
|
gint num_colors;
|
||||||
guchar *colormap;
|
guchar *colormap;
|
||||||
|
GimpMetadata *metadata;
|
||||||
gchar *parasite_name;
|
gchar *parasite_name;
|
||||||
GimpParasite *parasite;
|
GimpParasite *parasite;
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "core/gimpimage-duplicate.h"
|
#include "core/gimpimage-duplicate.h"
|
||||||
#include "core/gimpimage-flip.h"
|
#include "core/gimpimage-flip.h"
|
||||||
#include "core/gimpimage-merge.h"
|
#include "core/gimpimage-merge.h"
|
||||||
|
#include "core/gimpimage-metadata.h"
|
||||||
#include "core/gimpimage-pick-color.h"
|
#include "core/gimpimage-pick-color.h"
|
||||||
#include "core/gimpimage-pick-layer.h"
|
#include "core/gimpimage-pick-layer.h"
|
||||||
#include "core/gimpimage-resize.h"
|
#include "core/gimpimage-resize.h"
|
||||||
|
@ -1706,6 +1707,67 @@ image_set_colormap_invoker (GimpProcedure *procedure,
|
||||||
error ? *error : NULL);
|
error ? *error : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
image_get_metadata_invoker (GimpProcedure *procedure,
|
||||||
|
Gimp *gimp,
|
||||||
|
GimpContext *context,
|
||||||
|
GimpProgress *progress,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean success = TRUE;
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
GimpImage *image;
|
||||||
|
gchar *metadata_string = NULL;
|
||||||
|
|
||||||
|
image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_image_get_metadata (image);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
metadata_string = gimp_metadata_serialize (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_vals = gimp_procedure_get_return_values (procedure, success,
|
||||||
|
error ? *error : NULL);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
g_value_take_string (gimp_value_array_index (return_vals, 1), metadata_string);
|
||||||
|
|
||||||
|
return return_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
image_set_metadata_invoker (GimpProcedure *procedure,
|
||||||
|
Gimp *gimp,
|
||||||
|
GimpContext *context,
|
||||||
|
GimpProgress *progress,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean success = TRUE;
|
||||||
|
GimpImage *image;
|
||||||
|
const gchar *metadata_string;
|
||||||
|
|
||||||
|
image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp);
|
||||||
|
metadata_string = g_value_get_string (gimp_value_array_index (args, 1));
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_metadata_deserialize (metadata_string);
|
||||||
|
|
||||||
|
gimp_image_set_metadata (image, metadata, TRUE);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gimp_procedure_get_return_values (procedure, success,
|
||||||
|
error ? *error : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static GimpValueArray *
|
static GimpValueArray *
|
||||||
image_clean_all_invoker (GimpProcedure *procedure,
|
image_clean_all_invoker (GimpProcedure *procedure,
|
||||||
Gimp *gimp,
|
Gimp *gimp,
|
||||||
|
@ -4553,6 +4615,66 @@ register_image_procs (GimpPDB *pdb)
|
||||||
gimp_pdb_register_procedure (pdb, procedure);
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
g_object_unref (procedure);
|
g_object_unref (procedure);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gimp-image-get-metadata
|
||||||
|
*/
|
||||||
|
procedure = gimp_procedure_new (image_get_metadata_invoker);
|
||||||
|
gimp_object_set_static_name (GIMP_OBJECT (procedure),
|
||||||
|
"gimp-image-get-metadata");
|
||||||
|
gimp_procedure_set_static_strings (procedure,
|
||||||
|
"gimp-image-get-metadata",
|
||||||
|
"Returns the image's metadata.",
|
||||||
|
"Returns exif/iptc/xmp metadata from the image.",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"1995-1996",
|
||||||
|
NULL);
|
||||||
|
gimp_procedure_add_argument (procedure,
|
||||||
|
gimp_param_spec_image_id ("image",
|
||||||
|
"image",
|
||||||
|
"The image",
|
||||||
|
pdb->gimp, FALSE,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
gimp_param_spec_string ("metadata-string",
|
||||||
|
"metadata string",
|
||||||
|
"The exif/ptc/xmp metadata as a string",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
|
g_object_unref (procedure);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gimp-image-set-metadata
|
||||||
|
*/
|
||||||
|
procedure = gimp_procedure_new (image_set_metadata_invoker);
|
||||||
|
gimp_object_set_static_name (GIMP_OBJECT (procedure),
|
||||||
|
"gimp-image-set-metadata");
|
||||||
|
gimp_procedure_set_static_strings (procedure,
|
||||||
|
"gimp-image-set-metadata",
|
||||||
|
"Set the image's metadata.",
|
||||||
|
"Sets exif/iptc/xmp metadata on the image.",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"Spencer Kimball & Peter Mattis",
|
||||||
|
"1995-1996",
|
||||||
|
NULL);
|
||||||
|
gimp_procedure_add_argument (procedure,
|
||||||
|
gimp_param_spec_image_id ("image",
|
||||||
|
"image",
|
||||||
|
"The image",
|
||||||
|
pdb->gimp, FALSE,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_argument (procedure,
|
||||||
|
gimp_param_spec_string ("metadata-string",
|
||||||
|
"metadata string",
|
||||||
|
"The exif/ptc/xmp metadata as a string",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
|
g_object_unref (procedure);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gimp-image-clean-all
|
* gimp-image-clean-all
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "internal-procs.h"
|
#include "internal-procs.h"
|
||||||
|
|
||||||
|
|
||||||
/* 701 procedures registered total */
|
/* 703 procedures registered total */
|
||||||
|
|
||||||
void
|
void
|
||||||
internal_procs_init (GimpPDB *pdb)
|
internal_procs_init (GimpPDB *pdb)
|
||||||
|
|
45
app/sanity.c
45
app/sanity.c
|
@ -22,6 +22,7 @@
|
||||||
#include <pango/pango.h>
|
#include <pango/pango.h>
|
||||||
#include <pango/pangoft2.h>
|
#include <pango/pangoft2.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <gexiv2/gexiv2.h>
|
||||||
#include <gegl.h>
|
#include <gegl.h>
|
||||||
|
|
||||||
#include "libgimpbase/gimpbase.h"
|
#include "libgimpbase/gimpbase.h"
|
||||||
|
@ -38,6 +39,7 @@ static gchar * sanity_check_pango (void);
|
||||||
static gchar * sanity_check_fontconfig (void);
|
static gchar * sanity_check_fontconfig (void);
|
||||||
static gchar * sanity_check_freetype (void);
|
static gchar * sanity_check_freetype (void);
|
||||||
static gchar * sanity_check_gdk_pixbuf (void);
|
static gchar * sanity_check_gdk_pixbuf (void);
|
||||||
|
static gchar * sanity_check_gexiv2 (void);
|
||||||
static gchar * sanity_check_babl (void);
|
static gchar * sanity_check_babl (void);
|
||||||
static gchar * sanity_check_gegl (void);
|
static gchar * sanity_check_gegl (void);
|
||||||
static gchar * sanity_check_gegl_ops (void);
|
static gchar * sanity_check_gegl_ops (void);
|
||||||
|
@ -69,6 +71,9 @@ sanity_check (void)
|
||||||
if (! abort_message)
|
if (! abort_message)
|
||||||
abort_message = sanity_check_gdk_pixbuf ();
|
abort_message = sanity_check_gdk_pixbuf ();
|
||||||
|
|
||||||
|
if (! abort_message)
|
||||||
|
abort_message = sanity_check_gexiv2 ();
|
||||||
|
|
||||||
if (! abort_message)
|
if (! abort_message)
|
||||||
abort_message = sanity_check_babl ();
|
abort_message = sanity_check_babl ();
|
||||||
|
|
||||||
|
@ -346,6 +351,46 @@ sanity_check_gdk_pixbuf (void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
sanity_check_gexiv2 (void)
|
||||||
|
{
|
||||||
|
#ifdef GEXIV2_MAJOR_VERSION
|
||||||
|
|
||||||
|
#define GEXIV2_REQUIRED_MAJOR 0
|
||||||
|
#define GEXIV2_REQUIRED_MINOR 7
|
||||||
|
#define GEXIV2_REQUIRED_MICRO 0
|
||||||
|
|
||||||
|
gint gexiv2_version = gexiv2_get_version ();
|
||||||
|
|
||||||
|
if (gexiv2_version < (GEXIV2_REQUIRED_MAJOR * 100 * 100 +
|
||||||
|
GEXIV2_REQUIRED_MINOR * 100 +
|
||||||
|
GEXIV2_REQUIRED_MICRO))
|
||||||
|
{
|
||||||
|
const gint gexiv2_major_version = gexiv2_version / 100 / 100;
|
||||||
|
const gint gexiv2_minor_version = gexiv2_version / 100 % 100;
|
||||||
|
const gint gexiv2_micro_version = gexiv2_version % 100;
|
||||||
|
|
||||||
|
return g_strdup_printf
|
||||||
|
("gexiv2 version too old!\n\n"
|
||||||
|
"GIMP requires gexiv2 version %d.%d.%d or later.\n"
|
||||||
|
"Installed gexiv2 version is %d.%d.%d.\n\n"
|
||||||
|
"Somehow you or your software packager managed\n"
|
||||||
|
"to install GIMP with an older gexiv2 version.\n\n"
|
||||||
|
"Please upgrade to gexiv2 version %d.%d.%d or later.",
|
||||||
|
GEXIV2_REQUIRED_MAJOR, GEXIV2_REQUIRED_MINOR, GEXIV2_REQUIRED_MICRO,
|
||||||
|
gexiv2_major_version, gexiv2_minor_version, gexiv2_micro_version,
|
||||||
|
GEXIV2_REQUIRED_MAJOR, GEXIV2_REQUIRED_MINOR, GEXIV2_REQUIRED_MICRO);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GEXIV2_REQUIRED_MAJOR
|
||||||
|
#undef GEXIV2_REQUIRED_MINOR
|
||||||
|
#undef GEXIV2_REQUIRED_MICRO
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
sanity_check_babl (void)
|
sanity_check_babl (void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -124,7 +124,8 @@ LDADD = \
|
||||||
$(PANGOCAIRO_LIBS) \
|
$(PANGOCAIRO_LIBS) \
|
||||||
$(CAIRO_LIBS) \
|
$(CAIRO_LIBS) \
|
||||||
$(GEGL_LIBS) \
|
$(GEGL_LIBS) \
|
||||||
$(GLIB_LIBS) \
|
$(GIO_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
$(INTLLIBS) \
|
$(INTLLIBS) \
|
||||||
$(RT_LIBS)
|
$(RT_LIBS)
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "core/gimpimage-colormap.h"
|
#include "core/gimpimage-colormap.h"
|
||||||
#include "core/gimpimage-grid.h"
|
#include "core/gimpimage-grid.h"
|
||||||
#include "core/gimpimage-guides.h"
|
#include "core/gimpimage-guides.h"
|
||||||
|
#include "core/gimpimage-metadata.h"
|
||||||
#include "core/gimpimage-private.h"
|
#include "core/gimpimage-private.h"
|
||||||
#include "core/gimpimage-sample-points.h"
|
#include "core/gimpimage-sample-points.h"
|
||||||
#include "core/gimpimage-undo.h"
|
#include "core/gimpimage-undo.h"
|
||||||
|
@ -140,6 +141,7 @@ xcf_load_image (Gimp *gimp,
|
||||||
{
|
{
|
||||||
GimpImage *image = NULL;
|
GimpImage *image = NULL;
|
||||||
const GimpParasite *parasite;
|
const GimpParasite *parasite;
|
||||||
|
gboolean has_metadata = FALSE;
|
||||||
guint32 saved_pos;
|
guint32 saved_pos;
|
||||||
guint32 offset;
|
guint32 offset;
|
||||||
gint width;
|
gint width;
|
||||||
|
@ -208,6 +210,124 @@ xcf_load_image (Gimp *gimp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for a metadata parasite */
|
||||||
|
parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
|
||||||
|
"gimp-image-metadata");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
const gchar *meta_string;
|
||||||
|
|
||||||
|
meta_string = (gchar *) gimp_parasite_data (parasite);
|
||||||
|
metadata = gimp_metadata_deserialize (meta_string);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
has_metadata = TRUE;
|
||||||
|
|
||||||
|
gimp_image_set_metadata (image, metadata, FALSE);
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_parasite_list_remove (private->parasites,
|
||||||
|
gimp_parasite_name (parasite));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* migrate the old "exif-data" parasite */
|
||||||
|
parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
|
||||||
|
"exif-data");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||||
|
|
||||||
|
if (has_metadata)
|
||||||
|
{
|
||||||
|
g_printerr ("xcf-load: inconsistent metadata discovered: XCF file "
|
||||||
|
"has both 'gimp-image-metadata' and 'exif-data' "
|
||||||
|
"parasites, dropping old 'exif-data'\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_image_get_metadata (image);
|
||||||
|
GError *my_error = NULL;
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
g_object_ref (metadata);
|
||||||
|
else
|
||||||
|
metadata = gimp_metadata_new ();
|
||||||
|
|
||||||
|
if (! gimp_metadata_set_from_exif (metadata,
|
||||||
|
gimp_parasite_data (parasite),
|
||||||
|
gimp_parasite_data_size (parasite),
|
||||||
|
&my_error))
|
||||||
|
{
|
||||||
|
gimp_message (gimp, G_OBJECT (info->progress),
|
||||||
|
GIMP_MESSAGE_WARNING,
|
||||||
|
_("Corrupt 'exif-data' parasite discovered.\n"
|
||||||
|
"EXIF data could not be migrated: %s"),
|
||||||
|
my_error->message);
|
||||||
|
g_clear_error (&my_error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gimp_image_set_metadata (image, metadata, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_parasite_list_remove (private->parasites,
|
||||||
|
gimp_parasite_name (parasite));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* migrate the old "gimp-metadata" parasite */
|
||||||
|
parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
|
||||||
|
"gimp-metadata");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||||
|
|
||||||
|
if (has_metadata)
|
||||||
|
{
|
||||||
|
g_printerr ("xcf-load: inconsistent metadata discovered: XCF file "
|
||||||
|
"has both 'gimp-image-metadata' and 'gimp-metadata' "
|
||||||
|
"parasites, dropping old 'gimp-metadata'\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_image_get_metadata (image);
|
||||||
|
GError *my_error = NULL;
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
g_object_ref (metadata);
|
||||||
|
else
|
||||||
|
metadata = gimp_metadata_new ();
|
||||||
|
|
||||||
|
if (! gimp_metadata_set_from_xmp (metadata,
|
||||||
|
gimp_parasite_data (parasite),
|
||||||
|
gimp_parasite_data_size (parasite),
|
||||||
|
&my_error))
|
||||||
|
{
|
||||||
|
gimp_message (gimp, G_OBJECT (info->progress),
|
||||||
|
GIMP_MESSAGE_WARNING,
|
||||||
|
_("Corrupt 'gimp-metadata' parasite discovered.\n"
|
||||||
|
"XMP data could not be migrated: %s"),
|
||||||
|
my_error->message);
|
||||||
|
g_clear_error (&my_error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gimp_image_set_metadata (image, metadata, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_parasite_list_remove (private->parasites,
|
||||||
|
gimp_parasite_name (parasite));
|
||||||
|
}
|
||||||
|
|
||||||
xcf_progress_update (info);
|
xcf_progress_update (info);
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "core/gimpimage-colormap.h"
|
#include "core/gimpimage-colormap.h"
|
||||||
#include "core/gimpimage-grid.h"
|
#include "core/gimpimage-grid.h"
|
||||||
#include "core/gimpimage-guides.h"
|
#include "core/gimpimage-guides.h"
|
||||||
|
#include "core/gimpimage-metadata.h"
|
||||||
#include "core/gimpimage-private.h"
|
#include "core/gimpimage-private.h"
|
||||||
#include "core/gimpimage-sample-points.h"
|
#include "core/gimpimage-sample-points.h"
|
||||||
#include "core/gimplayer.h"
|
#include "core/gimplayer.h"
|
||||||
|
@ -390,9 +391,10 @@ xcf_save_image_props (XcfInfo *info,
|
||||||
GimpImage *image,
|
GimpImage *image,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
|
GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||||
GimpParasite *parasite = NULL;
|
GimpParasite *grid_parasite = NULL;
|
||||||
GimpUnit unit = gimp_image_get_unit (image);
|
GimpParasite *meta_parasite = NULL;
|
||||||
|
GimpUnit unit = gimp_image_get_unit (image);
|
||||||
gdouble xres;
|
gdouble xres;
|
||||||
gdouble yres;
|
gdouble yres;
|
||||||
|
|
||||||
|
@ -440,8 +442,26 @@ xcf_save_image_props (XcfInfo *info,
|
||||||
{
|
{
|
||||||
GimpGrid *grid = gimp_image_get_grid (image);
|
GimpGrid *grid = gimp_image_get_grid (image);
|
||||||
|
|
||||||
parasite = gimp_grid_to_parasite (grid);
|
grid_parasite = gimp_grid_to_parasite (grid);
|
||||||
gimp_parasite_list_add (private->parasites, parasite);
|
gimp_parasite_list_add (private->parasites, grid_parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gimp_image_get_metadata (image))
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_image_get_metadata (image);
|
||||||
|
gchar *meta_string;
|
||||||
|
|
||||||
|
meta_string = gimp_metadata_serialize (metadata);
|
||||||
|
|
||||||
|
if (meta_string)
|
||||||
|
{
|
||||||
|
meta_parasite = gimp_parasite_new ("gimp-image-metadata",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (meta_string) + 1,
|
||||||
|
meta_string);
|
||||||
|
gimp_parasite_list_add (private->parasites, meta_parasite);
|
||||||
|
g_free (meta_string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gimp_parasite_list_length (private->parasites) > 0)
|
if (gimp_parasite_list_length (private->parasites) > 0)
|
||||||
|
@ -450,11 +470,18 @@ xcf_save_image_props (XcfInfo *info,
|
||||||
private->parasites));
|
private->parasites));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parasite)
|
if (grid_parasite)
|
||||||
{
|
{
|
||||||
gimp_parasite_list_remove (private->parasites,
|
gimp_parasite_list_remove (private->parasites,
|
||||||
gimp_parasite_name (parasite));
|
gimp_parasite_name (grid_parasite));
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (grid_parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta_parasite)
|
||||||
|
{
|
||||||
|
gimp_parasite_list_remove (private->parasites,
|
||||||
|
gimp_parasite_name (meta_parasite));
|
||||||
|
gimp_parasite_free (meta_parasite);
|
||||||
}
|
}
|
||||||
|
|
||||||
xcf_check_error (xcf_save_prop (info, image, PROP_END, error));
|
xcf_check_error (xcf_save_prop (info, image, PROP_END, error));
|
||||||
|
|
30
configure.ac
30
configure.ac
|
@ -59,7 +59,7 @@ m4_define([pygtk_required_version], [2.10.4])
|
||||||
m4_define([poppler_required_version], [0.12.4])
|
m4_define([poppler_required_version], [0.12.4])
|
||||||
m4_define([libcurl_required_version], [7.15.1])
|
m4_define([libcurl_required_version], [7.15.1])
|
||||||
m4_define([libgudev_required_version], [167])
|
m4_define([libgudev_required_version], [167])
|
||||||
m4_define([exif_required_version], [0.6.15])
|
m4_define([gexiv2_required_version], [0.6.1])
|
||||||
m4_define([lcms_required_version], [2.2])
|
m4_define([lcms_required_version], [2.2])
|
||||||
m4_define([libpng_required_version], [1.2.37])
|
m4_define([libpng_required_version], [1.2.37])
|
||||||
m4_define([liblzma_required_version], [5.0.0])
|
m4_define([liblzma_required_version], [5.0.0])
|
||||||
|
@ -123,11 +123,13 @@ GDK_PIXBUF_REQUIRED_VERSION=gdk_pixbuf_required_version
|
||||||
GTK_REQUIRED_VERSION=gtk_required_version
|
GTK_REQUIRED_VERSION=gtk_required_version
|
||||||
CAIRO_REQUIRED_VERSION=cairo_required_version
|
CAIRO_REQUIRED_VERSION=cairo_required_version
|
||||||
GEGL_REQUIRED_VERSION=gegl_required_version
|
GEGL_REQUIRED_VERSION=gegl_required_version
|
||||||
|
GEXIV2_REQUIRED_VERSION=gexiv2_required_version
|
||||||
AC_SUBST(GLIB_REQUIRED_VERSION)
|
AC_SUBST(GLIB_REQUIRED_VERSION)
|
||||||
AC_SUBST(GDK_PIXBUF_REQUIRED_VERSION)
|
AC_SUBST(GDK_PIXBUF_REQUIRED_VERSION)
|
||||||
AC_SUBST(GTK_REQUIRED_VERSION)
|
AC_SUBST(GTK_REQUIRED_VERSION)
|
||||||
AC_SUBST(CAIRO_REQUIRED_VERSION)
|
AC_SUBST(CAIRO_REQUIRED_VERSION)
|
||||||
AC_SUBST(GEGL_REQUIRED_VERSION)
|
AC_SUBST(GEGL_REQUIRED_VERSION)
|
||||||
|
AC_SUBST(GEXIV2_REQUIRED_VERSION)
|
||||||
|
|
||||||
# The symbol GIMP_UNSTABLE is defined above for substitution in
|
# The symbol GIMP_UNSTABLE is defined above for substitution in
|
||||||
# Makefiles and conditionally defined here as a preprocessor symbol
|
# Makefiles and conditionally defined here as a preprocessor symbol
|
||||||
|
@ -607,6 +609,7 @@ if test "x$FREETYPE_CONFIG" != "xno" ; then
|
||||||
fi
|
fi
|
||||||
AC_SUBST(FREETYPE_LIBS)
|
AC_SUBST(FREETYPE_LIBS)
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(GEXIV2, gexiv2 >= gexiv2_required_version)
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# Check for some special functions we need
|
# Check for some special functions we need
|
||||||
|
@ -1327,28 +1330,6 @@ AC_SUBST(MNG_LIBS)
|
||||||
AC_SUBST(MNG_CFLAGS)
|
AC_SUBST(MNG_CFLAGS)
|
||||||
|
|
||||||
|
|
||||||
############################################################
|
|
||||||
# libexif: Library to allow exif tags to be read from, and
|
|
||||||
# saved to, jpeg files. Currently, this permits exif data to
|
|
||||||
# avoid destruction, but no data modification is performed.
|
|
||||||
############################################################
|
|
||||||
|
|
||||||
AC_ARG_WITH(libexif, [ --without-libexif build without EXIF support])
|
|
||||||
|
|
||||||
have_libexif=no
|
|
||||||
if test "x$with_libexif" != xno && test -z "$EXIF_LIBS" && test -n "$JPEG_LIBS"; then
|
|
||||||
have_libexif=yes
|
|
||||||
PKG_CHECK_MODULES(EXIF, libexif >= exif_required_version,
|
|
||||||
AC_DEFINE(HAVE_LIBEXIF, 1, [Define to 1 if libexif is available]),
|
|
||||||
have_libexif="no (libexif not found or too old)")
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_SUBST(EXIF_CFLAGS)
|
|
||||||
AC_SUBST(EXIF_LIBS)
|
|
||||||
|
|
||||||
AM_CONDITIONAL(HAVE_LIBEXIF, test "x$have_libexif" = xyes)
|
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Check for libaa
|
# Check for libaa
|
||||||
#################
|
#################
|
||||||
|
@ -2406,9 +2387,6 @@ Optional Plug-Ins:
|
||||||
X11 Mouse Cursor: $have_xmc
|
X11 Mouse Cursor: $have_xmc
|
||||||
XPM: $have_libxpm
|
XPM: $have_libxpm
|
||||||
|
|
||||||
Plug-In Features:
|
|
||||||
EXIF support: $have_libexif
|
|
||||||
|
|
||||||
Optional Modules:
|
Optional Modules:
|
||||||
ALSA (MIDI Input): $have_alsa
|
ALSA (MIDI Input): $have_alsa
|
||||||
Linux Input: $have_linux_input (GUdev support: $have_libgudev)
|
Linux Input: $have_linux_input (GUdev support: $have_libgudev)
|
||||||
|
|
|
@ -68,6 +68,7 @@ AM_CPPFLAGS = \
|
||||||
-I$(top_srcdir) \
|
-I$(top_srcdir) \
|
||||||
$(GTK_CFLAGS) \
|
$(GTK_CFLAGS) \
|
||||||
$(GEGL_CFLAGS) \
|
$(GEGL_CFLAGS) \
|
||||||
|
$(GEXIV2_CFLAGS) \
|
||||||
-I$(includedir) \
|
-I$(includedir) \
|
||||||
$(xobjective_c)
|
$(xobjective_c)
|
||||||
|
|
||||||
|
@ -280,6 +281,8 @@ libgimpui_sources = \
|
||||||
gimpitemcombobox.h \
|
gimpitemcombobox.h \
|
||||||
gimpmenu.c \
|
gimpmenu.c \
|
||||||
gimpmenu.h \
|
gimpmenu.h \
|
||||||
|
gimpmetadata.c \
|
||||||
|
gimpmetadats.h \
|
||||||
gimppalettemenu.c \
|
gimppalettemenu.c \
|
||||||
gimppalettemenu.h \
|
gimppalettemenu.h \
|
||||||
gimppaletteselectbutton.c \
|
gimppaletteselectbutton.c \
|
||||||
|
@ -354,6 +357,7 @@ gimpinclude_HEADERS = \
|
||||||
gimpimagecombobox.h \
|
gimpimagecombobox.h \
|
||||||
gimpitemcombobox.h \
|
gimpitemcombobox.h \
|
||||||
gimpmenu.h \
|
gimpmenu.h \
|
||||||
|
gimpmetadata.h \
|
||||||
gimppalettemenu.h \
|
gimppalettemenu.h \
|
||||||
gimppaletteselectbutton.h \
|
gimppaletteselectbutton.h \
|
||||||
gimppatternmenu.h \
|
gimppatternmenu.h \
|
||||||
|
@ -399,6 +403,7 @@ libgimpui_@GIMP_API_VERSION@_la_LIBADD = \
|
||||||
$(libgimpbase) \
|
$(libgimpbase) \
|
||||||
$(libgimpmodule) \
|
$(libgimpmodule) \
|
||||||
$(GTK_LIBS) \
|
$(GTK_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
$(RT_LIBS)
|
$(RT_LIBS)
|
||||||
|
|
||||||
libgimpui_@GIMP_API_VERSION@_la_DEPENDENCIES = \
|
libgimpui_@GIMP_API_VERSION@_la_DEPENDENCIES = \
|
||||||
|
|
|
@ -403,6 +403,7 @@ EXPORTS
|
||||||
gimp_image_get_layer_by_tattoo
|
gimp_image_get_layer_by_tattoo
|
||||||
gimp_image_get_layer_position
|
gimp_image_get_layer_position
|
||||||
gimp_image_get_layers
|
gimp_image_get_layers
|
||||||
|
gimp_image_get_metadata
|
||||||
gimp_image_get_name
|
gimp_image_get_name
|
||||||
gimp_image_get_parasite
|
gimp_image_get_parasite
|
||||||
gimp_image_get_parasite_list
|
gimp_image_get_parasite_list
|
||||||
|
@ -484,6 +485,7 @@ EXPORTS
|
||||||
gimp_image_set_component_active
|
gimp_image_set_component_active
|
||||||
gimp_image_set_component_visible
|
gimp_image_set_component_visible
|
||||||
gimp_image_set_filename
|
gimp_image_set_filename
|
||||||
|
gimp_image_set_metadata
|
||||||
gimp_image_set_resolution
|
gimp_image_set_resolution
|
||||||
gimp_image_set_tattoo_state
|
gimp_image_set_tattoo_state
|
||||||
gimp_image_set_unit
|
gimp_image_set_unit
|
||||||
|
|
|
@ -100,6 +100,66 @@ gimp_image_get_thumbnail_data (gint32 image_ID,
|
||||||
return image_data;
|
return image_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_image_get_metadata:
|
||||||
|
* @image_ID: The image.
|
||||||
|
*
|
||||||
|
* Returns the image's metadata.
|
||||||
|
*
|
||||||
|
* Returns exif/iptc/xmp metadata from the image.
|
||||||
|
*
|
||||||
|
* Returns: The exif/ptc/xmp metadata, or %NULL if there is none.
|
||||||
|
*
|
||||||
|
* Since: GIMP 2.10
|
||||||
|
**/
|
||||||
|
GimpMetadata *
|
||||||
|
gimp_image_get_metadata (gint32 image_ID)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = NULL;
|
||||||
|
gchar *metadata_string;
|
||||||
|
|
||||||
|
metadata_string = _gimp_image_get_metadata (image_ID);
|
||||||
|
if (metadata_string)
|
||||||
|
{
|
||||||
|
metadata = gimp_metadata_deserialize (metadata_string);
|
||||||
|
g_free (metadata_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_image_set_metadata:
|
||||||
|
* @image_ID: The image.
|
||||||
|
* @metadata: The exif/ptc/xmp metadata.
|
||||||
|
*
|
||||||
|
* Set the image's metadata.
|
||||||
|
*
|
||||||
|
* Sets exif/iptc/xmp metadata on the image, or deletes it if
|
||||||
|
* @metadata is %NULL.
|
||||||
|
*
|
||||||
|
* Returns: TRUE on success.
|
||||||
|
*
|
||||||
|
* Since: GIMP 2.10
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
gimp_image_set_metadata (gint32 image_ID,
|
||||||
|
GimpMetadata *metadata)
|
||||||
|
{
|
||||||
|
gchar *metadata_string = NULL;
|
||||||
|
gboolean success;
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
metadata_string = gimp_metadata_serialize (metadata);
|
||||||
|
|
||||||
|
success = _gimp_image_set_metadata (image_ID, metadata_string);
|
||||||
|
|
||||||
|
if (metadata_string)
|
||||||
|
g_free (metadata_string);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gimp_image_get_cmap:
|
* gimp_image_get_cmap:
|
||||||
* @image_ID: The image.
|
* @image_ID: The image.
|
||||||
|
|
|
@ -41,6 +41,10 @@ guchar * gimp_image_get_thumbnail_data (gint32 image_ID,
|
||||||
gint *height,
|
gint *height,
|
||||||
gint *bpp);
|
gint *bpp);
|
||||||
|
|
||||||
|
GimpMetadata * gimp_image_get_metadata (gint32 image_ID);
|
||||||
|
gboolean gimp_image_set_metadata (gint32 image_ID,
|
||||||
|
GimpMetadata *metadata);
|
||||||
|
|
||||||
GIMP_DEPRECATED_FOR(gimp_image_get_colormap)
|
GIMP_DEPRECATED_FOR(gimp_image_get_colormap)
|
||||||
guchar * gimp_image_get_cmap (gint32 image_ID,
|
guchar * gimp_image_get_cmap (gint32 image_ID,
|
||||||
gint *num_colors);
|
gint *num_colors);
|
||||||
|
|
|
@ -1799,6 +1799,68 @@ _gimp_image_set_colormap (gint32 image_ID,
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _gimp_image_get_metadata:
|
||||||
|
* @image_ID: The image.
|
||||||
|
*
|
||||||
|
* Returns the image's metadata.
|
||||||
|
*
|
||||||
|
* Returns exif/iptc/xmp metadata from the image.
|
||||||
|
*
|
||||||
|
* Returns: The exif/ptc/xmp metadata as a string.
|
||||||
|
**/
|
||||||
|
gchar *
|
||||||
|
_gimp_image_get_metadata (gint32 image_ID)
|
||||||
|
{
|
||||||
|
GimpParam *return_vals;
|
||||||
|
gint nreturn_vals;
|
||||||
|
gchar *metadata_string = NULL;
|
||||||
|
|
||||||
|
return_vals = gimp_run_procedure ("gimp-image-get-metadata",
|
||||||
|
&nreturn_vals,
|
||||||
|
GIMP_PDB_IMAGE, image_ID,
|
||||||
|
GIMP_PDB_END);
|
||||||
|
|
||||||
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
||||||
|
metadata_string = g_strdup (return_vals[1].data.d_string);
|
||||||
|
|
||||||
|
gimp_destroy_params (return_vals, nreturn_vals);
|
||||||
|
|
||||||
|
return metadata_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _gimp_image_set_metadata:
|
||||||
|
* @image_ID: The image.
|
||||||
|
* @metadata_string: The exif/ptc/xmp metadata as a string.
|
||||||
|
*
|
||||||
|
* Set the image's metadata.
|
||||||
|
*
|
||||||
|
* Sets exif/iptc/xmp metadata on the image.
|
||||||
|
*
|
||||||
|
* Returns: TRUE on success.
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
_gimp_image_set_metadata (gint32 image_ID,
|
||||||
|
const gchar *metadata_string)
|
||||||
|
{
|
||||||
|
GimpParam *return_vals;
|
||||||
|
gint nreturn_vals;
|
||||||
|
gboolean success = TRUE;
|
||||||
|
|
||||||
|
return_vals = gimp_run_procedure ("gimp-image-set-metadata",
|
||||||
|
&nreturn_vals,
|
||||||
|
GIMP_PDB_IMAGE, image_ID,
|
||||||
|
GIMP_PDB_STRING, metadata_string,
|
||||||
|
GIMP_PDB_END);
|
||||||
|
|
||||||
|
success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS;
|
||||||
|
|
||||||
|
gimp_destroy_params (return_vals, nreturn_vals);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gimp_image_clean_all:
|
* gimp_image_clean_all:
|
||||||
* @image_ID: The image.
|
* @image_ID: The image.
|
||||||
|
|
|
@ -148,6 +148,9 @@ G_GNUC_INTERNAL guint8* _gimp_image_get_colormap (gint32
|
||||||
G_GNUC_INTERNAL gboolean _gimp_image_set_colormap (gint32 image_ID,
|
G_GNUC_INTERNAL gboolean _gimp_image_set_colormap (gint32 image_ID,
|
||||||
gint num_bytes,
|
gint num_bytes,
|
||||||
const guint8 *colormap);
|
const guint8 *colormap);
|
||||||
|
G_GNUC_INTERNAL gchar* _gimp_image_get_metadata (gint32 image_ID);
|
||||||
|
G_GNUC_INTERNAL gboolean _gimp_image_set_metadata (gint32 image_ID,
|
||||||
|
const gchar *metadata_string);
|
||||||
gboolean gimp_image_clean_all (gint32 image_ID);
|
gboolean gimp_image_clean_all (gint32 image_ID);
|
||||||
gboolean gimp_image_is_dirty (gint32 image_ID);
|
gboolean gimp_image_is_dirty (gint32 image_ID);
|
||||||
G_GNUC_INTERNAL gboolean _gimp_image_thumbnail (gint32 image_ID,
|
G_GNUC_INTERNAL gboolean _gimp_image_thumbnail (gint32 image_ID,
|
||||||
|
|
640
libgimp/gimpmetadata.c
Normal file
640
libgimp/gimpmetadata.c
Normal file
|
@ -0,0 +1,640 @@
|
||||||
|
/* LIBGIMP - The GIMP Library
|
||||||
|
* Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
|
||||||
|
*
|
||||||
|
* gimpmetadata.c
|
||||||
|
*
|
||||||
|
* 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 3 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
|
||||||
|
* Lesser 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, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <gexiv2/gexiv2.h>
|
||||||
|
|
||||||
|
#include "gimp.h"
|
||||||
|
#include "gimpui.h"
|
||||||
|
#include "gimpmetadata.h"
|
||||||
|
|
||||||
|
#include "libgimp-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void gimp_image_metadata_rotate (gint32 image_ID,
|
||||||
|
GExiv2Orientation orientation);
|
||||||
|
static void gimp_image_metadata_rotate_query (gint32 image_ID,
|
||||||
|
const gchar *mime_type,
|
||||||
|
GimpMetadata *metadata,
|
||||||
|
gboolean interactive);
|
||||||
|
static gboolean gimp_image_metadata_rotate_dialog (gint32 image_ID,
|
||||||
|
const gchar *parasite_name);
|
||||||
|
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_image_metadata_load (gint32 image_ID,
|
||||||
|
const gchar *mime_type,
|
||||||
|
GFile *file,
|
||||||
|
gboolean interactive)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
g_return_if_fail (image_ID > 0);
|
||||||
|
g_return_if_fail (mime_type != NULL);
|
||||||
|
g_return_if_fail (G_IS_FILE (file));
|
||||||
|
|
||||||
|
metadata = gimp_metadata_load_from_file (file, NULL);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
gchar *comment;
|
||||||
|
gdouble xres;
|
||||||
|
gdouble yres;
|
||||||
|
GimpUnit unit;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
gchar *xml = gimp_metadata_serialize (metadata);
|
||||||
|
GimpMetadata *new = gimp_metadata_deserialize (xml);
|
||||||
|
gchar *xml2 = gimp_metadata_serialize (new);
|
||||||
|
|
||||||
|
FILE *f = fopen ("/tmp/gimp-test-xml1", "w");
|
||||||
|
fprintf (f, "%s", xml);
|
||||||
|
fclose (f);
|
||||||
|
|
||||||
|
f = fopen ("/tmp/gimp-test-xml2", "w");
|
||||||
|
fprintf (f, "%s", xml2);
|
||||||
|
fclose (f);
|
||||||
|
|
||||||
|
system ("diff -u /tmp/gimp-test-xml1 /tmp/gimp-test-xml2");
|
||||||
|
|
||||||
|
g_free (xml);
|
||||||
|
g_free (xml2);
|
||||||
|
g_object_unref (new);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
comment = gexiv2_metadata_get_tag_string (metadata,
|
||||||
|
"Exif.Photo.UserComment");
|
||||||
|
if (! comment)
|
||||||
|
comment = gexiv2_metadata_get_tag_string (metadata,
|
||||||
|
"Exif.Image.ImageDescription");
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
{
|
||||||
|
GimpParasite *parasite;
|
||||||
|
|
||||||
|
parasite = gimp_parasite_new ("gimp-comment",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (comment) + 1,
|
||||||
|
comment);
|
||||||
|
g_free (comment);
|
||||||
|
|
||||||
|
gimp_image_attach_parasite (image_ID, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gimp_metadata_get_resolution (metadata, &xres, &yres, &unit))
|
||||||
|
{
|
||||||
|
gimp_image_set_resolution (image_ID, xres, yres);
|
||||||
|
gimp_image_set_unit (image_ID, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_image_metadata_rotate_query (image_ID, mime_type,
|
||||||
|
metadata, interactive);
|
||||||
|
|
||||||
|
gexiv2_metadata_erase_exif_thumbnail (metadata);
|
||||||
|
|
||||||
|
gimp_image_set_metadata (image_ID, metadata);
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpMetadata *
|
||||||
|
gimp_image_metadata_save_prepare (gint32 image_ID,
|
||||||
|
const gchar *mime_type)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
g_return_val_if_fail (image_ID > 0, NULL);
|
||||||
|
g_return_val_if_fail (mime_type != NULL, NULL);
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (image_ID);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
GDateTime *datetime;
|
||||||
|
const GimpParasite *comment_parasite;
|
||||||
|
const gchar *comment = NULL;
|
||||||
|
gint image_width;
|
||||||
|
gint image_height;
|
||||||
|
gdouble xres;
|
||||||
|
gdouble yres;
|
||||||
|
gchar buffer[32];
|
||||||
|
|
||||||
|
image_width = gimp_image_width (image_ID);
|
||||||
|
image_height = gimp_image_height (image_ID);
|
||||||
|
|
||||||
|
datetime = g_date_time_new_now_local ();
|
||||||
|
|
||||||
|
comment_parasite = gimp_image_get_parasite (image_ID, "gimp-comment");
|
||||||
|
if (comment_parasite)
|
||||||
|
comment = gimp_parasite_data (comment_parasite);
|
||||||
|
|
||||||
|
/* EXIF */
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
{
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Exif.Photo.UserComment",
|
||||||
|
comment);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Exif.Image.ImageDescription",
|
||||||
|
comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer),
|
||||||
|
"%d:%02d:%02d %02d:%02d:%02d",
|
||||||
|
g_date_time_get_year (datetime),
|
||||||
|
g_date_time_get_month (datetime),
|
||||||
|
g_date_time_get_day_of_month (datetime),
|
||||||
|
g_date_time_get_hour (datetime),
|
||||||
|
g_date_time_get_minute (datetime),
|
||||||
|
g_date_time_get_second (datetime));
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Exif.Image.DateTime",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Exif.Image.Software",
|
||||||
|
PACKAGE_STRING);
|
||||||
|
|
||||||
|
gimp_metadata_set_pixel_size (metadata,
|
||||||
|
image_width, image_height);
|
||||||
|
|
||||||
|
gimp_image_get_resolution (image_ID, &xres, &yres);
|
||||||
|
gimp_metadata_set_resolution (metadata, xres, yres,
|
||||||
|
gimp_image_get_unit (image_ID));
|
||||||
|
|
||||||
|
/* XMP */
|
||||||
|
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Xmp.dc.Format",
|
||||||
|
mime_type);
|
||||||
|
|
||||||
|
if (! g_strcmp0 (mime_type, "image/tiff"))
|
||||||
|
{
|
||||||
|
/* TIFF specific XMP data */
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", image_width);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Xmp.tiff.ImageWidth",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", image_height);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Xmp.tiff.ImageLength",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer),
|
||||||
|
"%d:%02d:%02d %02d:%02d:%02d",
|
||||||
|
g_date_time_get_year (datetime),
|
||||||
|
g_date_time_get_month (datetime),
|
||||||
|
g_date_time_get_day_of_month (datetime),
|
||||||
|
g_date_time_get_hour (datetime),
|
||||||
|
g_date_time_get_minute (datetime),
|
||||||
|
g_date_time_get_second (datetime));
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Xmp.tiff.DateTime",
|
||||||
|
buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IPTC */
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer),
|
||||||
|
"%d-%d-%d",
|
||||||
|
g_date_time_get_year (datetime),
|
||||||
|
g_date_time_get_month (datetime),
|
||||||
|
g_date_time_get_day_of_month (datetime));
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Iptc.Application2.DateCreated",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer),
|
||||||
|
"%02d:%02d:%02d-%02d:%02d",
|
||||||
|
g_date_time_get_hour (datetime),
|
||||||
|
g_date_time_get_minute (datetime),
|
||||||
|
g_date_time_get_second (datetime),
|
||||||
|
g_date_time_get_hour (datetime),
|
||||||
|
g_date_time_get_minute (datetime));
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Iptc.Application2.TimeCreated",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
g_date_time_unref (datetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gimp_image_metadata_save_finish (gint32 image_ID,
|
||||||
|
const gchar *mime_type,
|
||||||
|
GimpMetadata *metadata,
|
||||||
|
GFile *file,
|
||||||
|
GimpMetadataSaveFlags flags,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GExiv2Metadata *new_metadata;
|
||||||
|
gboolean support_exif;
|
||||||
|
gboolean support_xmp;
|
||||||
|
gboolean support_iptc;
|
||||||
|
gchar *value;
|
||||||
|
gboolean success = FALSE;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (image_ID > 0, FALSE);
|
||||||
|
g_return_val_if_fail (mime_type != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
|
||||||
|
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
|
/* read metadata from saved file */
|
||||||
|
new_metadata = gimp_metadata_load_from_file (file, error);
|
||||||
|
|
||||||
|
if (! new_metadata)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
support_exif = gexiv2_metadata_get_supports_exif (new_metadata);
|
||||||
|
support_xmp = gexiv2_metadata_get_supports_xmp (new_metadata);
|
||||||
|
support_iptc = gexiv2_metadata_get_supports_iptc (new_metadata);
|
||||||
|
|
||||||
|
if ((flags & GIMP_METADATA_SAVE_EXIF) && support_exif)
|
||||||
|
{
|
||||||
|
gchar **exif_data = gexiv2_metadata_get_exif_tags (metadata);
|
||||||
|
|
||||||
|
for (i = 0; exif_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
if (! gexiv2_metadata_has_tag (new_metadata, exif_data[i]) &&
|
||||||
|
gimp_metadata_is_tag_supported (exif_data[i], mime_type))
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (metadata, exif_data[i]);
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata, exif_data[i],
|
||||||
|
value);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (exif_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & GIMP_METADATA_SAVE_XMP) && support_xmp)
|
||||||
|
{
|
||||||
|
gchar **xmp_data = gexiv2_metadata_get_xmp_tags (metadata);
|
||||||
|
|
||||||
|
for (i = 0; xmp_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
if (! gexiv2_metadata_has_tag (new_metadata, xmp_data[i]) &&
|
||||||
|
gimp_metadata_is_tag_supported (xmp_data[i], mime_type))
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (metadata, xmp_data[i]);
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata, xmp_data[i],
|
||||||
|
value);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (xmp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & GIMP_METADATA_SAVE_IPTC) && support_iptc)
|
||||||
|
{
|
||||||
|
gchar **iptc_data = gexiv2_metadata_get_iptc_tags (metadata);
|
||||||
|
|
||||||
|
for (i = 0; iptc_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
if (! gexiv2_metadata_has_tag (new_metadata, iptc_data[i]) &&
|
||||||
|
gimp_metadata_is_tag_supported (iptc_data[i], mime_type))
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (metadata, iptc_data[i]);
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata, iptc_data[i],
|
||||||
|
value);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (iptc_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & GIMP_METADATA_SAVE_THUMBNAIL)
|
||||||
|
{
|
||||||
|
GdkPixbuf *thumb_pixbuf;
|
||||||
|
gchar *thumb_buffer;
|
||||||
|
gint image_width;
|
||||||
|
gint image_height;
|
||||||
|
gsize count;
|
||||||
|
gint thumbw;
|
||||||
|
gint thumbh;
|
||||||
|
|
||||||
|
#define EXIF_THUMBNAIL_SIZE 256
|
||||||
|
|
||||||
|
image_width = gimp_image_width (image_ID);
|
||||||
|
image_height = gimp_image_height (image_ID);
|
||||||
|
|
||||||
|
if (image_width > image_height)
|
||||||
|
{
|
||||||
|
thumbw = EXIF_THUMBNAIL_SIZE;
|
||||||
|
thumbh = EXIF_THUMBNAIL_SIZE * image_height / image_width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thumbh = EXIF_THUMBNAIL_SIZE;
|
||||||
|
thumbw = EXIF_THUMBNAIL_SIZE * image_height / image_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
thumb_pixbuf = gimp_image_get_thumbnail (image_ID, thumbw, thumbh,
|
||||||
|
GIMP_PIXBUF_KEEP_ALPHA);
|
||||||
|
|
||||||
|
if (gdk_pixbuf_save_to_buffer (thumb_pixbuf, &thumb_buffer, &count,
|
||||||
|
"jpeg", NULL,
|
||||||
|
"quality", "75",
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
gchar buffer[32];
|
||||||
|
|
||||||
|
gexiv2_metadata_set_exif_thumbnail_from_buffer (new_metadata,
|
||||||
|
(guchar *) thumb_buffer,
|
||||||
|
count);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", thumbw);
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata,
|
||||||
|
"Exif.Thumbnail.ImageWidth",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", thumbh);
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata,
|
||||||
|
"Exif.Thumbnail.ImageLength",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata,
|
||||||
|
"Exif.Thumbnail.BitsPerSample",
|
||||||
|
"8 8 8");
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata,
|
||||||
|
"Exif.Thumbnail.SamplesPerPixel",
|
||||||
|
"3");
|
||||||
|
gexiv2_metadata_set_tag_string (new_metadata,
|
||||||
|
"Exif.Thumbnail.PhotometricInterpretation",
|
||||||
|
"6");
|
||||||
|
|
||||||
|
g_free (thumb_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (thumb_pixbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
success = gimp_metadata_save_to_file (new_metadata, file, error);
|
||||||
|
|
||||||
|
g_object_unref (new_metadata);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* private functions */
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_image_metadata_rotate (gint32 image_ID,
|
||||||
|
GExiv2Orientation orientation)
|
||||||
|
{
|
||||||
|
switch (orientation)
|
||||||
|
{
|
||||||
|
case GEXIV2_ORIENTATION_UNSPECIFIED:
|
||||||
|
case GEXIV2_ORIENTATION_NORMAL: /* standard orientation, do nothing */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_HFLIP:
|
||||||
|
gimp_image_flip (image_ID, GIMP_ORIENTATION_HORIZONTAL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_ROT_180:
|
||||||
|
gimp_image_rotate (image_ID, GIMP_ROTATE_180);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_VFLIP:
|
||||||
|
gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_ROT_90_HFLIP: /* flipped diagonally around '\' */
|
||||||
|
gimp_image_rotate (image_ID, GIMP_ROTATE_90);
|
||||||
|
gimp_image_flip (image_ID, GIMP_ORIENTATION_HORIZONTAL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_ROT_90: /* 90 CW */
|
||||||
|
gimp_image_rotate (image_ID, GIMP_ROTATE_90);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_ROT_90_VFLIP: /* flipped diagonally around '/' */
|
||||||
|
gimp_image_rotate (image_ID, GIMP_ROTATE_90);
|
||||||
|
gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEXIV2_ORIENTATION_ROT_270: /* 90 CCW */
|
||||||
|
gimp_image_rotate (image_ID, GIMP_ROTATE_270);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: /* shouldn't happen */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_image_metadata_rotate_query (gint32 image_ID,
|
||||||
|
const gchar *mime_type,
|
||||||
|
GimpMetadata *metadata,
|
||||||
|
gboolean interactive)
|
||||||
|
{
|
||||||
|
GimpParasite *parasite;
|
||||||
|
gchar *parasite_name;
|
||||||
|
GExiv2Orientation orientation;
|
||||||
|
gboolean query = interactive;
|
||||||
|
|
||||||
|
orientation = gexiv2_metadata_get_orientation (metadata);
|
||||||
|
|
||||||
|
if (orientation <= GEXIV2_ORIENTATION_NORMAL ||
|
||||||
|
orientation > GEXIV2_ORIENTATION_MAX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parasite_name = g_strdup_printf ("gimp-metadata-exif-rotate(%s)", mime_type);
|
||||||
|
|
||||||
|
parasite = gimp_get_parasite (parasite_name);
|
||||||
|
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
if (strncmp (gimp_parasite_data (parasite), "yes",
|
||||||
|
gimp_parasite_data_size (parasite)) == 0)
|
||||||
|
{
|
||||||
|
query = FALSE;
|
||||||
|
}
|
||||||
|
else if (strncmp (gimp_parasite_data (parasite), "no",
|
||||||
|
gimp_parasite_data_size (parasite)) == 0)
|
||||||
|
{
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
g_free (parasite_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query && ! gimp_image_metadata_rotate_dialog (image_ID,
|
||||||
|
parasite_name))
|
||||||
|
{
|
||||||
|
g_free (parasite_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (parasite_name);
|
||||||
|
|
||||||
|
gimp_image_metadata_rotate (image_ID, orientation);
|
||||||
|
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Exif.Image.Orientation", "1");
|
||||||
|
gexiv2_metadata_set_tag_string (metadata,
|
||||||
|
"Xmp.tiff.Orientation", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gimp_image_metadata_rotate_dialog (gint32 image_ID,
|
||||||
|
const gchar *parasite_name)
|
||||||
|
{
|
||||||
|
GtkWidget *dialog;
|
||||||
|
GtkWidget *hbox;
|
||||||
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *label;
|
||||||
|
GtkWidget *toggle;
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
gint response;
|
||||||
|
|
||||||
|
dialog = gimp_dialog_new (_("Rotate Image?"), "gimp-metadata-rotate-dialog",
|
||||||
|
NULL, 0, NULL, NULL,
|
||||||
|
|
||||||
|
_("_Keep Orientation"), GTK_RESPONSE_CANCEL,
|
||||||
|
GIMP_STOCK_TOOL_ROTATE, GTK_RESPONSE_OK,
|
||||||
|
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
|
||||||
|
GTK_RESPONSE_OK,
|
||||||
|
GTK_RESPONSE_CANCEL,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
|
||||||
|
gimp_window_set_transient (GTK_WINDOW (dialog));
|
||||||
|
|
||||||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||||
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
|
||||||
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
||||||
|
hbox, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (hbox);
|
||||||
|
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (vbox);
|
||||||
|
|
||||||
|
#define THUMBNAIL_SIZE 128
|
||||||
|
|
||||||
|
pixbuf = gimp_image_get_thumbnail (image_ID,
|
||||||
|
THUMBNAIL_SIZE, THUMBNAIL_SIZE,
|
||||||
|
GIMP_PIXBUF_SMALL_CHECKS);
|
||||||
|
|
||||||
|
if (pixbuf)
|
||||||
|
{
|
||||||
|
GtkWidget *image;
|
||||||
|
gchar *name;
|
||||||
|
|
||||||
|
image = gtk_image_new_from_pixbuf (pixbuf);
|
||||||
|
g_object_unref (pixbuf);
|
||||||
|
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (image);
|
||||||
|
|
||||||
|
name = gimp_image_get_name (image_ID);
|
||||||
|
|
||||||
|
label = gtk_label_new (name);
|
||||||
|
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_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
g_free (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
|
||||||
|
gtk_widget_show (vbox);
|
||||||
|
|
||||||
|
label = g_object_new (GTK_TYPE_LABEL,
|
||||||
|
"label", _("According to the EXIF data, "
|
||||||
|
"this image is rotated."),
|
||||||
|
"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 (vbox), label, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
label = g_object_new (GTK_TYPE_LABEL,
|
||||||
|
"label", _("Would you like GIMP to rotate it "
|
||||||
|
"into the standard orientation?"),
|
||||||
|
"wrap", TRUE,
|
||||||
|
"justify", GTK_JUSTIFY_LEFT,
|
||||||
|
"xalign", 0.0,
|
||||||
|
"yalign", 0.5,
|
||||||
|
NULL);
|
||||||
|
gtk_box_pack_start (GTK_BOX (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 (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));
|
||||||
|
|
||||||
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)))
|
||||||
|
{
|
||||||
|
GimpParasite *parasite;
|
||||||
|
const gchar *str = (response == GTK_RESPONSE_OK) ? "yes" : "no";
|
||||||
|
|
||||||
|
parasite = gimp_parasite_new (parasite_name,
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (str), str);
|
||||||
|
gimp_attach_parasite (parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_destroy (dialog);
|
||||||
|
|
||||||
|
return (response == GTK_RESPONSE_OK);
|
||||||
|
}
|
48
libgimp/gimpmetadata.h
Normal file
48
libgimp/gimpmetadata.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* LIBGIMP - The GIMP Library
|
||||||
|
* Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
|
||||||
|
*
|
||||||
|
* gimpmetadata.h
|
||||||
|
*
|
||||||
|
* 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 3 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
|
||||||
|
* Lesser 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, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION)
|
||||||
|
#error "Only <libgimp/gimpui.h> can be included directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __LIBGIMP_GIMP_METADATA_H__
|
||||||
|
#define __LIBGIMP_GIMP_METADATA_H__
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* For information look into the C source or the html documentation */
|
||||||
|
|
||||||
|
|
||||||
|
void gimp_image_metadata_load (gint32 image_ID,
|
||||||
|
const gchar *mime_type,
|
||||||
|
GFile *file,
|
||||||
|
gboolean interactive);
|
||||||
|
GimpMetadata * gimp_image_metadata_save_prepare (gint32 image_ID,
|
||||||
|
const gchar *mime_type);
|
||||||
|
gboolean gimp_image_metadata_save_finish (gint32 image_ID,
|
||||||
|
const gchar *mime_type,
|
||||||
|
GimpMetadata *metadata,
|
||||||
|
GFile *file,
|
||||||
|
GimpMetadataSaveFlags flags,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* ___LIBGIMP_GIMP_METADATA_H__ */
|
|
@ -38,6 +38,9 @@ EXPORTS
|
||||||
gimp_image_combo_box_get_type
|
gimp_image_combo_box_get_type
|
||||||
gimp_image_combo_box_new
|
gimp_image_combo_box_new
|
||||||
gimp_image_menu_new
|
gimp_image_menu_new
|
||||||
|
gimp_image_metadata_load
|
||||||
|
gimp_image_metadata_save_prepare
|
||||||
|
gimp_image_metadata_save_finish
|
||||||
gimp_layer_combo_box_get_type
|
gimp_layer_combo_box_get_type
|
||||||
gimp_layer_combo_box_new
|
gimp_layer_combo_box_new
|
||||||
gimp_layer_menu_new
|
gimp_layer_menu_new
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include <libgimp/gimpexport.h>
|
#include <libgimp/gimpexport.h>
|
||||||
#include <libgimp/gimpmenu.h>
|
#include <libgimp/gimpmenu.h>
|
||||||
|
#include <libgimp/gimpmetadata.h>
|
||||||
#include <libgimp/gimpaspectpreview.h>
|
#include <libgimp/gimpaspectpreview.h>
|
||||||
#include <libgimp/gimpdrawablepreview.h>
|
#include <libgimp/gimpdrawablepreview.h>
|
||||||
#include <libgimp/gimpbrushmenu.h>
|
#include <libgimp/gimpbrushmenu.h>
|
||||||
|
|
|
@ -61,6 +61,7 @@ AM_CPPFLAGS = \
|
||||||
-DGIMP_BASE_COMPILATION \
|
-DGIMP_BASE_COMPILATION \
|
||||||
-I$(top_srcdir) \
|
-I$(top_srcdir) \
|
||||||
$(GIO_CFLAGS) \
|
$(GIO_CFLAGS) \
|
||||||
|
$(GEXIV2_CFLAGS) \
|
||||||
$(BINRELOC_CFLAGS) \
|
$(BINRELOC_CFLAGS) \
|
||||||
-I$(includedir) \
|
-I$(includedir) \
|
||||||
$(xobjective_c)
|
$(xobjective_c)
|
||||||
|
@ -101,6 +102,8 @@ libgimpbase_sources = \
|
||||||
gimpenv.h \
|
gimpenv.h \
|
||||||
gimpmemsize.c \
|
gimpmemsize.c \
|
||||||
gimpmemsize.h \
|
gimpmemsize.h \
|
||||||
|
gimpmetadata.c \
|
||||||
|
gimpmetadata.h \
|
||||||
gimpparasite.c \
|
gimpparasite.c \
|
||||||
gimpparasite.h \
|
gimpparasite.h \
|
||||||
gimpparasiteio.c \
|
gimpparasiteio.c \
|
||||||
|
@ -144,6 +147,7 @@ libgimpbaseinclude_HEADERS = \
|
||||||
gimpdatafiles.h \
|
gimpdatafiles.h \
|
||||||
gimpenv.h \
|
gimpenv.h \
|
||||||
gimpmemsize.h \
|
gimpmemsize.h \
|
||||||
|
gimpmetadata.h \
|
||||||
gimpparasite.h \
|
gimpparasite.h \
|
||||||
gimpparasiteio.h \
|
gimpparasiteio.h \
|
||||||
gimprectangle.h \
|
gimprectangle.h \
|
||||||
|
@ -152,7 +156,6 @@ libgimpbaseinclude_HEADERS = \
|
||||||
gimputils.h \
|
gimputils.h \
|
||||||
gimpvaluearray.h
|
gimpvaluearray.h
|
||||||
|
|
||||||
|
|
||||||
libgimpbase_@GIMP_API_VERSION@_la_LDFLAGS = \
|
libgimpbase_@GIMP_API_VERSION@_la_LDFLAGS = \
|
||||||
-version-info $(LT_VERSION_INFO) \
|
-version-info $(LT_VERSION_INFO) \
|
||||||
$(no_undefined) \
|
$(no_undefined) \
|
||||||
|
@ -163,9 +166,9 @@ libgimpbase_@GIMP_API_VERSION@_la_DEPENDENCIES = $(gimpbase_def)
|
||||||
|
|
||||||
libgimpbase_@GIMP_API_VERSION@_la_LIBADD = \
|
libgimpbase_@GIMP_API_VERSION@_la_LIBADD = \
|
||||||
$(GIO_LIBS) \
|
$(GIO_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
$(ole32_lib)
|
$(ole32_lib)
|
||||||
|
|
||||||
|
|
||||||
install-data-local: install-ms-lib install-libtool-import-lib
|
install-data-local: install-ms-lib install-libtool-import-lib
|
||||||
|
|
||||||
uninstall-local: uninstall-ms-lib uninstall-libtool-import-lib
|
uninstall-local: uninstall-ms-lib uninstall-libtool-import-lib
|
||||||
|
|
|
@ -50,6 +50,19 @@ EXPORTS
|
||||||
gimp_memsize_serialize
|
gimp_memsize_serialize
|
||||||
gimp_memsize_to_string
|
gimp_memsize_to_string
|
||||||
gimp_message_handler_type_get_type
|
gimp_message_handler_type_get_type
|
||||||
|
gimp_metadata_deserialize
|
||||||
|
gimp_metadata_duplicate
|
||||||
|
gimp_metadata_get_resolution
|
||||||
|
gimp_metadata_is_tag_supported
|
||||||
|
gimp_metadata_load_from_file
|
||||||
|
gimp_metadata_new
|
||||||
|
gimp_metadata_save_to_file
|
||||||
|
gimp_metadata_serialize
|
||||||
|
gimp_metadata_set_bits_per_sample
|
||||||
|
gimp_metadata_set_from_exif
|
||||||
|
gimp_metadata_set_from_xmp
|
||||||
|
gimp_metadata_set_pixel_size
|
||||||
|
gimp_metadata_set_resolution
|
||||||
gimp_micro_version
|
gimp_micro_version
|
||||||
gimp_minor_version
|
gimp_minor_version
|
||||||
gimp_paint_application_mode_get_type
|
gimp_paint_application_mode_get_type
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <libgimpbase/gimpenv.h>
|
#include <libgimpbase/gimpenv.h>
|
||||||
#include <libgimpbase/gimplimits.h>
|
#include <libgimpbase/gimplimits.h>
|
||||||
#include <libgimpbase/gimpmemsize.h>
|
#include <libgimpbase/gimpmemsize.h>
|
||||||
|
#include <libgimpbase/gimpmetadata.h>
|
||||||
#include <libgimpbase/gimpparasite.h>
|
#include <libgimpbase/gimpparasite.h>
|
||||||
#include <libgimpbase/gimprectangle.h>
|
#include <libgimpbase/gimprectangle.h>
|
||||||
#include <libgimpbase/gimpunit.h>
|
#include <libgimpbase/gimpunit.h>
|
||||||
|
|
|
@ -55,6 +55,8 @@ typedef struct _GimpValueArray GimpValueArray;
|
||||||
typedef void (* GimpDatafileLoaderFunc) (const GimpDatafileData *file_data,
|
typedef void (* GimpDatafileLoaderFunc) (const GimpDatafileData *file_data,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
typedef struct _GExiv2Metadata GimpMetadata;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GimpEnumDesc:
|
* GimpEnumDesc:
|
||||||
|
|
945
libgimpbase/gimpmetadata.c
Normal file
945
libgimpbase/gimpmetadata.c
Normal file
|
@ -0,0 +1,945 @@
|
||||||
|
/* LIBGIMPBASE - The GIMP Basic Library
|
||||||
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||||
|
*
|
||||||
|
* gimpmetadata.c
|
||||||
|
* Copyright (C) 2013 Hartmut Kuhse <hartmutkuhse@src.gnome.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 3 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
|
||||||
|
* Lesser 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, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gexiv2/gexiv2.h>
|
||||||
|
|
||||||
|
#include "gimpbasetypes.h"
|
||||||
|
|
||||||
|
#include "gimpmetadata.h"
|
||||||
|
#include "gimpunit.h"
|
||||||
|
|
||||||
|
#include "libgimp/libgimp-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define TAG_LINE_DELIMITER "\v"
|
||||||
|
#define TAG_TAG_DELIMITER "#"
|
||||||
|
|
||||||
|
|
||||||
|
static GQuark gimp_metadata_error_quark (void);
|
||||||
|
static gint gimp_metadata_length (const gchar *testline,
|
||||||
|
const gchar *delim);
|
||||||
|
static gboolean gimp_metadata_get_rational (const gchar *value,
|
||||||
|
gint sections,
|
||||||
|
gchar ***numerator,
|
||||||
|
gchar ***denominator);
|
||||||
|
static void gimp_metadata_add (GimpMetadata *src,
|
||||||
|
GimpMetadata *dest);
|
||||||
|
|
||||||
|
|
||||||
|
static const gchar *tiff_tags[] =
|
||||||
|
{
|
||||||
|
"Xmp.tiff",
|
||||||
|
"Exif.Image.ImageWidth",
|
||||||
|
"Exif.Image.ImageLength",
|
||||||
|
"Exif.Image.BitsPerSample",
|
||||||
|
"Exif.Image.Compression",
|
||||||
|
"Exif.Image.PhotometricInterpretation",
|
||||||
|
"Exif.Image.FillOrder",
|
||||||
|
"Exif.Image.SamplesPerPixel",
|
||||||
|
"Exif.Image.StripOffsets",
|
||||||
|
"Exif.Image.RowsPerStrip",
|
||||||
|
"Exif.Image.StripByteCounts",
|
||||||
|
"Exif.Image.PlanarConfiguration"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const gchar *jpeg_tags[] =
|
||||||
|
{
|
||||||
|
"Exif.Image.JPEGProc",
|
||||||
|
"Exif.Image.JPEGInterchangeFormat",
|
||||||
|
"Exif.Image.JPEGInterchangeFormatLength",
|
||||||
|
"Exif.Image.JPEGRestartInterval",
|
||||||
|
"Exif.Image.JPEGLosslessPredictors",
|
||||||
|
"Exif.Image.JPEGPointTransforms",
|
||||||
|
"Exif.Image.JPEGQTables",
|
||||||
|
"Exif.Image.JPEGDCTables",
|
||||||
|
"Exif.Image.JPEGACTables"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const gchar *unsupported_tags[] =
|
||||||
|
{
|
||||||
|
"Exif.Image.SubIFDs",
|
||||||
|
"Exif.Image.ClipPath",
|
||||||
|
"Exif.Image.XClipPathUnits",
|
||||||
|
"Exif.Image.YClipPathUnits",
|
||||||
|
"Xmp.xmpMM.History",
|
||||||
|
"Exif.Image.XPTitle",
|
||||||
|
"Exif.Image.XPComment",
|
||||||
|
"Exif.Image.XPAuthor",
|
||||||
|
"Exif.Image.XPKeywords",
|
||||||
|
"Exif.Image.XPSubject",
|
||||||
|
"Exif.Image.DNGVersion",
|
||||||
|
"Exif.Image.DNGBackwardVersion",
|
||||||
|
"Exif.Iop"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const guint8 minimal_exif[] =
|
||||||
|
{
|
||||||
|
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
|
||||||
|
0x01, 0x01, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x00, 0xff, 0xe1
|
||||||
|
};
|
||||||
|
|
||||||
|
static const guint8 wilber_jpg[] =
|
||||||
|
{
|
||||||
|
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
|
||||||
|
0x01, 0x01, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
|
||||||
|
0x00, 0x50, 0x37, 0x3c, 0x46, 0x3c, 0x32, 0x50, 0x46, 0x41, 0x46, 0x5a,
|
||||||
|
0x55, 0x50, 0x5f, 0x78, 0xc8, 0x82, 0x78, 0x6e, 0x6e, 0x78, 0xf5, 0xaf,
|
||||||
|
0xb9, 0x91, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x55, 0x5a,
|
||||||
|
0x5a, 0x78, 0x69, 0x78, 0xeb, 0x82, 0x82, 0xeb, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x10, 0x03,
|
||||||
|
0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
|
||||||
|
0x16, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0xff, 0xc4, 0x00,
|
||||||
|
0x1e, 0x10, 0x00, 0x01, 0x05, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x11, 0x31,
|
||||||
|
0x04, 0x12, 0x51, 0x61, 0x71, 0xff, 0xc4, 0x00, 0x14, 0x01, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11,
|
||||||
|
0x00, 0x3f, 0x00, 0x18, 0xa0, 0x0e, 0x6d, 0xbc, 0xf5, 0xca, 0xf7, 0x78,
|
||||||
|
0xb6, 0xfe, 0x3b, 0x23, 0xb2, 0x1d, 0x64, 0x68, 0xf0, 0x8a, 0x39, 0x4b,
|
||||||
|
0x74, 0x9c, 0xa5, 0x5f, 0x35, 0x8a, 0xb2, 0x7e, 0xa0, 0xff, 0xd9, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static const guint wilber_jpg_len = G_N_ELEMENTS (wilber_jpg);
|
||||||
|
|
||||||
|
|
||||||
|
GimpMetadata *
|
||||||
|
gimp_metadata_new (void)
|
||||||
|
{
|
||||||
|
GExiv2Metadata *metadata = NULL;
|
||||||
|
|
||||||
|
if (gexiv2_initialize ())
|
||||||
|
{
|
||||||
|
metadata = gexiv2_metadata_new ();
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_open_buf (metadata, wilber_jpg, wilber_jpg_len,
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
g_object_unref (metadata);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpMetadata *
|
||||||
|
gimp_metadata_duplicate (GimpMetadata *metadata)
|
||||||
|
{
|
||||||
|
GimpMetadata *new_metadata = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (metadata == NULL || GEXIV2_IS_METADATA (metadata), NULL);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
gchar *xml;
|
||||||
|
|
||||||
|
xml = gimp_metadata_serialize (metadata);
|
||||||
|
new_metadata = gimp_metadata_deserialize (xml);
|
||||||
|
g_free (xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar name[1024];
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
} GimpMetadataParseData;
|
||||||
|
|
||||||
|
static const gchar*
|
||||||
|
gimp_metadata_attribute_name_to_value (const gchar **attribute_names,
|
||||||
|
const gchar **attribute_values,
|
||||||
|
const gchar *name)
|
||||||
|
{
|
||||||
|
while (*attribute_names)
|
||||||
|
{
|
||||||
|
if (! strcmp (*attribute_names, name))
|
||||||
|
{
|
||||||
|
return *attribute_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_names++;
|
||||||
|
attribute_values++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_metadata_deserialize_start_element (GMarkupParseContext *context,
|
||||||
|
const gchar *element_name,
|
||||||
|
const gchar **attribute_names,
|
||||||
|
const gchar **attribute_values,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GimpMetadataParseData *parse_data = user_data;
|
||||||
|
|
||||||
|
if (! strcmp (element_name, "tag"))
|
||||||
|
{
|
||||||
|
const gchar *name;
|
||||||
|
|
||||||
|
name = gimp_metadata_attribute_name_to_value (attribute_names,
|
||||||
|
attribute_values,
|
||||||
|
"name");
|
||||||
|
|
||||||
|
if (! name)
|
||||||
|
{
|
||||||
|
g_set_error (error, gimp_metadata_error_quark (), 1001,
|
||||||
|
"Element 'tag' not contain required attribute 'name'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (parse_data->name, name, sizeof (parse_data->name));
|
||||||
|
parse_data->name[sizeof (parse_data->name) - 1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_metadata_deserialize_end_element (GMarkupParseContext *context,
|
||||||
|
const gchar *element_name,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_metadata_deserialize_text (GMarkupParseContext *context,
|
||||||
|
const gchar *text,
|
||||||
|
gsize text_len,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GimpMetadataParseData *parse_data = user_data;
|
||||||
|
const gchar *current_element;
|
||||||
|
|
||||||
|
current_element = g_markup_parse_context_get_element (context);
|
||||||
|
|
||||||
|
if (! g_strcmp0 (current_element, "tag"))
|
||||||
|
{
|
||||||
|
gchar *value = g_strndup (text, text_len);
|
||||||
|
|
||||||
|
gexiv2_metadata_set_tag_string (parse_data->metadata,
|
||||||
|
parse_data->name,
|
||||||
|
value);
|
||||||
|
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_metadata_deserialize_error (GMarkupParseContext *context,
|
||||||
|
GError *error,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_printerr ("Metadata parse error: %s\n", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes metadata from a string
|
||||||
|
**/
|
||||||
|
GExiv2Metadata *
|
||||||
|
gimp_metadata_deserialize (const gchar *metadata_xml)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
GMarkupParser markup_parser;
|
||||||
|
GimpMetadataParseData parse_data;
|
||||||
|
GMarkupParseContext *context;
|
||||||
|
|
||||||
|
g_return_val_if_fail (metadata_xml != NULL, NULL);
|
||||||
|
|
||||||
|
metadata = gimp_metadata_new ();
|
||||||
|
|
||||||
|
parse_data.metadata = metadata;
|
||||||
|
|
||||||
|
markup_parser.start_element = gimp_metadata_deserialize_start_element;
|
||||||
|
markup_parser.end_element = gimp_metadata_deserialize_end_element;
|
||||||
|
markup_parser.text = gimp_metadata_deserialize_text;
|
||||||
|
markup_parser.passthrough = NULL;
|
||||||
|
markup_parser.error = gimp_metadata_deserialize_error;
|
||||||
|
|
||||||
|
context = g_markup_parse_context_new (&markup_parser, 0, &parse_data, NULL);
|
||||||
|
|
||||||
|
g_markup_parse_context_parse (context,
|
||||||
|
metadata_xml, strlen (metadata_xml),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_markup_parse_context_unref (context);
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializing metadata as a string
|
||||||
|
*/
|
||||||
|
gchar *
|
||||||
|
gimp_metadata_serialize (GimpMetadata *metadata)
|
||||||
|
{
|
||||||
|
GString *string;
|
||||||
|
gchar **exif_data = NULL;
|
||||||
|
gchar **iptc_data = NULL;
|
||||||
|
gchar **xmp_data = NULL;
|
||||||
|
gchar *value;
|
||||||
|
gchar *escaped;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), NULL);
|
||||||
|
|
||||||
|
string = g_string_new (NULL);
|
||||||
|
|
||||||
|
g_string_append (string, "<?xml version='1.0' encoding='UTF-8'?>\n");
|
||||||
|
g_string_append (string, "<metadata>\n");
|
||||||
|
|
||||||
|
exif_data = gexiv2_metadata_get_exif_tags (metadata);
|
||||||
|
|
||||||
|
if (exif_data)
|
||||||
|
{
|
||||||
|
for (i = 0; exif_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (metadata, exif_data[i]);
|
||||||
|
escaped = g_markup_escape_text (value, -1);
|
||||||
|
|
||||||
|
g_string_append_printf (string, " <tag name=\"%s\">%s</tag>\n",
|
||||||
|
exif_data[i], escaped);
|
||||||
|
|
||||||
|
g_free (escaped);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (exif_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmp_data = gexiv2_metadata_get_xmp_tags (metadata);
|
||||||
|
|
||||||
|
if (xmp_data)
|
||||||
|
{
|
||||||
|
for (i = 0; xmp_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (metadata, xmp_data[i]);
|
||||||
|
escaped = g_markup_escape_text (value, -1);
|
||||||
|
|
||||||
|
g_string_append_printf (string, " <tag name=\"%s\">%s</tag>\n",
|
||||||
|
xmp_data[i], escaped);
|
||||||
|
|
||||||
|
g_free (escaped);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (xmp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
iptc_data = gexiv2_metadata_get_iptc_tags (metadata);
|
||||||
|
|
||||||
|
if (iptc_data)
|
||||||
|
{
|
||||||
|
for (i = 0; iptc_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (metadata, iptc_data[i]);
|
||||||
|
escaped = g_markup_escape_text (value, -1);
|
||||||
|
|
||||||
|
g_string_append_printf (string, " <tag name=\"%s\">%s</tag>\n",
|
||||||
|
iptc_data[i], escaped);
|
||||||
|
|
||||||
|
g_free (escaped);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (iptc_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append (string, "</metadata>\n");
|
||||||
|
|
||||||
|
return g_string_free (string, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reads metadata from a physical file
|
||||||
|
*/
|
||||||
|
GimpMetadata *
|
||||||
|
gimp_metadata_load_from_file (GFile *file,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GExiv2Metadata *meta = NULL;
|
||||||
|
gchar *path;
|
||||||
|
gchar *filename;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||||
|
|
||||||
|
path = g_file_get_path (file);
|
||||||
|
|
||||||
|
if (! path)
|
||||||
|
{
|
||||||
|
g_set_error (error, gimp_metadata_error_quark (), 0,
|
||||||
|
_("Can load metadata only from local files"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
filename = g_win32_locale_filename_from_utf8 (path);
|
||||||
|
#else
|
||||||
|
filename = g_strdup (path);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_free (path);
|
||||||
|
|
||||||
|
if (gexiv2_initialize ())
|
||||||
|
{
|
||||||
|
meta = gexiv2_metadata_new ();
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_open_path (meta, filename, error))
|
||||||
|
{
|
||||||
|
g_object_unref (meta);
|
||||||
|
g_free (filename);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (filename);
|
||||||
|
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* saves metadata to a physical file
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gimp_metadata_save_to_file (GimpMetadata *metadata,
|
||||||
|
GFile *file,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gchar *path;
|
||||||
|
gchar *filename;
|
||||||
|
gboolean success;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
|
||||||
|
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
|
path = g_file_get_path (file);
|
||||||
|
|
||||||
|
if (! path)
|
||||||
|
{
|
||||||
|
g_set_error (error, gimp_metadata_error_quark (), 0,
|
||||||
|
_("Can save metadata only from to files"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
filename = g_win32_locale_filename_from_utf8 (path);
|
||||||
|
#else
|
||||||
|
filename = g_strdup (path);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_free (path);
|
||||||
|
|
||||||
|
success = gexiv2_metadata_save_file (metadata, filename, error);
|
||||||
|
|
||||||
|
g_free (filename);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gimp_metadata_set_from_exif (GimpMetadata *metadata,
|
||||||
|
const guchar *exif_data,
|
||||||
|
gint exif_data_length,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
|
||||||
|
GByteArray *exif_bytes;
|
||||||
|
GimpMetadata *exif_metadata;
|
||||||
|
guint8 data_size[2] = { 0, };
|
||||||
|
|
||||||
|
g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
|
||||||
|
g_return_val_if_fail (exif_data != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (exif_data_length > 0, FALSE);
|
||||||
|
g_return_val_if_fail (exif_data_length < 65536, FALSE);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
|
data_size[0] = (exif_data_length & 0xFF00) >> 8;
|
||||||
|
data_size[1] = (exif_data_length & 0x00FF);
|
||||||
|
|
||||||
|
exif_bytes = g_byte_array_new ();
|
||||||
|
exif_bytes = g_byte_array_append (exif_bytes,
|
||||||
|
minimal_exif, G_N_ELEMENTS (minimal_exif));
|
||||||
|
exif_bytes = g_byte_array_append (exif_bytes,
|
||||||
|
data_size, 2);
|
||||||
|
exif_bytes = g_byte_array_append (exif_bytes,
|
||||||
|
(guint8 *) exif_data, exif_data_length);
|
||||||
|
|
||||||
|
exif_metadata = gimp_metadata_new ();
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_open_buf (exif_metadata,
|
||||||
|
exif_bytes->data, exif_bytes->len, error))
|
||||||
|
{
|
||||||
|
g_object_unref (exif_metadata);
|
||||||
|
g_byte_array_free (exif_bytes, TRUE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_has_exif (exif_metadata))
|
||||||
|
{
|
||||||
|
g_set_error (error, gimp_metadata_error_quark (), 0,
|
||||||
|
_("Parsing EXIF data failed."));
|
||||||
|
g_object_unref (exif_metadata);
|
||||||
|
g_byte_array_free (exif_bytes, TRUE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_metadata_add (exif_metadata, metadata);
|
||||||
|
g_object_unref (exif_metadata);
|
||||||
|
g_byte_array_free (exif_bytes, TRUE);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gimp_metadata_set_from_xmp (GimpMetadata *metadata,
|
||||||
|
const guchar *xmp_data,
|
||||||
|
gint xmp_data_length,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GimpMetadata *xmp_metadata;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
|
||||||
|
g_return_val_if_fail (xmp_data != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (xmp_data_length > 0, FALSE);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
|
xmp_data += 10;
|
||||||
|
xmp_data_length -= 10;
|
||||||
|
|
||||||
|
xmp_metadata = gimp_metadata_new ();
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_open_buf (xmp_metadata,
|
||||||
|
xmp_data, xmp_data_length, error))
|
||||||
|
{
|
||||||
|
g_object_unref (xmp_metadata);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_has_xmp (xmp_metadata))
|
||||||
|
{
|
||||||
|
g_set_error (error, gimp_metadata_error_quark (), 0,
|
||||||
|
_("Parsing XMP data failed."));
|
||||||
|
g_object_unref (xmp_metadata);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_metadata_add (xmp_metadata, metadata);
|
||||||
|
g_object_unref (xmp_metadata);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_metadata_set_pixel_size (GimpMetadata *metadata,
|
||||||
|
gint width,
|
||||||
|
gint height)
|
||||||
|
{
|
||||||
|
gchar buffer[32];
|
||||||
|
|
||||||
|
g_return_if_fail (GEXIV2_IS_METADATA (metadata));
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", width);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, "Exif.Image.ImageWidth", buffer);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", height);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, "Exif.Image.ImageLength", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_metadata_set_bits_per_sample (GimpMetadata *metadata,
|
||||||
|
gint bps)
|
||||||
|
{
|
||||||
|
gchar buffer[32];
|
||||||
|
|
||||||
|
g_return_if_fail (GEXIV2_IS_METADATA (metadata));
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d %d %d", bps, bps, bps);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, "Exif.Image.BitsPerSample", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets exif resolution
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gimp_metadata_get_resolution (GimpMetadata *metadata,
|
||||||
|
gdouble *xres,
|
||||||
|
gdouble *yres,
|
||||||
|
GimpUnit *unit)
|
||||||
|
{
|
||||||
|
gchar *xr;
|
||||||
|
gchar *yr;
|
||||||
|
gchar *un;
|
||||||
|
gint exif_unit = 2;
|
||||||
|
gchar **xnom = NULL;
|
||||||
|
gchar **xdenom = NULL;
|
||||||
|
gchar **ynom = NULL;
|
||||||
|
gchar **ydenom = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
|
||||||
|
|
||||||
|
xr = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.XResolution");
|
||||||
|
yr = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.YResolution");
|
||||||
|
|
||||||
|
if (! (xr && yr))
|
||||||
|
{
|
||||||
|
g_free (xr);
|
||||||
|
g_free (yr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
un = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.ResolutionUnit");
|
||||||
|
|
||||||
|
if (un)
|
||||||
|
{
|
||||||
|
exif_unit = atoi (un);
|
||||||
|
g_free (un);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exif_unit == 3)
|
||||||
|
*unit = GIMP_UNIT_MM;
|
||||||
|
else
|
||||||
|
*unit = GIMP_UNIT_INCH;
|
||||||
|
|
||||||
|
if (gimp_metadata_get_rational (xr, 1, &xnom, &xdenom))
|
||||||
|
{
|
||||||
|
gdouble x1 = g_ascii_strtod (xnom[0], NULL);
|
||||||
|
gdouble x2 = g_ascii_strtod (xdenom[0], NULL);
|
||||||
|
gdouble xrd;
|
||||||
|
|
||||||
|
if (x2 == 0.0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
xrd = x1 / x2;
|
||||||
|
|
||||||
|
if (exif_unit == 3)
|
||||||
|
xrd *= 2.54;
|
||||||
|
|
||||||
|
*xres = xrd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gimp_metadata_get_rational (yr, 1, &ynom, &ydenom))
|
||||||
|
{
|
||||||
|
gdouble y1 = g_ascii_strtod (ynom[0], NULL);
|
||||||
|
gdouble y2 = g_ascii_strtod (ydenom[0], NULL);
|
||||||
|
gdouble yrd;
|
||||||
|
|
||||||
|
if (y2 == 0.0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
yrd = y1 / y2;
|
||||||
|
|
||||||
|
if (exif_unit == 3)
|
||||||
|
yrd *= 2.54;
|
||||||
|
|
||||||
|
*yres = yrd;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (xr);
|
||||||
|
g_free (yr);
|
||||||
|
|
||||||
|
g_strfreev (xnom);
|
||||||
|
g_strfreev (xdenom);
|
||||||
|
g_strfreev (ynom);
|
||||||
|
g_strfreev (ydenom);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets exif resolution
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gimp_metadata_set_resolution (GimpMetadata *metadata,
|
||||||
|
gdouble xres,
|
||||||
|
gdouble yres,
|
||||||
|
GimpUnit unit)
|
||||||
|
{
|
||||||
|
gchar buffer[32];
|
||||||
|
gint exif_unit;
|
||||||
|
|
||||||
|
g_return_if_fail (GEXIV2_IS_METADATA (metadata));
|
||||||
|
|
||||||
|
if (gimp_unit_is_metric (unit))
|
||||||
|
{
|
||||||
|
xres /= 2.54;
|
||||||
|
yres /= 2.54;
|
||||||
|
|
||||||
|
exif_unit = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exif_unit = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ascii_formatd (buffer, sizeof (buffer), "%.0f/1", xres);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, "Exif.Image.XResolution", buffer);
|
||||||
|
|
||||||
|
g_ascii_formatd (buffer, sizeof (buffer), "%.0f/1", yres);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, "Exif.Image.YResolution", buffer);
|
||||||
|
|
||||||
|
g_snprintf (buffer, sizeof (buffer), "%d", exif_unit);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, "Exif.Image.ResolutionUnit", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks for supported tags
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gimp_metadata_is_tag_supported (const gchar *tag,
|
||||||
|
const gchar *mime_type)
|
||||||
|
{
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
g_return_val_if_fail (tag != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (mime_type != NULL, FALSE);
|
||||||
|
|
||||||
|
for (j = 0; j < G_N_ELEMENTS (unsupported_tags); j++)
|
||||||
|
{
|
||||||
|
if (g_str_has_prefix (tag, unsupported_tags[j]))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! strcmp (mime_type, "image/jpeg"))
|
||||||
|
{
|
||||||
|
for (j = 0; j < G_N_ELEMENTS (tiff_tags); j++)
|
||||||
|
{
|
||||||
|
if (g_str_has_prefix (tag, tiff_tags[j]))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (! strcmp (mime_type, "image/tiff"))
|
||||||
|
{
|
||||||
|
for (j = 0; j < G_N_ELEMENTS (jpeg_tags); j++)
|
||||||
|
{
|
||||||
|
if (g_str_has_prefix (tag, jpeg_tags[j]))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* private functions */
|
||||||
|
|
||||||
|
static GQuark
|
||||||
|
gimp_metadata_error_quark (void)
|
||||||
|
{
|
||||||
|
static GQuark quark = 0;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (quark == 0))
|
||||||
|
quark = g_quark_from_static_string ("gimp-metadata-error-quark");
|
||||||
|
|
||||||
|
return quark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determines the amount of delimiters in serialized
|
||||||
|
* metadata string
|
||||||
|
*/
|
||||||
|
static gint
|
||||||
|
gimp_metadata_length (const gchar *testline,
|
||||||
|
const gchar *delim)
|
||||||
|
{
|
||||||
|
gchar *delim_test;
|
||||||
|
gint i;
|
||||||
|
gint sum;
|
||||||
|
|
||||||
|
delim_test = g_strdup (testline);
|
||||||
|
|
||||||
|
sum =0;
|
||||||
|
|
||||||
|
for (i=0; i < strlen (delim_test); i++)
|
||||||
|
{
|
||||||
|
if (delim_test[i] == delim[0])
|
||||||
|
sum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (delim_test);
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets rational values from string
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gimp_metadata_get_rational (const gchar *value,
|
||||||
|
gint sections,
|
||||||
|
gchar ***numerator,
|
||||||
|
gchar ***denominator)
|
||||||
|
{
|
||||||
|
GSList *nomlist = NULL;
|
||||||
|
GSList *denomlist = NULL;
|
||||||
|
|
||||||
|
GSList *nlist, *dlist;
|
||||||
|
|
||||||
|
gchar sect[] = " ";
|
||||||
|
gchar rdel[] = "/";
|
||||||
|
gchar **sects;
|
||||||
|
gchar **nom = NULL;
|
||||||
|
gint i;
|
||||||
|
gint n;
|
||||||
|
|
||||||
|
gchar **num;
|
||||||
|
gchar **den;
|
||||||
|
|
||||||
|
if (! value)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (gimp_metadata_length (value, sect) == (sections -1))
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
sects = g_strsplit (value, sect, -1);
|
||||||
|
while (sects[i] != NULL)
|
||||||
|
{
|
||||||
|
if(gimp_metadata_length (sects[i], rdel) == 1)
|
||||||
|
{
|
||||||
|
nom = g_strsplit (sects[i], rdel, -1);
|
||||||
|
nomlist = g_slist_prepend (nomlist, g_strdup (nom[0]));
|
||||||
|
denomlist = g_slist_prepend (denomlist, g_strdup (nom[1]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = i;
|
||||||
|
|
||||||
|
num = g_new0 (gchar*, i + 1);
|
||||||
|
den = g_new0 (gchar*, n + 1);
|
||||||
|
|
||||||
|
for (nlist = nomlist; nlist; nlist = nlist->next)
|
||||||
|
num[--i] = nlist->data;
|
||||||
|
|
||||||
|
for (dlist = denomlist; dlist; dlist = dlist->next)
|
||||||
|
den[--n] = dlist->data;
|
||||||
|
|
||||||
|
*numerator = num;
|
||||||
|
*denominator = den;
|
||||||
|
|
||||||
|
g_slist_free (nomlist);
|
||||||
|
g_slist_free (denomlist);
|
||||||
|
|
||||||
|
g_strfreev (sects);
|
||||||
|
g_strfreev (nom);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_metadata_add (GimpMetadata *src,
|
||||||
|
GimpMetadata *dest)
|
||||||
|
{
|
||||||
|
gchar *value;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
if (gexiv2_metadata_get_supports_exif (src) &&
|
||||||
|
gexiv2_metadata_get_supports_exif (dest))
|
||||||
|
{
|
||||||
|
gchar **exif_data = gexiv2_metadata_get_exif_tags (src);
|
||||||
|
|
||||||
|
if (exif_data)
|
||||||
|
{
|
||||||
|
for (i = 0; exif_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (src, exif_data[i]);
|
||||||
|
gexiv2_metadata_set_tag_string (dest, exif_data[i], value);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (exif_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (gexiv2_metadata_get_supports_xmp (src) &&
|
||||||
|
gexiv2_metadata_get_supports_xmp (dest))
|
||||||
|
{
|
||||||
|
gchar **xmp_data = gexiv2_metadata_get_xmp_tags (src);
|
||||||
|
|
||||||
|
if (xmp_data)
|
||||||
|
{
|
||||||
|
for (i = 0; xmp_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (src, xmp_data[i]);
|
||||||
|
gexiv2_metadata_set_tag_string (dest, xmp_data[i], value);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (xmp_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gexiv2_metadata_get_supports_iptc (src) &&
|
||||||
|
gexiv2_metadata_get_supports_iptc (dest))
|
||||||
|
{
|
||||||
|
gchar **iptc_data = gexiv2_metadata_get_iptc_tags (src);
|
||||||
|
|
||||||
|
if (iptc_data)
|
||||||
|
{
|
||||||
|
for (i = 0; iptc_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
value = gexiv2_metadata_get_tag_string (src, iptc_data[i]);
|
||||||
|
gexiv2_metadata_set_tag_string (dest, iptc_data[i], value);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (iptc_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
libgimpbase/gimpmetadata.h
Normal file
82
libgimpbase/gimpmetadata.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* LIBGIMPBASE - The GIMP Basic Library
|
||||||
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||||||
|
*
|
||||||
|
* gimpmetadata.h
|
||||||
|
* Copyright (C) 2013 Hartmut Kuhse <hartmutkuhse@src.gnome.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 3 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
|
||||||
|
* Lesser 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, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GIMP_METADATA_H__
|
||||||
|
#define __GIMP_METADATA_H__
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GIMP_METADATA_SAVE_EXIF = 1 << 0,
|
||||||
|
GIMP_METADATA_SAVE_XMP = 1 << 1,
|
||||||
|
GIMP_METADATA_SAVE_IPTC = 1 << 2,
|
||||||
|
GIMP_METADATA_SAVE_THUMBNAIL = 1 << 3,
|
||||||
|
|
||||||
|
GIMP_METADATA_SAVE_ALL = (GIMP_METADATA_SAVE_EXIF |
|
||||||
|
GIMP_METADATA_SAVE_XMP |
|
||||||
|
GIMP_METADATA_SAVE_IPTC |
|
||||||
|
GIMP_METADATA_SAVE_THUMBNAIL)
|
||||||
|
} GimpMetadataSaveFlags;
|
||||||
|
|
||||||
|
GimpMetadata * gimp_metadata_new (void);
|
||||||
|
GimpMetadata * gimp_metadata_duplicate (GimpMetadata *metadata);
|
||||||
|
|
||||||
|
GimpMetadata * gimp_metadata_deserialize (const gchar *metadata_xml);
|
||||||
|
gchar * gimp_metadata_serialize (GimpMetadata *metadata);
|
||||||
|
|
||||||
|
GimpMetadata * gimp_metadata_load_from_file (GFile *file,
|
||||||
|
GError **error);
|
||||||
|
gboolean gimp_metadata_save_to_file (GimpMetadata *metadata,
|
||||||
|
GFile *file,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean gimp_metadata_set_from_exif (GimpMetadata *metadata,
|
||||||
|
const guchar *exif_data,
|
||||||
|
gint exif_data_length,
|
||||||
|
GError **error);
|
||||||
|
gboolean gimp_metadata_set_from_xmp (GimpMetadata *metadata,
|
||||||
|
const guchar *xmp_data,
|
||||||
|
gint xmp_data_length,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void gimp_metadata_set_pixel_size (GimpMetadata *metadata,
|
||||||
|
gint width,
|
||||||
|
gint height);
|
||||||
|
void gimp_metadata_set_bits_per_sample (GimpMetadata *metadata,
|
||||||
|
gint bits_per_sample);
|
||||||
|
|
||||||
|
gboolean gimp_metadata_get_resolution (GimpMetadata *metadata,
|
||||||
|
gdouble *xres,
|
||||||
|
gdouble *yres,
|
||||||
|
GimpUnit *unit);
|
||||||
|
void gimp_metadata_set_resolution (GimpMetadata *metadata,
|
||||||
|
gdouble xres,
|
||||||
|
gdouble yres,
|
||||||
|
GimpUnit unit);
|
||||||
|
|
||||||
|
gboolean gimp_metadata_is_tag_supported (const gchar *tag,
|
||||||
|
const gchar *mime_type);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GIMP_METADATA_H__ */
|
|
@ -51,11 +51,6 @@ else
|
||||||
file_uri = file-uri
|
file_uri = file-uri
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if HAVE_LIBEXIF
|
|
||||||
metadata = metadata
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
$(script_fu) \
|
$(script_fu) \
|
||||||
$(pygimp) \
|
$(pygimp) \
|
||||||
|
@ -83,7 +78,6 @@ SUBDIRS = \
|
||||||
lighting \
|
lighting \
|
||||||
map-object \
|
map-object \
|
||||||
maze \
|
maze \
|
||||||
$(metadata) \
|
|
||||||
pagecurl \
|
pagecurl \
|
||||||
$(print) \
|
$(print) \
|
||||||
selection-to-path \
|
selection-to-path \
|
||||||
|
|
2
plug-ins/common/.gitignore
vendored
2
plug-ins/common/.gitignore
vendored
|
@ -182,6 +182,8 @@
|
||||||
/mail.exe
|
/mail.exe
|
||||||
/max-rgb
|
/max-rgb
|
||||||
/max-rgb.exe
|
/max-rgb.exe
|
||||||
|
/metadata
|
||||||
|
/metadata.exe
|
||||||
/newsprint
|
/newsprint
|
||||||
/newsprint.exe
|
/newsprint.exe
|
||||||
/nl-filter
|
/nl-filter
|
||||||
|
|
|
@ -134,6 +134,7 @@ libexec_PROGRAMS = \
|
||||||
lens-flare \
|
lens-flare \
|
||||||
$(MAIL) \
|
$(MAIL) \
|
||||||
max-rgb \
|
max-rgb \
|
||||||
|
metadata \
|
||||||
newsprint \
|
newsprint \
|
||||||
nl-filter \
|
nl-filter \
|
||||||
noise-rgb \
|
noise-rgb \
|
||||||
|
@ -1090,13 +1091,15 @@ file_jp2_load_SOURCES = \
|
||||||
file-jp2-load.c
|
file-jp2-load.c
|
||||||
|
|
||||||
file_jp2_load_LDADD = \
|
file_jp2_load_LDADD = \
|
||||||
|
$(libgimpui) \
|
||||||
|
$(libgimpwidgets) \
|
||||||
|
$(libgimpmodule) \
|
||||||
$(libgimp) \
|
$(libgimp) \
|
||||||
$(libgimpmath) \
|
$(libgimpmath) \
|
||||||
$(libgimpconfig) \
|
$(libgimpconfig) \
|
||||||
$(libgimpcolor) \
|
$(libgimpcolor) \
|
||||||
$(libgimpbase) \
|
$(libgimpbase) \
|
||||||
$(CAIRO_LIBS) \
|
$(GTK_LIBS) \
|
||||||
$(GDK_PIXBUF_LIBS) \
|
|
||||||
$(GEGL_LIBS) \
|
$(GEGL_LIBS) \
|
||||||
$(JP2_LIBS) \
|
$(JP2_LIBS) \
|
||||||
$(RT_LIBS) \
|
$(RT_LIBS) \
|
||||||
|
@ -1773,6 +1776,26 @@ max_rgb_LDADD = \
|
||||||
$(INTLLIBS) \
|
$(INTLLIBS) \
|
||||||
$(max_rgb_RC)
|
$(max_rgb_RC)
|
||||||
|
|
||||||
|
metadata_CFLAGS = $(GEXIV2_CFLAGS)
|
||||||
|
|
||||||
|
metadata_SOURCES = \
|
||||||
|
metadata.c
|
||||||
|
|
||||||
|
metadata_LDADD = \
|
||||||
|
$(libgimpui) \
|
||||||
|
$(libgimpwidgets) \
|
||||||
|
$(libgimpmodule) \
|
||||||
|
$(libgimp) \
|
||||||
|
$(libgimpmath) \
|
||||||
|
$(libgimpconfig) \
|
||||||
|
$(libgimpcolor) \
|
||||||
|
$(libgimpbase) \
|
||||||
|
$(GTK_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
|
$(RT_LIBS) \
|
||||||
|
$(INTLLIBS) \
|
||||||
|
$(metadata_RC)
|
||||||
|
|
||||||
newsprint_SOURCES = \
|
newsprint_SOURCES = \
|
||||||
newsprint.c
|
newsprint.c
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@
|
||||||
#include <jasper/jasper.h>
|
#include <jasper/jasper.h>
|
||||||
|
|
||||||
|
|
||||||
#define LOAD_PROC "file-jp2-load"
|
#define LOAD_PROC "file-jp2-load"
|
||||||
|
#define PLUG_IN_BINARY "file-jp2-load"
|
||||||
|
|
||||||
|
|
||||||
static void query (void);
|
static void query (void);
|
||||||
|
@ -120,10 +121,13 @@ run (const gchar *name,
|
||||||
GimpParam **return_vals)
|
GimpParam **return_vals)
|
||||||
{
|
{
|
||||||
static GimpParam values[2];
|
static GimpParam values[2];
|
||||||
|
GimpRunMode run_mode;
|
||||||
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
||||||
gint image_ID;
|
gint image_ID;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
|
run_mode = param[0].data.d_int32;
|
||||||
|
|
||||||
INIT_I18N ();
|
INIT_I18N ();
|
||||||
gegl_init (NULL, NULL);
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
@ -135,10 +139,31 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (strcmp (name, LOAD_PROC) == 0)
|
if (strcmp (name, LOAD_PROC) == 0)
|
||||||
{
|
{
|
||||||
|
gboolean interactive;
|
||||||
|
|
||||||
|
switch (run_mode)
|
||||||
|
{
|
||||||
|
case GIMP_RUN_INTERACTIVE:
|
||||||
|
case GIMP_RUN_WITH_LAST_VALS:
|
||||||
|
gimp_ui_init (PLUG_IN_BINARY, FALSE);
|
||||||
|
interactive = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interactive = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
image_ID = load_image (param[1].data.d_string, &error);
|
image_ID = load_image (param[1].data.d_string, &error);
|
||||||
|
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
{
|
{
|
||||||
|
GFile *file = g_file_new_for_path (param[1].data.d_string);
|
||||||
|
|
||||||
|
gimp_image_metadata_load (image_ID, "image/jp2", file,
|
||||||
|
interactive);
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
*nreturn_vals = 2;
|
*nreturn_vals = 2;
|
||||||
values[1].type = GIMP_PDB_IMAGE;
|
values[1].type = GIMP_PDB_IMAGE;
|
||||||
values[1].data.d_image = image_ID;
|
values[1].data.d_image = image_ID;
|
||||||
|
|
|
@ -88,6 +88,10 @@ typedef struct
|
||||||
gboolean comment;
|
gboolean comment;
|
||||||
gboolean save_transp_pixels;
|
gboolean save_transp_pixels;
|
||||||
gint compression_level;
|
gint compression_level;
|
||||||
|
gboolean save_exif;
|
||||||
|
gboolean save_xmp;
|
||||||
|
gboolean save_iptc;
|
||||||
|
gboolean save_thumbnail;
|
||||||
}
|
}
|
||||||
PngSaveVals;
|
PngSaveVals;
|
||||||
|
|
||||||
|
@ -104,6 +108,10 @@ typedef struct
|
||||||
GtkWidget *comment;
|
GtkWidget *comment;
|
||||||
GtkWidget *save_transp_pixels;
|
GtkWidget *save_transp_pixels;
|
||||||
GtkAdjustment *compression_level;
|
GtkAdjustment *compression_level;
|
||||||
|
GtkWidget *save_exif;
|
||||||
|
GtkWidget *save_xmp;
|
||||||
|
GtkWidget *save_iptc;
|
||||||
|
GtkWidget *save_thumbnail;
|
||||||
}
|
}
|
||||||
PngSaveGui;
|
PngSaveGui;
|
||||||
|
|
||||||
|
@ -119,6 +127,7 @@ typedef struct
|
||||||
}
|
}
|
||||||
PngGlobals;
|
PngGlobals;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local functions...
|
* Local functions...
|
||||||
*/
|
*/
|
||||||
|
@ -164,6 +173,7 @@ static void load_defaults (void);
|
||||||
static void save_defaults (void);
|
static void save_defaults (void);
|
||||||
static void load_gui_defaults (PngSaveGui *pg);
|
static void load_gui_defaults (PngSaveGui *pg);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Globals...
|
* Globals...
|
||||||
*/
|
*/
|
||||||
|
@ -186,11 +196,15 @@ static const PngSaveVals defaults =
|
||||||
TRUE,
|
TRUE,
|
||||||
TRUE,
|
TRUE,
|
||||||
TRUE,
|
TRUE,
|
||||||
9
|
9,
|
||||||
|
TRUE, /* save exif */
|
||||||
|
TRUE, /* save xmp */
|
||||||
|
TRUE, /* save iptc */
|
||||||
|
TRUE /* save thumbnail */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PngSaveVals pngvals;
|
static PngSaveVals pngvals;
|
||||||
static PngGlobals pngg;
|
static PngGlobals pngg;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -406,6 +420,8 @@ run (const gchar *name,
|
||||||
GimpExportReturn export = GIMP_EXPORT_CANCEL;
|
GimpExportReturn export = GIMP_EXPORT_CANCEL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
|
run_mode = param[0].data.d_int32;
|
||||||
|
|
||||||
INIT_I18N ();
|
INIT_I18N ();
|
||||||
gegl_init (NULL, NULL);
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
@ -417,13 +433,32 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (strcmp (name, LOAD_PROC) == 0)
|
if (strcmp (name, LOAD_PROC) == 0)
|
||||||
{
|
{
|
||||||
run_mode = param[0].data.d_int32;
|
gboolean interactive;
|
||||||
|
|
||||||
|
switch (run_mode)
|
||||||
|
{
|
||||||
|
case GIMP_RUN_INTERACTIVE:
|
||||||
|
case GIMP_RUN_WITH_LAST_VALS:
|
||||||
|
gimp_ui_init (PLUG_IN_BINARY, FALSE);
|
||||||
|
interactive = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interactive = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
image_ID = load_image (param[1].data.d_string,
|
image_ID = load_image (param[1].data.d_string,
|
||||||
run_mode == GIMP_RUN_INTERACTIVE, &error);
|
interactive, &error);
|
||||||
|
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
{
|
{
|
||||||
|
GFile *file = g_file_new_for_path (param[1].data.d_string);
|
||||||
|
|
||||||
|
gimp_image_metadata_load (image_ID, "image/png", file,
|
||||||
|
interactive);
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
*nreturn_vals = 2;
|
*nreturn_vals = 2;
|
||||||
values[1].type = GIMP_PDB_IMAGE;
|
values[1].type = GIMP_PDB_IMAGE;
|
||||||
values[1].data.d_image = image_ID;
|
values[1].data.d_image = image_ID;
|
||||||
|
@ -439,7 +474,6 @@ run (const gchar *name,
|
||||||
{
|
{
|
||||||
gboolean alpha;
|
gboolean alpha;
|
||||||
|
|
||||||
run_mode = param[0].data.d_int32;
|
|
||||||
image_ID = orig_image_ID = param[1].data.d_int32;
|
image_ID = orig_image_ID = param[1].data.d_int32;
|
||||||
drawable_ID = param[2].data.d_int32;
|
drawable_ID = param[2].data.d_int32;
|
||||||
|
|
||||||
|
@ -549,6 +583,33 @@ run (const gchar *name,
|
||||||
if (save_image (param[3].data.d_string,
|
if (save_image (param[3].data.d_string,
|
||||||
image_ID, drawable_ID, orig_image_ID, &error))
|
image_ID, drawable_ID, orig_image_ID, &error))
|
||||||
{
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_image_metadata_save_prepare (image_ID,
|
||||||
|
"image/png");
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
GimpMetadataSaveFlags flags = 0;
|
||||||
|
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 8);
|
||||||
|
|
||||||
|
if (pngvals.save_exif) flags |= GIMP_METADATA_SAVE_EXIF;
|
||||||
|
if (pngvals.save_xmp) flags |= GIMP_METADATA_SAVE_XMP;
|
||||||
|
if (pngvals.save_iptc) flags |= GIMP_METADATA_SAVE_IPTC;
|
||||||
|
if (pngvals.save_thumbnail) flags |= GIMP_METADATA_SAVE_THUMBNAIL;
|
||||||
|
|
||||||
|
file = g_file_new_for_path (param[3].data.d_string);
|
||||||
|
gimp_image_metadata_save_finish (image_ID,
|
||||||
|
"image/png",
|
||||||
|
metadata, file, flags,
|
||||||
|
NULL);
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
gimp_set_data (SAVE_PROC, &pngvals, sizeof (pngvals));
|
gimp_set_data (SAVE_PROC, &pngvals, sizeof (pngvals));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -587,6 +648,8 @@ run (const gchar *name,
|
||||||
{
|
{
|
||||||
if (nparams == 9)
|
if (nparams == 9)
|
||||||
{
|
{
|
||||||
|
load_defaults ();
|
||||||
|
|
||||||
pngvals.interlaced = param[0].data.d_int32;
|
pngvals.interlaced = param[0].data.d_int32;
|
||||||
pngvals.compression_level = param[1].data.d_int32;
|
pngvals.compression_level = param[1].data.d_int32;
|
||||||
pngvals.bkgd = param[2].data.d_int32;
|
pngvals.bkgd = param[2].data.d_int32;
|
||||||
|
@ -2059,7 +2122,7 @@ save_dialog (gint32 image_ID,
|
||||||
/* Table */
|
/* Table */
|
||||||
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
|
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
|
||||||
GTK_WIDGET (gtk_builder_get_object (builder, "table")),
|
GTK_WIDGET (gtk_builder_get_object (builder, "table")),
|
||||||
TRUE, TRUE, 0);
|
FALSE, FALSE, 0);
|
||||||
|
|
||||||
/* Toggles */
|
/* Toggles */
|
||||||
pg.interlaced = toggle_button_init (builder, "interlace",
|
pg.interlaced = toggle_button_init (builder, "interlace",
|
||||||
|
@ -2080,6 +2143,18 @@ save_dialog (gint32 image_ID,
|
||||||
pg.time = toggle_button_init (builder, "save-creation-time",
|
pg.time = toggle_button_init (builder, "save-creation-time",
|
||||||
pngvals.time,
|
pngvals.time,
|
||||||
&pngvals.time);
|
&pngvals.time);
|
||||||
|
pg.save_exif = toggle_button_init (builder, "sv_exif",
|
||||||
|
pngvals.save_exif,
|
||||||
|
&pngvals.save_exif);
|
||||||
|
pg.save_xmp = toggle_button_init (builder, "sv_xmp",
|
||||||
|
pngvals.save_xmp,
|
||||||
|
&pngvals.save_xmp);
|
||||||
|
pg.save_iptc = toggle_button_init (builder, "sv_iptc",
|
||||||
|
pngvals.save_iptc,
|
||||||
|
&pngvals.save_iptc);
|
||||||
|
pg.save_thumbnail = toggle_button_init (builder, "sv_thumbnail",
|
||||||
|
pngvals.save_thumbnail,
|
||||||
|
&pngvals.save_thumbnail);
|
||||||
|
|
||||||
/* Comment toggle */
|
/* Comment toggle */
|
||||||
parasite = gimp_image_get_parasite (image_ID, "gimp-comment");
|
parasite = gimp_image_get_parasite (image_ID, "gimp-comment");
|
||||||
|
@ -2150,12 +2225,15 @@ load_defaults (void)
|
||||||
{
|
{
|
||||||
GimpParasite *parasite;
|
GimpParasite *parasite;
|
||||||
|
|
||||||
|
/* initialize with hardcoded defaults */
|
||||||
|
pngvals = defaults;
|
||||||
|
|
||||||
parasite = gimp_get_parasite (PNG_DEFAULTS_PARASITE);
|
parasite = gimp_get_parasite (PNG_DEFAULTS_PARASITE);
|
||||||
|
|
||||||
if (parasite)
|
if (parasite)
|
||||||
{
|
{
|
||||||
gchar *def_str;
|
gchar *def_str;
|
||||||
PngSaveVals tmpvals;
|
PngSaveVals tmpvals = defaults;
|
||||||
gint num_fields;
|
gint num_fields;
|
||||||
|
|
||||||
def_str = g_strndup (gimp_parasite_data (parasite),
|
def_str = g_strndup (gimp_parasite_data (parasite),
|
||||||
|
@ -2163,7 +2241,7 @@ load_defaults (void)
|
||||||
|
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
|
|
||||||
num_fields = sscanf (def_str, "%d %d %d %d %d %d %d %d %d",
|
num_fields = sscanf (def_str, "%d %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||||
&tmpvals.interlaced,
|
&tmpvals.interlaced,
|
||||||
&tmpvals.bkgd,
|
&tmpvals.bkgd,
|
||||||
&tmpvals.gama,
|
&tmpvals.gama,
|
||||||
|
@ -2172,18 +2250,17 @@ load_defaults (void)
|
||||||
&tmpvals.time,
|
&tmpvals.time,
|
||||||
&tmpvals.comment,
|
&tmpvals.comment,
|
||||||
&tmpvals.save_transp_pixels,
|
&tmpvals.save_transp_pixels,
|
||||||
&tmpvals.compression_level);
|
&tmpvals.compression_level,
|
||||||
|
&tmpvals.save_exif,
|
||||||
|
&tmpvals.save_xmp,
|
||||||
|
&tmpvals.save_iptc,
|
||||||
|
&tmpvals.save_thumbnail);
|
||||||
|
|
||||||
g_free (def_str);
|
g_free (def_str);
|
||||||
|
|
||||||
if (num_fields == 9)
|
if (num_fields == 9 || num_fields == 13)
|
||||||
{
|
pngvals = tmpvals;
|
||||||
memcpy (&pngvals, &tmpvals, sizeof (tmpvals));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (&pngvals, &defaults, sizeof (defaults));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2192,7 +2269,7 @@ save_defaults (void)
|
||||||
GimpParasite *parasite;
|
GimpParasite *parasite;
|
||||||
gchar *def_str;
|
gchar *def_str;
|
||||||
|
|
||||||
def_str = g_strdup_printf ("%d %d %d %d %d %d %d %d %d",
|
def_str = g_strdup_printf ("%d %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||||
pngvals.interlaced,
|
pngvals.interlaced,
|
||||||
pngvals.bkgd,
|
pngvals.bkgd,
|
||||||
pngvals.gama,
|
pngvals.gama,
|
||||||
|
@ -2201,7 +2278,11 @@ save_defaults (void)
|
||||||
pngvals.time,
|
pngvals.time,
|
||||||
pngvals.comment,
|
pngvals.comment,
|
||||||
pngvals.save_transp_pixels,
|
pngvals.save_transp_pixels,
|
||||||
pngvals.compression_level);
|
pngvals.compression_level,
|
||||||
|
pngvals.save_exif,
|
||||||
|
pngvals.save_xmp,
|
||||||
|
pngvals.save_iptc,
|
||||||
|
pngvals.save_thumbnail);
|
||||||
|
|
||||||
parasite = gimp_parasite_new (PNG_DEFAULTS_PARASITE,
|
parasite = gimp_parasite_new (PNG_DEFAULTS_PARASITE,
|
||||||
GIMP_PARASITE_PERSISTENT,
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
@ -2230,6 +2311,10 @@ load_gui_defaults (PngSaveGui *pg)
|
||||||
SET_ACTIVE (time);
|
SET_ACTIVE (time);
|
||||||
SET_ACTIVE (comment);
|
SET_ACTIVE (comment);
|
||||||
SET_ACTIVE (save_transp_pixels);
|
SET_ACTIVE (save_transp_pixels);
|
||||||
|
SET_ACTIVE (save_exif);
|
||||||
|
SET_ACTIVE (save_xmp);
|
||||||
|
SET_ACTIVE (save_iptc);
|
||||||
|
SET_ACTIVE (save_thumbnail);
|
||||||
|
|
||||||
#undef SET_ACTIVE
|
#undef SET_ACTIVE
|
||||||
|
|
||||||
|
|
|
@ -280,6 +280,13 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (image != -1)
|
if (image != -1)
|
||||||
{
|
{
|
||||||
|
GFile *file = g_file_new_for_path (param[1].data.d_string);
|
||||||
|
|
||||||
|
gimp_image_metadata_load (image, "image/tiff", file,
|
||||||
|
run_mode == GIMP_RUN_INTERACTIVE);
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
*nreturn_vals = 2;
|
*nreturn_vals = 2;
|
||||||
values[1].type = GIMP_PDB_IMAGE;
|
values[1].type = GIMP_PDB_IMAGE;
|
||||||
values[1].data.d_image = image;
|
values[1].data.d_image = image;
|
||||||
|
|
|
@ -82,6 +82,10 @@ typedef struct
|
||||||
gint compression;
|
gint compression;
|
||||||
gint fillorder;
|
gint fillorder;
|
||||||
gboolean save_transp_pixels;
|
gboolean save_transp_pixels;
|
||||||
|
gboolean save_exif;
|
||||||
|
gboolean save_xmp;
|
||||||
|
gboolean save_iptc;
|
||||||
|
gboolean save_thumbnail;
|
||||||
} TiffSaveVals;
|
} TiffSaveVals;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -110,6 +114,7 @@ static gboolean save_image (const gchar *filename,
|
||||||
gint32 image,
|
gint32 image,
|
||||||
gint32 drawable,
|
gint32 drawable,
|
||||||
gint32 orig_image,
|
gint32 orig_image,
|
||||||
|
gint *saved_bpp,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
static gboolean save_dialog (gboolean has_alpha,
|
static gboolean save_dialog (gboolean has_alpha,
|
||||||
|
@ -143,8 +148,13 @@ const GimpPlugInInfo PLUG_IN_INFO =
|
||||||
|
|
||||||
static TiffSaveVals tsvals =
|
static TiffSaveVals tsvals =
|
||||||
{
|
{
|
||||||
COMPRESSION_NONE, /* compression */
|
COMPRESSION_NONE, /* compression */
|
||||||
TRUE, /* alpha handling */
|
TRUE, /* alpha handling */
|
||||||
|
TRUE, /* save transp. pixels */
|
||||||
|
TRUE, /* save exif */
|
||||||
|
TRUE, /* save xmp */
|
||||||
|
TRUE, /* save iptc */
|
||||||
|
TRUE /* save thumbnail */
|
||||||
};
|
};
|
||||||
|
|
||||||
static gchar *image_comment = NULL;
|
static gchar *image_comment = NULL;
|
||||||
|
@ -346,9 +356,38 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (status == GIMP_PDB_SUCCESS)
|
if (status == GIMP_PDB_SUCCESS)
|
||||||
{
|
{
|
||||||
|
gint saved_bpp;
|
||||||
|
|
||||||
if (save_image (param[3].data.d_string, image, drawable, orig_image,
|
if (save_image (param[3].data.d_string, image, drawable, orig_image,
|
||||||
&error))
|
&saved_bpp, &error))
|
||||||
{
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_image_metadata_save_prepare (image,
|
||||||
|
"image/tiff");
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
GimpMetadataSaveFlags flags = 0;
|
||||||
|
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, saved_bpp);
|
||||||
|
|
||||||
|
if (tsvals.save_exif) flags |= GIMP_METADATA_SAVE_EXIF;
|
||||||
|
if (tsvals.save_xmp) flags |= GIMP_METADATA_SAVE_XMP;
|
||||||
|
if (tsvals.save_iptc) flags |= GIMP_METADATA_SAVE_IPTC;
|
||||||
|
if (tsvals.save_thumbnail) flags |= GIMP_METADATA_SAVE_THUMBNAIL;
|
||||||
|
|
||||||
|
file = g_file_new_for_path (param[3].data.d_string);
|
||||||
|
gimp_image_metadata_save_finish (image,
|
||||||
|
"image/tiff",
|
||||||
|
metadata, file, flags,
|
||||||
|
NULL);
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/* Store mvals data */
|
/* Store mvals data */
|
||||||
gimp_set_data (SAVE_PROC, &tsvals, sizeof (TiffSaveVals));
|
gimp_set_data (SAVE_PROC, &tsvals, sizeof (TiffSaveVals));
|
||||||
}
|
}
|
||||||
|
@ -657,6 +696,7 @@ save_image (const gchar *filename,
|
||||||
gint32 image,
|
gint32 image,
|
||||||
gint32 layer,
|
gint32 layer,
|
||||||
gint32 orig_image, /* the export function might have */
|
gint32 orig_image, /* the export function might have */
|
||||||
|
gint *saved_bpp,
|
||||||
GError **error) /* created a duplicate */
|
GError **error) /* created a duplicate */
|
||||||
{
|
{
|
||||||
gboolean status = FALSE;
|
gboolean status = FALSE;
|
||||||
|
@ -725,6 +765,8 @@ save_image (const gchar *filename,
|
||||||
else
|
else
|
||||||
bitspersample = 16;
|
bitspersample = 16;
|
||||||
|
|
||||||
|
*saved_bpp = bitspersample;
|
||||||
|
|
||||||
drawable_type = gimp_drawable_type (layer);
|
drawable_type = gimp_drawable_type (layer);
|
||||||
buffer = gimp_drawable_get_buffer (layer);
|
buffer = gimp_drawable_get_buffer (layer);
|
||||||
|
|
||||||
|
@ -1075,25 +1117,44 @@ static gboolean
|
||||||
save_dialog (gboolean has_alpha,
|
save_dialog (gboolean has_alpha,
|
||||||
gboolean is_monochrome)
|
gboolean is_monochrome)
|
||||||
{
|
{
|
||||||
GtkWidget *dialog;
|
GError *error = NULL;
|
||||||
GtkWidget *vbox;
|
GtkWidget *dialog;
|
||||||
GtkWidget *frame;
|
GtkWidget *vbox;
|
||||||
GtkWidget *hbox;
|
GtkWidget *frame;
|
||||||
GtkWidget *label;
|
GtkWidget *entry;
|
||||||
GtkWidget *entry;
|
GtkWidget *toggle;
|
||||||
GtkWidget *toggle;
|
GtkWidget *cmp_g3;
|
||||||
GtkWidget *g3;
|
GtkWidget *cmp_g4;
|
||||||
GtkWidget *g4;
|
GtkBuilder *builder;
|
||||||
gboolean run;
|
gchar *ui_file;
|
||||||
|
gboolean run;
|
||||||
|
|
||||||
dialog = gimp_export_dialog_new (_("TIFF"), PLUG_IN_BINARY, SAVE_PROC);
|
dialog = gimp_export_dialog_new (_("TIFF"), PLUG_IN_BINARY, SAVE_PROC);
|
||||||
|
|
||||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
builder = gtk_builder_new ();
|
||||||
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
|
ui_file = g_build_filename (gimp_data_directory (),
|
||||||
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
|
"ui", "plug-ins", "plug-in-file-tiff.ui",
|
||||||
vbox, FALSE, TRUE, 0);
|
NULL);
|
||||||
|
if (! gtk_builder_add_from_file (builder, ui_file, &error))
|
||||||
|
{
|
||||||
|
gchar *display_name = g_filename_display_name (ui_file);
|
||||||
|
|
||||||
|
g_printerr (_("Error loading UI file '%s': %s"),
|
||||||
|
display_name, error ? error->message : _("Unknown error"));
|
||||||
|
|
||||||
|
g_free (display_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (ui_file);
|
||||||
|
|
||||||
|
vbox = GTK_WIDGET (gtk_builder_get_object (builder, "tiff_export_vbox"));
|
||||||
|
|
||||||
|
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
|
||||||
|
vbox, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (vbox);
|
||||||
|
|
||||||
|
vbox = GTK_WIDGET (gtk_builder_get_object (builder, "radio_button_box"));
|
||||||
|
|
||||||
/* compression */
|
|
||||||
frame = gimp_int_radio_group_new (TRUE, _("Compression"),
|
frame = gimp_int_radio_group_new (TRUE, _("Compression"),
|
||||||
G_CALLBACK (gimp_radio_button_update),
|
G_CALLBACK (gimp_radio_button_update),
|
||||||
&tsvals.compression, tsvals.compression,
|
&tsvals.compression, tsvals.compression,
|
||||||
|
@ -1103,20 +1164,20 @@ save_dialog (gboolean has_alpha,
|
||||||
_("_Pack Bits"), COMPRESSION_PACKBITS, NULL,
|
_("_Pack Bits"), COMPRESSION_PACKBITS, NULL,
|
||||||
_("_Deflate"), COMPRESSION_ADOBE_DEFLATE, NULL,
|
_("_Deflate"), COMPRESSION_ADOBE_DEFLATE, NULL,
|
||||||
_("_JPEG"), COMPRESSION_JPEG, NULL,
|
_("_JPEG"), COMPRESSION_JPEG, NULL,
|
||||||
_("CCITT Group _3 fax"), COMPRESSION_CCITTFAX3, &g3,
|
_("CCITT Group _3 fax"), COMPRESSION_CCITTFAX3, &cmp_g3,
|
||||||
_("CCITT Group _4 fax"), COMPRESSION_CCITTFAX4, &g4,
|
_("CCITT Group _4 fax"), COMPRESSION_CCITTFAX4, &cmp_g4,
|
||||||
|
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gtk_widget_set_sensitive (g3, is_monochrome);
|
gtk_widget_set_sensitive (cmp_g3, is_monochrome);
|
||||||
gtk_widget_set_sensitive (g4, is_monochrome);
|
gtk_widget_set_sensitive (cmp_g4, is_monochrome);
|
||||||
|
|
||||||
if (! is_monochrome)
|
if (! is_monochrome)
|
||||||
{
|
{
|
||||||
if (tsvals.compression == COMPRESSION_CCITTFAX3 ||
|
if (tsvals.compression == COMPRESSION_CCITTFAX3 ||
|
||||||
tsvals.compression == COMPRESSION_CCITTFAX4)
|
tsvals.compression == COMPRESSION_CCITTFAX4)
|
||||||
{
|
{
|
||||||
gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (g3),
|
gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (cmp_g3),
|
||||||
COMPRESSION_NONE);
|
COMPRESSION_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1124,40 +1185,49 @@ save_dialog (gboolean has_alpha,
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||||
gtk_widget_show (frame);
|
gtk_widget_show (frame);
|
||||||
|
|
||||||
/* Keep colors behind alpha mask */
|
toggle = GTK_WIDGET (gtk_builder_get_object (builder, "sv_alpha"));
|
||||||
toggle = gtk_check_button_new_with_mnemonic
|
|
||||||
( _("Save _color values from transparent pixels"));
|
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
||||||
has_alpha && tsvals.save_transp_pixels);
|
has_alpha && tsvals.save_transp_pixels);
|
||||||
gtk_widget_set_sensitive (toggle, has_alpha);
|
gtk_widget_set_sensitive (toggle, has_alpha);
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (toggle);
|
|
||||||
|
|
||||||
g_signal_connect (toggle, "toggled",
|
g_signal_connect (toggle, "toggled",
|
||||||
G_CALLBACK (gimp_toggle_button_update),
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
&tsvals.save_transp_pixels);
|
&tsvals.save_transp_pixels);
|
||||||
|
|
||||||
/* comment entry */
|
entry = GTK_WIDGET (gtk_builder_get_object (builder, "commentfield"));
|
||||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (hbox);
|
|
||||||
|
|
||||||
label = gtk_label_new ( _("Comment:"));
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (label);
|
|
||||||
|
|
||||||
entry = gtk_entry_new ();
|
|
||||||
gtk_widget_show (entry);
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
|
|
||||||
gtk_entry_set_text (GTK_ENTRY (entry), image_comment ? image_comment : "");
|
gtk_entry_set_text (GTK_ENTRY (entry), image_comment ? image_comment : "");
|
||||||
|
|
||||||
g_signal_connect (entry, "changed",
|
g_signal_connect (entry, "changed",
|
||||||
G_CALLBACK (comment_entry_callback),
|
G_CALLBACK (comment_entry_callback),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gtk_widget_show (frame);
|
toggle = GTK_WIDGET (gtk_builder_get_object (builder, "sv_exif"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
||||||
|
tsvals.save_exif);
|
||||||
|
g_signal_connect (toggle, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
&tsvals.save_exif);
|
||||||
|
|
||||||
|
toggle = GTK_WIDGET (gtk_builder_get_object (builder, "sv_xmp"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
||||||
|
tsvals.save_xmp);
|
||||||
|
g_signal_connect (toggle, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
&tsvals.save_xmp);
|
||||||
|
|
||||||
|
toggle = GTK_WIDGET (gtk_builder_get_object (builder, "sv_iptc"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
||||||
|
tsvals.save_iptc);
|
||||||
|
g_signal_connect (toggle, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
&tsvals.save_iptc);
|
||||||
|
|
||||||
|
toggle = GTK_WIDGET (gtk_builder_get_object (builder, "sv_thumbnail"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
||||||
|
tsvals.save_thumbnail);
|
||||||
|
g_signal_connect (toggle, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
&tsvals.save_thumbnail);
|
||||||
|
|
||||||
gtk_widget_show (vbox);
|
|
||||||
gtk_widget_show (dialog);
|
gtk_widget_show (dialog);
|
||||||
|
|
||||||
run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
|
run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
|
||||||
|
|
|
@ -88,6 +88,7 @@ lens_apply_RC = lens-apply.rc.o
|
||||||
lens_flare_RC = lens-flare.rc.o
|
lens_flare_RC = lens-flare.rc.o
|
||||||
mail_RC = mail.rc.o
|
mail_RC = mail.rc.o
|
||||||
max_rgb_RC = max-rgb.rc.o
|
max_rgb_RC = max-rgb.rc.o
|
||||||
|
metadata_RC = metadata.rc.o
|
||||||
newsprint_RC = newsprint.rc.o
|
newsprint_RC = newsprint.rc.o
|
||||||
nl_filter_RC = nl-filter.rc.o
|
nl_filter_RC = nl-filter.rc.o
|
||||||
noise_rgb_RC = noise-rgb.rc.o
|
noise_rgb_RC = noise-rgb.rc.o
|
||||||
|
|
382
plug-ins/common/metadata.c
Normal file
382
plug-ins/common/metadata.c
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* metadata.c
|
||||||
|
* Copyright (C) 2013 Hartmut Kuhse
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gegl.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <gexiv2/gexiv2.h>
|
||||||
|
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define PLUG_IN_PROC "plug-in-metadata-editor"
|
||||||
|
#define PLUG_IN_BINARY "metadata"
|
||||||
|
#define PLUG_IN_ROLE "gimp-metadata"
|
||||||
|
|
||||||
|
#define EXIF_PREFIX "Exif."
|
||||||
|
#define IPTC_PREFIX "Iptc."
|
||||||
|
#define XMP_PREFIX "Xmp."
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
C_XMP_TAG = 0,
|
||||||
|
C_XMP_VALUE,
|
||||||
|
NUM_XMP_COLS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
C_EXIF_TAG = 0,
|
||||||
|
C_EXIF_VALUE,
|
||||||
|
NUM_EXIF_COLS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar *tag;
|
||||||
|
gchar *mode;
|
||||||
|
} iptc_tag;
|
||||||
|
|
||||||
|
|
||||||
|
/* local function prototypes */
|
||||||
|
|
||||||
|
static void query (void);
|
||||||
|
static void run (const gchar *name,
|
||||||
|
gint nparams,
|
||||||
|
const GimpParam *param,
|
||||||
|
gint *nreturn_vals,
|
||||||
|
GimpParam **return_vals);
|
||||||
|
|
||||||
|
static gboolean metadata_dialog (gint32 image_id,
|
||||||
|
GExiv2Metadata *metadata);
|
||||||
|
|
||||||
|
static void metadata_dialog_set_metadata (GExiv2Metadata *metadata,
|
||||||
|
GtkBuilder *builder);
|
||||||
|
|
||||||
|
static void metadata_dialog_iptc_callback (GtkWidget *dialog,
|
||||||
|
GtkBuilder *builder);
|
||||||
|
|
||||||
|
|
||||||
|
/* local variables */
|
||||||
|
|
||||||
|
const GimpPlugInInfo PLUG_IN_INFO =
|
||||||
|
{
|
||||||
|
NULL, /* init_proc */
|
||||||
|
NULL, /* quit_proc */
|
||||||
|
query, /* query_proc */
|
||||||
|
run, /* run_proc */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const iptc_tag const iptc_tags[] =
|
||||||
|
{
|
||||||
|
{ "Iptc.Application2.Byline", "single" },
|
||||||
|
{ "Iptc.Application2.BylineTitle", "single" },
|
||||||
|
{ "Iptc.Application2.Caption", "multi" },
|
||||||
|
{ "Iptc.Application2.Category", "single" },
|
||||||
|
{ "Iptc.Application2.City", "single" },
|
||||||
|
{ "Iptc.Application2.Copyright", "single" },
|
||||||
|
{ "Iptc.Application2.CountryName", "single" },
|
||||||
|
{ "Iptc.Application2.Credit", "single" },
|
||||||
|
{ "Iptc.Application2.Headline", "multi" },
|
||||||
|
{ "Iptc.Application2.Keywords", "multi" },
|
||||||
|
{ "Iptc.Application2.ObjectName", "single" },
|
||||||
|
{ "Iptc.Application2.ProvinceState", "single" },
|
||||||
|
{ "Iptc.Application2.Source", "single" },
|
||||||
|
{ "Iptc.Application2.SpecialInstructions", "multi" },
|
||||||
|
{ "Iptc.Application2.SubLocation", "single" },
|
||||||
|
{ "Iptc.Application2.SuppCategory", "multi" },
|
||||||
|
{ "Iptc.Application2.TransmissionReference", "single" },
|
||||||
|
{ "Iptc.Application2.Urgency", "single" },
|
||||||
|
{ "Iptc.Application2.Writer", "single" }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* functions */
|
||||||
|
|
||||||
|
MAIN ()
|
||||||
|
|
||||||
|
static void
|
||||||
|
query (void)
|
||||||
|
{
|
||||||
|
static const GimpParamDef metadata_args[] =
|
||||||
|
{
|
||||||
|
{ GIMP_PDB_INT32, "run-mode", "Run mode { RUN-INTERACTIVE (0) }" },
|
||||||
|
{ GIMP_PDB_IMAGE, "image", "Input image" }
|
||||||
|
};
|
||||||
|
|
||||||
|
gimp_install_procedure (PLUG_IN_PROC,
|
||||||
|
N_("View and edit metadata (EXIF, IPTC, XMP)"),
|
||||||
|
"View and edit metadata information attached to the "
|
||||||
|
"current image. This can include EXIF, IPTC and/or "
|
||||||
|
"XMP information. Some or all of this metadata "
|
||||||
|
"will be saved in the file, depending on the output "
|
||||||
|
"file format.",
|
||||||
|
"Hartmut Kuhse, Michael Natterer",
|
||||||
|
"Hartmut Kuhse, Michael Natterer",
|
||||||
|
"2013",
|
||||||
|
N_("Show Metadata"),
|
||||||
|
"*",
|
||||||
|
GIMP_PLUGIN,
|
||||||
|
G_N_ELEMENTS (metadata_args), 0,
|
||||||
|
metadata_args, NULL);
|
||||||
|
|
||||||
|
gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/File/Info");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run (const gchar *name,
|
||||||
|
gint nparams,
|
||||||
|
const GimpParam *param,
|
||||||
|
gint *nreturn_vals,
|
||||||
|
GimpParam **return_vals)
|
||||||
|
{
|
||||||
|
static GimpParam values[1];
|
||||||
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
||||||
|
|
||||||
|
*nreturn_vals = 1;
|
||||||
|
*return_vals = values;
|
||||||
|
|
||||||
|
values[0].type = GIMP_PDB_STATUS;
|
||||||
|
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
|
||||||
|
INIT_I18N();
|
||||||
|
gimp_ui_init (PLUG_IN_BINARY, TRUE);
|
||||||
|
|
||||||
|
if (! strcmp (name, PLUG_IN_PROC))
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
gint32 image_ID = param[1].data.d_image;
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (image_ID);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
metadata_dialog (image_ID, metadata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_message (_("This image has no metadata attached to it."));
|
||||||
|
}
|
||||||
|
|
||||||
|
status = GIMP_PDB_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = GIMP_PDB_CALLING_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
values[0].data.d_status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
metadata_dialog (gint32 image_id,
|
||||||
|
GExiv2Metadata *metadata)
|
||||||
|
{
|
||||||
|
GtkBuilder *builder;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
GtkWidget *metadata_vbox;
|
||||||
|
GtkWidget *content_area;
|
||||||
|
GObject *write_button;
|
||||||
|
gchar *ui_file;
|
||||||
|
gchar *title;
|
||||||
|
gchar *fname;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
builder = gtk_builder_new ();
|
||||||
|
|
||||||
|
ui_file = g_build_filename (gimp_data_directory (),
|
||||||
|
"ui", "plug-ins", "plug-in-metadata.ui", NULL);
|
||||||
|
|
||||||
|
if (! gtk_builder_add_from_file (builder, ui_file, &error))
|
||||||
|
{
|
||||||
|
g_printerr ("Error occured while loading UI file!\n");
|
||||||
|
g_printerr ("Message: %s\n", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_free (ui_file);
|
||||||
|
g_object_unref (builder);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (ui_file);
|
||||||
|
fname = g_filename_display_basename (gimp_image_get_uri (image_id));
|
||||||
|
title = g_strdup_printf ("Metadata: %s", fname);
|
||||||
|
g_free (fname);
|
||||||
|
|
||||||
|
dialog = gimp_dialog_new (title,
|
||||||
|
"gimp-metadata-dialog",
|
||||||
|
NULL, 0,
|
||||||
|
gimp_standard_help_func, PLUG_IN_PROC,
|
||||||
|
|
||||||
|
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
|
||||||
|
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_free (title);
|
||||||
|
|
||||||
|
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
|
||||||
|
GTK_RESPONSE_CLOSE,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||||
|
|
||||||
|
metadata_vbox = GTK_WIDGET (gtk_builder_get_object (builder,
|
||||||
|
"metadata-vbox"));
|
||||||
|
gtk_container_set_border_width (GTK_CONTAINER (metadata_vbox), 12);
|
||||||
|
gtk_box_pack_start (GTK_BOX (content_area), metadata_vbox, TRUE, TRUE, 0);
|
||||||
|
|
||||||
|
write_button = gtk_builder_get_object (builder, "iptc-write-button");
|
||||||
|
|
||||||
|
g_signal_connect (write_button, "clicked",
|
||||||
|
G_CALLBACK (metadata_dialog_iptc_callback),
|
||||||
|
builder);
|
||||||
|
|
||||||
|
metadata_dialog_set_metadata (metadata, builder);
|
||||||
|
|
||||||
|
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* private functions */
|
||||||
|
|
||||||
|
static void
|
||||||
|
metadata_dialog_set_metadata (GExiv2Metadata *metadata,
|
||||||
|
GtkBuilder *builder)
|
||||||
|
{
|
||||||
|
GtkListStore *exif_store;
|
||||||
|
GtkListStore *xmp_store;
|
||||||
|
gchar **exif_data;
|
||||||
|
gchar **iptc_data;
|
||||||
|
gchar **xmp_data;
|
||||||
|
gchar *value;
|
||||||
|
gchar *value_utf;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
exif_store = GTK_LIST_STORE (gtk_builder_get_object (builder,
|
||||||
|
"exif-liststore"));
|
||||||
|
xmp_store = GTK_LIST_STORE (gtk_builder_get_object (builder,
|
||||||
|
"xmp-liststore"));
|
||||||
|
|
||||||
|
exif_data = gexiv2_metadata_get_exif_tags (metadata);
|
||||||
|
|
||||||
|
for (i = 0; exif_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
gtk_list_store_append (exif_store, &iter);
|
||||||
|
value = gexiv2_metadata_get_tag_interpreted_string (metadata,
|
||||||
|
exif_data[i]);
|
||||||
|
value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
gtk_list_store_set (exif_store, &iter,
|
||||||
|
C_EXIF_TAG, exif_data[i],
|
||||||
|
C_EXIF_VALUE, value_utf,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmp_data = gexiv2_metadata_get_xmp_tags (metadata);
|
||||||
|
|
||||||
|
for (i = 0; xmp_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
gtk_list_store_append (xmp_store, &iter);
|
||||||
|
value = gexiv2_metadata_get_tag_interpreted_string (metadata,
|
||||||
|
xmp_data[i]);
|
||||||
|
value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
gtk_list_store_set (xmp_store, &iter,
|
||||||
|
C_XMP_TAG, xmp_data[i],
|
||||||
|
C_XMP_VALUE, value_utf,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
iptc_data = gexiv2_metadata_get_iptc_tags (metadata);
|
||||||
|
|
||||||
|
for (i = 0; iptc_data[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
GtkWidget *widget;
|
||||||
|
|
||||||
|
widget = GTK_WIDGET (gtk_builder_get_object (builder, iptc_data[i]));
|
||||||
|
value = gexiv2_metadata_get_tag_interpreted_string (metadata,
|
||||||
|
iptc_data[i]);
|
||||||
|
value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (GTK_IS_ENTRY (widget))
|
||||||
|
{
|
||||||
|
GtkEntry *entry_widget = GTK_ENTRY (widget);
|
||||||
|
|
||||||
|
gtk_entry_set_text (entry_widget, value_utf);
|
||||||
|
}
|
||||||
|
else if (GTK_IS_TEXT_VIEW (widget))
|
||||||
|
{
|
||||||
|
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (text_view);
|
||||||
|
gtk_text_buffer_set_text (buffer, value_utf, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
metadata_dialog_iptc_callback (GtkWidget *dialog,
|
||||||
|
GtkBuilder *builder)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
GExiv2Metadata *metadata;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
metadata = gimp_image_get_metadata (handler->image);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (iptc_tags); i++)
|
||||||
|
{
|
||||||
|
GObject *object = gtk_builder_get_object (handler->builder,
|
||||||
|
iptc_tags[i].tag);
|
||||||
|
|
||||||
|
if (! strcmp ("single", iptc_tags[i].mode))
|
||||||
|
{
|
||||||
|
GtkEntry *entry = GTK_ENTRY (object);
|
||||||
|
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, iptc_tags[i].tag,
|
||||||
|
gtk_entry_get_text (entry));
|
||||||
|
}
|
||||||
|
else if (!strcmp ("multi", iptc_tags[i].mode))
|
||||||
|
{
|
||||||
|
GtkTextView *text_view = GTK_TEXT_VIEW (object);
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkTextIter start;
|
||||||
|
GtkTextIter end;
|
||||||
|
gchar *text;
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (text_view);
|
||||||
|
gtk_text_buffer_get_start_iter (buffer, &start);
|
||||||
|
gtk_text_buffer_get_end_iter (buffer, &end);
|
||||||
|
|
||||||
|
text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
|
||||||
|
gexiv2_metadata_set_tag_string (metadata, iptc_tags[i].tag, text);
|
||||||
|
g_free (text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -51,7 +51,7 @@
|
||||||
'file-glob' => {},
|
'file-glob' => {},
|
||||||
'file-header' => { ui => 1, gegl => 1 },
|
'file-header' => { ui => 1, gegl => 1 },
|
||||||
'file-html-table' => { ui => 1, gegl => 1 },
|
'file-html-table' => { ui => 1, gegl => 1 },
|
||||||
'file-jp2-load' => { optional => 1, gegl => 1, libs => 'JP2_LIBS' },
|
'file-jp2-load' => { ui => 1, optional => 1, gegl => 1, libs => 'JP2_LIBS' },
|
||||||
'file-mng' => { ui => 1, gegl => 1, optional => 1, libs => 'MNG_LIBS', cflags => 'MNG_CFLAGS' },
|
'file-mng' => { ui => 1, gegl => 1, optional => 1, libs => 'MNG_LIBS', cflags => 'MNG_CFLAGS' },
|
||||||
'file-pat' => { ui => 1, gegl => 1 },
|
'file-pat' => { ui => 1, gegl => 1 },
|
||||||
'file-pcx' => { ui => 1, gegl => 1 },
|
'file-pcx' => { ui => 1, gegl => 1 },
|
||||||
|
@ -89,6 +89,7 @@
|
||||||
'lens-flare' => { ui => 1 },
|
'lens-flare' => { ui => 1 },
|
||||||
'mail' => { ui => 1, optional => 1 },
|
'mail' => { ui => 1, optional => 1 },
|
||||||
'max-rgb' => { ui => 1 },
|
'max-rgb' => { ui => 1 },
|
||||||
|
'metadata' => { ui => 1, libs => 'GEXIV2_LIBS', cflags => 'GEXIV2_CFLAGS' },
|
||||||
'newsprint' => { ui => 1 },
|
'newsprint' => { ui => 1 },
|
||||||
'nl-filter' => { ui => 1 },
|
'nl-filter' => { ui => 1 },
|
||||||
'noise-rgb' => { ui => 1 },
|
'noise-rgb' => { ui => 1 },
|
||||||
|
|
|
@ -22,11 +22,12 @@ AM_LDFLAGS = $(mwindows)
|
||||||
libexecdir = $(gimpplugindir)/plug-ins
|
libexecdir = $(gimpplugindir)/plug-ins
|
||||||
|
|
||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
-I$(top_srcdir) \
|
-I$(top_srcdir) \
|
||||||
$(GTK_CFLAGS) \
|
$(GTK_CFLAGS) \
|
||||||
$(EXIF_CFLAGS) \
|
$(EXIF_CFLAGS) \
|
||||||
$(LCMS_CFLAGS) \
|
$(LCMS_CFLAGS) \
|
||||||
$(GEGL_CFLAGS) \
|
$(GEGL_CFLAGS) \
|
||||||
|
$(GEXIV2_CFLAGS) \
|
||||||
-I$(includedir)
|
-I$(includedir)
|
||||||
|
|
||||||
libexec_PROGRAMS = file-jpeg
|
libexec_PROGRAMS = file-jpeg
|
||||||
|
@ -45,14 +46,6 @@ file_jpeg_SOURCES = \
|
||||||
jpeg-settings.c \
|
jpeg-settings.c \
|
||||||
jpeg-settings.h
|
jpeg-settings.h
|
||||||
|
|
||||||
if HAVE_LIBEXIF
|
|
||||||
file_jpeg_SOURCES += \
|
|
||||||
jpeg-exif.c \
|
|
||||||
jpeg-exif.h \
|
|
||||||
gimpexif.c \
|
|
||||||
gimpexif.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
file_jpeg_LDADD = \
|
file_jpeg_LDADD = \
|
||||||
$(libgimpui) \
|
$(libgimpui) \
|
||||||
$(libgimpwidgets) \
|
$(libgimpwidgets) \
|
||||||
|
@ -65,15 +58,11 @@ file_jpeg_LDADD = \
|
||||||
$(LCMS_LIBS) \
|
$(LCMS_LIBS) \
|
||||||
$(GTK_LIBS) \
|
$(GTK_LIBS) \
|
||||||
$(GEGL_LIBS) \
|
$(GEGL_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
$(RT_LIBS) \
|
$(RT_LIBS) \
|
||||||
$(INTLLIBS) \
|
$(INTLLIBS) \
|
||||||
$(file_jpeg_RC)
|
$(file_jpeg_RC)
|
||||||
|
|
||||||
if HAVE_LIBEXIF
|
|
||||||
file_jpeg_LDADD += \
|
|
||||||
$(EXIF_LIBS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
noinst_PROGRAMS = jpegqual
|
noinst_PROGRAMS = jpegqual
|
||||||
|
|
||||||
jpegqual_SOURCES = \
|
jpegqual_SOURCES = \
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
/* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* EXIF-handling code for the metadata library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
|
||||||
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#include <libexif/exif-content.h>
|
|
||||||
#include <libexif/exif-utils.h>
|
|
||||||
|
|
||||||
#include "gimpexif.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define EXIF_HEADER_SIZE 8
|
|
||||||
|
|
||||||
/*
|
|
||||||
* gimp_metadata_store_exif:
|
|
||||||
* @image_ID: the GIMP image to work on.
|
|
||||||
* @exif_data: the Exif data that is to be stored.
|
|
||||||
*
|
|
||||||
* This function is supposed to load the "gimp-metadata" parasite
|
|
||||||
* (which is in XMP format), parse it, add the exif information,
|
|
||||||
* reformat it into XMP, and store the result as the new parasite.
|
|
||||||
* The infrastructure to do this is not yet available, so for the
|
|
||||||
* moment it does something much simpler -- it calls upon libexif
|
|
||||||
* to serialize the exif data, and stores the result in a parasite
|
|
||||||
* called "exif-data".
|
|
||||||
*/
|
|
||||||
void gimp_metadata_store_exif (gint32 image_ID,
|
|
||||||
ExifData *exif_data)
|
|
||||||
{
|
|
||||||
GimpParam *return_vals;
|
|
||||||
gint nreturn_vals;
|
|
||||||
GimpParasite *parasite = NULL;
|
|
||||||
guchar *exif_buf = NULL;
|
|
||||||
guint exif_buf_len = 0;
|
|
||||||
|
|
||||||
exif_data_save_data (exif_data, &exif_buf, &exif_buf_len);
|
|
||||||
|
|
||||||
if (exif_buf_len > EXIF_HEADER_SIZE)
|
|
||||||
{
|
|
||||||
parasite = gimp_parasite_new ("exif-data",
|
|
||||||
GIMP_PARASITE_PERSISTENT,
|
|
||||||
exif_buf_len, exif_buf);
|
|
||||||
gimp_image_attach_parasite (image_ID, parasite);
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
}
|
|
||||||
return_vals = gimp_run_procedure ("plug-in-metadata-decode-exif",
|
|
||||||
&nreturn_vals,
|
|
||||||
GIMP_PDB_IMAGE, image_ID,
|
|
||||||
GIMP_PDB_INT32, 7,
|
|
||||||
GIMP_PDB_INT8ARRAY, "unused",
|
|
||||||
GIMP_PDB_END);
|
|
||||||
if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS)
|
|
||||||
g_warning ("JPEG Exif -> XMP Merge failed");
|
|
||||||
|
|
||||||
free (exif_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* gimp_metadata_generate_exif:
|
|
||||||
* @image_ID: the ID of the GIMP image to work on.
|
|
||||||
*
|
|
||||||
* This function is supposed to load the "gimp-metadata" parasite
|
|
||||||
* (which is a block of XMP info), parse it, extract the exif
|
|
||||||
* values, and build an ExifData structure from them.
|
|
||||||
* The infrastructure to do this is not yet available, so for the
|
|
||||||
* moment it does something much simpler -- it loads the "exif-data"
|
|
||||||
* parasite (which is a serialized representation of the exif data),
|
|
||||||
* and calls upon libexif to parse it into an ExifData struct.
|
|
||||||
*
|
|
||||||
* returns: The reconstructed exif data, or NULL if none exists.
|
|
||||||
*/
|
|
||||||
ExifData *
|
|
||||||
gimp_metadata_generate_exif (gint32 image_ID)
|
|
||||||
{
|
|
||||||
ExifData *exif_data;
|
|
||||||
GimpParasite *parasite = gimp_image_get_parasite (image_ID, "exif-data");
|
|
||||||
|
|
||||||
if (parasite)
|
|
||||||
{
|
|
||||||
exif_data = exif_data_new_from_data (gimp_parasite_data (parasite),
|
|
||||||
gimp_parasite_data_size (parasite));
|
|
||||||
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
return exif_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* gimp_exif_content_get_value:
|
|
||||||
* @content: ExifContent block from which to get value
|
|
||||||
* @tag: Tag whose value to get
|
|
||||||
* @value: Place to put the result
|
|
||||||
* @maxlen: Maximum size of returned string
|
|
||||||
*
|
|
||||||
* This function is a wrapper around the libexif function
|
|
||||||
* exif_content_get_value(), necessary to deal with an incompatible
|
|
||||||
* API change. It looks up the value of the specified tag,
|
|
||||||
* returning the result as a human-readable string. Note that
|
|
||||||
* @value must be pre-allocated.
|
|
||||||
*/
|
|
||||||
const gchar *
|
|
||||||
gimp_exif_content_get_value (ExifContent *content,
|
|
||||||
ExifTag tag,
|
|
||||||
gchar *value,
|
|
||||||
gint maxlen)
|
|
||||||
{
|
|
||||||
ExifEntry *entry = exif_content_get_entry (content, tag);
|
|
||||||
|
|
||||||
if (entry)
|
|
||||||
return exif_entry_get_value (entry, value, maxlen);
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* gimp_exif_data_remove_entry:
|
|
||||||
* @data: ExifData pointer
|
|
||||||
* @ifd: Index of the ifd holding the entry to be removed
|
|
||||||
* @tag: Tag of the entry to be removed
|
|
||||||
*
|
|
||||||
* This is a convenience function for removing a specified
|
|
||||||
* entry from an exif data structure. If no such entry
|
|
||||||
* exists, the function returns without doing anything.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gimp_exif_data_remove_entry (ExifData *exif_data,
|
|
||||||
ExifIfd ifd,
|
|
||||||
ExifTag tag)
|
|
||||||
{
|
|
||||||
ExifEntry *entry = exif_content_get_entry (exif_data->ifd[ifd],
|
|
||||||
tag);
|
|
||||||
|
|
||||||
if (entry)
|
|
||||||
exif_content_remove_entry (exif_data->ifd[ifd], entry);
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* EXIF-handling code for the metadata library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __GIMP_EXIF_H__
|
|
||||||
#define __GIMP_EXIF_H__
|
|
||||||
|
|
||||||
void gimp_metadata_store_exif (gint32 image_ID,
|
|
||||||
ExifData *exif_data);
|
|
||||||
|
|
||||||
ExifData * gimp_metadata_generate_exif (gint32 image_ID);
|
|
||||||
|
|
||||||
const gchar * gimp_exif_content_get_value (ExifContent *content,
|
|
||||||
ExifTag tag,
|
|
||||||
gchar *value,
|
|
||||||
gint maxlen);
|
|
||||||
|
|
||||||
void gimp_exif_data_remove_entry (ExifData *exif_data,
|
|
||||||
ExifIfd ifd,
|
|
||||||
ExifTag tag);
|
|
||||||
|
|
||||||
#endif /* __GIMP_EXIF_H__ */
|
|
|
@ -1,458 +0,0 @@
|
||||||
/* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* EXIF-handling code for the jpeg plugin. May eventually be better
|
|
||||||
* to move this stuff into libgimpbase or a new libgimpmetadata and
|
|
||||||
* make it available for other plugins.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
#include <jpeglib.h>
|
|
||||||
#include <jerror.h>
|
|
||||||
|
|
||||||
#include <libexif/exif-content.h>
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#include <libexif/exif-utils.h>
|
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
|
||||||
#include <libgimp/gimpui.h>
|
|
||||||
|
|
||||||
#include "jpeg-exif.h"
|
|
||||||
#include "gimpexif.h"
|
|
||||||
#include "jpeg.h"
|
|
||||||
#include "jpeg-settings.h"
|
|
||||||
|
|
||||||
#include "libgimp/stdplugins-intl.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define THUMBNAIL_SIZE 128
|
|
||||||
#define JPEG_EXIF_ROTATE_PARASITE "exif-orientation-rotate"
|
|
||||||
|
|
||||||
|
|
||||||
static gboolean jpeg_exif_rotate_query_dialog (gint32 image_ID);
|
|
||||||
|
|
||||||
|
|
||||||
/* Replacement for exif_data_new_from_file() to work around
|
|
||||||
* filename encoding problems (see bug #335391).
|
|
||||||
*/
|
|
||||||
ExifData *
|
|
||||||
jpeg_exif_data_new_from_file (const gchar *filename,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
ExifData *data;
|
|
||||||
GMappedFile *file;
|
|
||||||
|
|
||||||
g_return_val_if_fail (filename != NULL, NULL);
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
||||||
|
|
||||||
file = g_mapped_file_new (filename, FALSE, error);
|
|
||||||
if (! file)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
data = exif_data_new_from_data ((guchar *) g_mapped_file_get_contents (file),
|
|
||||||
g_mapped_file_get_length (file));
|
|
||||||
|
|
||||||
g_mapped_file_unref (file);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gint
|
|
||||||
jpeg_exif_get_orientation (ExifData *exif_data)
|
|
||||||
{
|
|
||||||
ExifEntry *entry;
|
|
||||||
gint byte_order = exif_data_get_byte_order (exif_data);
|
|
||||||
|
|
||||||
/* get orientation and rotate image accordingly if necessary */
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_ORIENTATION)))
|
|
||||||
{
|
|
||||||
return exif_get_short (entry->data, byte_order);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
jpeg_exif_get_resolution (ExifData *exif_data,
|
|
||||||
gdouble *xresolution,
|
|
||||||
gdouble *yresolution,
|
|
||||||
gint *unit)
|
|
||||||
{
|
|
||||||
gboolean success;
|
|
||||||
ExifEntry *entry;
|
|
||||||
gint byte_order;
|
|
||||||
gdouble xres;
|
|
||||||
gdouble yres;
|
|
||||||
gint ruint;
|
|
||||||
ExifRational r;
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
byte_order = exif_data_get_byte_order (exif_data);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_X_RESOLUTION);
|
|
||||||
if (!entry)
|
|
||||||
break;
|
|
||||||
|
|
||||||
r = exif_get_rational (entry->data, byte_order);
|
|
||||||
if (r.denominator == 0.0)
|
|
||||||
break;
|
|
||||||
xres = r.numerator / r.denominator;
|
|
||||||
|
|
||||||
entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_Y_RESOLUTION);
|
|
||||||
if (!entry)
|
|
||||||
break;
|
|
||||||
|
|
||||||
r = exif_get_rational (entry->data, byte_order);
|
|
||||||
if (r.denominator == 0.0)
|
|
||||||
break;
|
|
||||||
yres = r.numerator / r.denominator;
|
|
||||||
|
|
||||||
entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_RESOLUTION_UNIT);
|
|
||||||
if (!entry)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ruint = exif_get_short (entry->data, byte_order);
|
|
||||||
if ((ruint != 2) && /* inches */
|
|
||||||
(ruint != 3)) /* centimetres */
|
|
||||||
break;
|
|
||||||
|
|
||||||
success = TRUE;
|
|
||||||
}
|
|
||||||
while (0);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
*xresolution = xres;
|
|
||||||
*yresolution = yres;
|
|
||||||
*unit = ruint;
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
jpeg_setup_exif_for_save (ExifData *exif_data,
|
|
||||||
const gint32 image_ID)
|
|
||||||
{
|
|
||||||
ExifRational r;
|
|
||||||
gdouble xres, yres;
|
|
||||||
ExifEntry *entry;
|
|
||||||
gint byte_order = exif_data_get_byte_order (exif_data);
|
|
||||||
|
|
||||||
/* set orientation to top - left */
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_ORIENTATION)))
|
|
||||||
{
|
|
||||||
exif_set_short (entry->data, byte_order, (ExifShort) 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set x and y resolution */
|
|
||||||
gimp_image_get_resolution (image_ID, &xres, &yres);
|
|
||||||
r.numerator = xres;
|
|
||||||
r.denominator = 1;
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_X_RESOLUTION)))
|
|
||||||
{
|
|
||||||
exif_set_rational (entry->data, byte_order, r);
|
|
||||||
}
|
|
||||||
r.numerator = yres;
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_Y_RESOLUTION)))
|
|
||||||
{
|
|
||||||
exif_set_rational (entry->data, byte_order, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set resolution unit, always inches */
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_RESOLUTION_UNIT)))
|
|
||||||
{
|
|
||||||
exif_set_short (entry->data, byte_order, (ExifShort) 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set software to "GIMP" and include the version number */
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_SOFTWARE)))
|
|
||||||
{
|
|
||||||
const gchar *name = "GIMP " GIMP_VERSION;
|
|
||||||
|
|
||||||
entry->data = (guchar *) g_strdup (name);
|
|
||||||
entry->size = strlen (name) + 1;
|
|
||||||
entry->components = entry->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the width and height */
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_EXIF],
|
|
||||||
EXIF_TAG_PIXEL_X_DIMENSION)))
|
|
||||||
{
|
|
||||||
exif_set_long (entry->data, byte_order,
|
|
||||||
(ExifLong) gimp_image_width (image_ID));
|
|
||||||
}
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_EXIF],
|
|
||||||
EXIF_TAG_PIXEL_Y_DIMENSION)))
|
|
||||||
{
|
|
||||||
exif_set_long (entry->data, byte_order,
|
|
||||||
(ExifLong) gimp_image_height (image_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set the date & time image was saved
|
|
||||||
* note, date & time of original photo is stored elsewwhere, we
|
|
||||||
* aren't losing it.
|
|
||||||
*/
|
|
||||||
if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_DATE_TIME)))
|
|
||||||
{
|
|
||||||
/* small memory leak here */
|
|
||||||
entry->data = NULL;
|
|
||||||
exif_entry_initialize (entry, EXIF_TAG_DATE_TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* should set components configuration, don't know how */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* remove entries that don't apply to jpeg
|
|
||||||
* (may have come from tiff or raw)
|
|
||||||
*/
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_COMPRESSION);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_BITS_PER_SAMPLE);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_SAMPLES_PER_PIXEL);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_PHOTOMETRIC_INTERPRETATION);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_STRIP_OFFSETS);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_PLANAR_CONFIGURATION);
|
|
||||||
gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_YCBCR_SUB_SAMPLING);
|
|
||||||
|
|
||||||
/* should set thumbnail attributes */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
jpeg_exif_rotate (gint32 image_ID,
|
|
||||||
gint orientation)
|
|
||||||
{
|
|
||||||
switch (orientation)
|
|
||||||
{
|
|
||||||
case 1: /* standard orientation, do nothing */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* flipped right-left */
|
|
||||||
gimp_image_flip (image_ID, GIMP_ORIENTATION_HORIZONTAL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: /* rotated 180 */
|
|
||||||
gimp_image_rotate (image_ID, GIMP_ROTATE_180);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: /* flipped top-bottom */
|
|
||||||
gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5: /* flipped diagonally around '\' */
|
|
||||||
gimp_image_rotate (image_ID, GIMP_ROTATE_90);
|
|
||||||
jpeg_swap_original_settings (image_ID);
|
|
||||||
gimp_image_flip (image_ID, GIMP_ORIENTATION_HORIZONTAL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6: /* 90 CW */
|
|
||||||
gimp_image_rotate (image_ID, GIMP_ROTATE_90);
|
|
||||||
jpeg_swap_original_settings (image_ID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7: /* flipped diagonally around '/' */
|
|
||||||
gimp_image_rotate (image_ID, GIMP_ROTATE_90);
|
|
||||||
jpeg_swap_original_settings (image_ID);
|
|
||||||
gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 8: /* 90 CCW */
|
|
||||||
gimp_image_rotate (image_ID, GIMP_ROTATE_270);
|
|
||||||
jpeg_swap_original_settings (image_ID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: /* shouldn't happen */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
jpeg_exif_rotate_query (gint32 image_ID,
|
|
||||||
gint orientation)
|
|
||||||
{
|
|
||||||
GimpParasite *parasite;
|
|
||||||
gboolean query = load_interactive;
|
|
||||||
|
|
||||||
if (orientation < 2 || orientation > 8)
|
|
||||||
return;
|
|
||||||
|
|
||||||
parasite = gimp_get_parasite (JPEG_EXIF_ROTATE_PARASITE);
|
|
||||||
|
|
||||||
if (parasite)
|
|
||||||
{
|
|
||||||
if (strncmp (gimp_parasite_data (parasite), "yes",
|
|
||||||
gimp_parasite_data_size (parasite)) == 0)
|
|
||||||
{
|
|
||||||
query = FALSE;
|
|
||||||
}
|
|
||||||
else if (strncmp (gimp_parasite_data (parasite), "no",
|
|
||||||
gimp_parasite_data_size (parasite)) == 0)
|
|
||||||
{
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query && ! jpeg_exif_rotate_query_dialog (image_ID))
|
|
||||||
return;
|
|
||||||
|
|
||||||
jpeg_exif_rotate (image_ID, orientation);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
jpeg_exif_rotate_query_dialog (gint32 image_ID)
|
|
||||||
{
|
|
||||||
GtkWidget *dialog;
|
|
||||||
GtkWidget *hbox;
|
|
||||||
GtkWidget *vbox;
|
|
||||||
GtkWidget *label;
|
|
||||||
GtkWidget *toggle;
|
|
||||||
GdkPixbuf *pixbuf;
|
|
||||||
gint response;
|
|
||||||
|
|
||||||
dialog = gimp_dialog_new (_("Rotate Image?"), PLUG_IN_ROLE,
|
|
||||||
NULL, 0, NULL, NULL,
|
|
||||||
|
|
||||||
_("_Keep Orientation"), GTK_RESPONSE_CANCEL,
|
|
||||||
GIMP_STOCK_TOOL_ROTATE, GTK_RESPONSE_OK,
|
|
||||||
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
|
|
||||||
GTK_RESPONSE_OK,
|
|
||||||
GTK_RESPONSE_CANCEL,
|
|
||||||
-1);
|
|
||||||
|
|
||||||
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
|
|
||||||
gimp_window_set_transient (GTK_WINDOW (dialog));
|
|
||||||
|
|
||||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
|
||||||
gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
|
|
||||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
|
||||||
hbox, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (hbox);
|
|
||||||
|
|
||||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (vbox);
|
|
||||||
|
|
||||||
pixbuf = gimp_image_get_thumbnail (image_ID,
|
|
||||||
THUMBNAIL_SIZE, THUMBNAIL_SIZE,
|
|
||||||
GIMP_PIXBUF_SMALL_CHECKS);
|
|
||||||
|
|
||||||
if (pixbuf)
|
|
||||||
{
|
|
||||||
GtkWidget *image;
|
|
||||||
gchar *name;
|
|
||||||
|
|
||||||
image = gtk_image_new_from_pixbuf (pixbuf);
|
|
||||||
g_object_unref (pixbuf);
|
|
||||||
|
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (image);
|
|
||||||
|
|
||||||
name = gimp_image_get_name (image_ID);
|
|
||||||
|
|
||||||
label = gtk_label_new (name);
|
|
||||||
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_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (label);
|
|
||||||
|
|
||||||
g_free (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
|
|
||||||
gtk_widget_show (vbox);
|
|
||||||
|
|
||||||
label = g_object_new (GTK_TYPE_LABEL,
|
|
||||||
"label", _("According to the EXIF data, "
|
|
||||||
"this image is rotated."),
|
|
||||||
"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 (vbox), label, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show (label);
|
|
||||||
|
|
||||||
label = g_object_new (GTK_TYPE_LABEL,
|
|
||||||
"label", _("Would you like GIMP to rotate it "
|
|
||||||
"into the standard orientation?"),
|
|
||||||
"wrap", TRUE,
|
|
||||||
"justify", GTK_JUSTIFY_LEFT,
|
|
||||||
"xalign", 0.0,
|
|
||||||
"yalign", 0.5,
|
|
||||||
NULL);
|
|
||||||
gtk_box_pack_start (GTK_BOX (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 (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));
|
|
||||||
|
|
||||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)))
|
|
||||||
{
|
|
||||||
GimpParasite *parasite;
|
|
||||||
const gchar *str = (response == GTK_RESPONSE_OK) ? "yes" : "no";
|
|
||||||
|
|
||||||
parasite = gimp_parasite_new (JPEG_EXIF_ROTATE_PARASITE,
|
|
||||||
GIMP_PARASITE_PERSISTENT,
|
|
||||||
strlen (str), str);
|
|
||||||
gimp_attach_parasite (parasite);
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_destroy (dialog);
|
|
||||||
|
|
||||||
return (response == GTK_RESPONSE_OK);
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __JPEG_EXIF_H__
|
|
||||||
#define __JPEG_EXIF_H__
|
|
||||||
|
|
||||||
extern ExifData *exif_data;
|
|
||||||
|
|
||||||
ExifData * jpeg_exif_data_new_from_file (const gchar *filename,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
gint jpeg_exif_get_orientation (ExifData *exif_data);
|
|
||||||
|
|
||||||
gboolean jpeg_exif_get_resolution (ExifData *exif_data,
|
|
||||||
gdouble *xresolution,
|
|
||||||
gdouble *yresolution,
|
|
||||||
gint *unit);
|
|
||||||
|
|
||||||
void jpeg_setup_exif_for_save (ExifData *exif_data,
|
|
||||||
const gint32 image_ID);
|
|
||||||
|
|
||||||
void jpeg_exif_rotate (gint32 image_ID,
|
|
||||||
gint orientation);
|
|
||||||
void jpeg_exif_rotate_query (gint32 image_ID,
|
|
||||||
gint orientation);
|
|
||||||
|
|
||||||
#endif /* __JPEG_EXIF_H__ */
|
|
|
@ -21,15 +21,13 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
#include <gexiv2/gexiv2.h>
|
||||||
|
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
#include <jerror.h>
|
#include <jerror.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
#ifdef HAVE_LCMS
|
#ifdef HAVE_LCMS
|
||||||
#include <lcms2.h>
|
#include <lcms2.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -43,21 +41,11 @@
|
||||||
#include "jpeg-icc.h"
|
#include "jpeg-icc.h"
|
||||||
#include "jpeg-settings.h"
|
#include "jpeg-settings.h"
|
||||||
#include "jpeg-load.h"
|
#include "jpeg-load.h"
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include "jpeg-exif.h"
|
|
||||||
#include "gimpexif.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static void jpeg_load_resolution (gint32 image_ID,
|
static void jpeg_load_resolution (gint32 image_ID,
|
||||||
struct jpeg_decompress_struct
|
struct jpeg_decompress_struct
|
||||||
*cinfo);
|
*cinfo);
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
static gboolean jpeg_load_exif_resolution (gint32 image_ID,
|
|
||||||
ExifData *exif_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void jpeg_load_sanitize_comment (gchar *comment);
|
static void jpeg_load_sanitize_comment (gchar *comment);
|
||||||
|
|
||||||
static gpointer jpeg_load_cmyk_transform (guint8 *profile_data,
|
static gpointer jpeg_load_cmyk_transform (guint8 *profile_data,
|
||||||
|
@ -90,9 +78,6 @@ load_image (const gchar *filename,
|
||||||
gint tile_height;
|
gint tile_height;
|
||||||
gint scanlines;
|
gint scanlines;
|
||||||
gint i, start, end;
|
gint i, start, end;
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
gint orientation = 0;
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LCMS
|
#ifdef HAVE_LCMS
|
||||||
cmsHTRANSFORM cmyk_transform = NULL;
|
cmsHTRANSFORM cmyk_transform = NULL;
|
||||||
#else
|
#else
|
||||||
|
@ -265,9 +250,6 @@ load_image (const gchar *filename,
|
||||||
GString *comment_buffer = NULL;
|
GString *comment_buffer = NULL;
|
||||||
guint8 *profile = NULL;
|
guint8 *profile = NULL;
|
||||||
guint profile_size = 0;
|
guint profile_size = 0;
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
ExifData *exif_data = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Step 5.0: save the original JPEG settings in a parasite */
|
/* Step 5.0: save the original JPEG settings in a parasite */
|
||||||
jpeg_detect_original_settings (&cinfo, image_ID);
|
jpeg_detect_original_settings (&cinfo, image_ID);
|
||||||
|
@ -303,19 +285,10 @@ load_image (const gchar *filename,
|
||||||
#ifdef GIMP_UNSTABLE
|
#ifdef GIMP_UNSTABLE
|
||||||
g_print ("jpeg-load: found EXIF block (%d bytes)\n",
|
g_print ("jpeg-load: found EXIF block (%d bytes)\n",
|
||||||
(gint) (len - sizeof (JPEG_APP_HEADER_EXIF)));
|
(gint) (len - sizeof (JPEG_APP_HEADER_EXIF)));
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
if (! exif_data)
|
|
||||||
exif_data = exif_data_new ();
|
|
||||||
/* if there are multiple blocks, their data will be merged */
|
|
||||||
exif_data_load_data (exif_data, (unsigned char *) data, len);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
if (!jpeg_load_exif_resolution (image_ID, exif_data))
|
|
||||||
#endif
|
|
||||||
jpeg_load_resolution (image_ID, &cinfo);
|
jpeg_load_resolution (image_ID, &cinfo);
|
||||||
|
|
||||||
/* if we found any comments, then make a parasite for them */
|
/* if we found any comments, then make a parasite for them */
|
||||||
|
@ -334,55 +307,6 @@ load_image (const gchar *filename,
|
||||||
g_string_free (comment_buffer, TRUE);
|
g_string_free (comment_buffer, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
/* if we found any EXIF block, then attach the metadata to the image */
|
|
||||||
if (exif_data)
|
|
||||||
{
|
|
||||||
gimp_metadata_store_exif (image_ID, exif_data);
|
|
||||||
orientation = jpeg_exif_get_orientation (exif_data);
|
|
||||||
exif_data_unref (exif_data);
|
|
||||||
exif_data = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Step 5.2: check for XMP metadata in APP1 markers (after EXIF) */
|
|
||||||
for (marker = cinfo.marker_list; marker; marker = marker->next)
|
|
||||||
{
|
|
||||||
const gchar *data = (const gchar *) marker->data;
|
|
||||||
gsize len = marker->data_length;
|
|
||||||
|
|
||||||
if ((marker->marker == JPEG_APP0 + 1)
|
|
||||||
&& (len > sizeof (JPEG_APP_HEADER_XMP) + 20)
|
|
||||||
&& ! strcmp (JPEG_APP_HEADER_XMP, data))
|
|
||||||
{
|
|
||||||
GimpParam *return_vals;
|
|
||||||
gint nreturn_vals;
|
|
||||||
gchar *xmp_packet;
|
|
||||||
|
|
||||||
#ifdef GIMP_UNSTABLE
|
|
||||||
g_print ("jpeg-load: found XMP packet (%d bytes)\n",
|
|
||||||
(gint) (len - sizeof (JPEG_APP_HEADER_XMP)));
|
|
||||||
#endif
|
|
||||||
xmp_packet = g_strndup (data + sizeof (JPEG_APP_HEADER_XMP),
|
|
||||||
len - sizeof (JPEG_APP_HEADER_XMP));
|
|
||||||
|
|
||||||
/* FIXME: running this through the PDB is not very efficient */
|
|
||||||
return_vals = gimp_run_procedure ("plug-in-metadata-decode-xmp",
|
|
||||||
&nreturn_vals,
|
|
||||||
GIMP_PDB_IMAGE, image_ID,
|
|
||||||
GIMP_PDB_STRING, xmp_packet,
|
|
||||||
GIMP_PDB_END);
|
|
||||||
|
|
||||||
if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS)
|
|
||||||
{
|
|
||||||
g_warning ("JPEG - unable to decode XMP metadata packet");
|
|
||||||
}
|
|
||||||
|
|
||||||
gimp_destroy_params (return_vals, nreturn_vals);
|
|
||||||
g_free (xmp_packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step 5.3: check for an embedded ICC profile in APP2 markers */
|
/* Step 5.3: check for an embedded ICC profile in APP2 markers */
|
||||||
jpeg_icc_read_profile (&cinfo, &profile, &profile_size);
|
jpeg_icc_read_profile (&cinfo, &profile, &profile_size);
|
||||||
|
|
||||||
|
@ -489,10 +413,6 @@ load_image (const gchar *filename,
|
||||||
|
|
||||||
gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
|
gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
jpeg_exif_rotate_query (image_ID, orientation);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return image_ID;
|
return image_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,53 +457,6 @@ jpeg_load_resolution (gint32 image_ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
jpeg_load_exif_resolution (gint32 image_ID,
|
|
||||||
ExifData *exif_data)
|
|
||||||
{
|
|
||||||
gboolean success;
|
|
||||||
gdouble xresolution;
|
|
||||||
gdouble yresolution;
|
|
||||||
gint unit;
|
|
||||||
|
|
||||||
if (!exif_data)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!jpeg_exif_get_resolution (exif_data,
|
|
||||||
&xresolution,
|
|
||||||
&yresolution,
|
|
||||||
&unit))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
switch (unit)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
success = TRUE;
|
|
||||||
break;
|
|
||||||
case 3: /* dots per cm */
|
|
||||||
xresolution *= 2.54;
|
|
||||||
yresolution *= 2.54;
|
|
||||||
gimp_image_set_unit (image_ID, GIMP_UNIT_MM);
|
|
||||||
success = TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_warning ("Unknown EXIF resolution unit %d; skipping EXIF resolution.",
|
|
||||||
unit);
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
gimp_image_set_resolution (image_ID, xresolution, yresolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A number of JPEG files have comments written in a local character set
|
* A number of JPEG files have comments written in a local character set
|
||||||
* instead of UTF-8. Some of these files may have been saved by older
|
* instead of UTF-8. Some of these files may have been saved by older
|
||||||
|
@ -608,9 +481,6 @@ jpeg_load_sanitize_comment (gchar *comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
struct jpeg_source_mgr pub; /* public fields */
|
struct jpeg_source_mgr pub; /* public fields */
|
||||||
|
@ -627,7 +497,6 @@ init_source (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static boolean
|
static boolean
|
||||||
fill_input_buffer (j_decompress_ptr cinfo)
|
fill_input_buffer (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
|
@ -660,14 +529,16 @@ term_source (j_decompress_ptr cinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
gint32
|
gint32
|
||||||
load_thumbnail_image (const gchar *filename,
|
load_thumbnail_image (GFile *file,
|
||||||
gint *width,
|
gint *width,
|
||||||
gint *height,
|
gint *height,
|
||||||
GimpImageType *type,
|
GimpImageType *type,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gint32 volatile image_ID;
|
gint32 volatile image_ID = -1;
|
||||||
ExifData *exif_data;
|
GimpMetadata *metadata = NULL;
|
||||||
|
guint8 *thumbnail_buffer = NULL;
|
||||||
|
gint thumbnail_size;
|
||||||
gint32 layer_ID;
|
gint32 layer_ID;
|
||||||
struct jpeg_decompress_struct cinfo;
|
struct jpeg_decompress_struct cinfo;
|
||||||
struct my_error_mgr jerr;
|
struct my_error_mgr jerr;
|
||||||
|
@ -683,20 +554,25 @@ load_thumbnail_image (const gchar *filename,
|
||||||
my_src_ptr src;
|
my_src_ptr src;
|
||||||
FILE *infile;
|
FILE *infile;
|
||||||
|
|
||||||
image_ID = -1;
|
metadata = gimp_metadata_load_from_file (file, error);
|
||||||
exif_data = jpeg_exif_data_new_from_file (filename, NULL);
|
if (! metadata)
|
||||||
|
|
||||||
if (! ((exif_data) && (exif_data->data) && (exif_data->size > 0)))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
orientation = jpeg_exif_get_orientation (exif_data);
|
orientation = gexiv2_metadata_get_orientation (metadata);
|
||||||
|
|
||||||
|
if (! gexiv2_metadata_get_exif_thumbnail (metadata,
|
||||||
|
&thumbnail_buffer, &thumbnail_size))
|
||||||
|
{
|
||||||
|
g_object_unref (metadata);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
cinfo.err = jpeg_std_error (&jerr.pub);
|
cinfo.err = jpeg_std_error (&jerr.pub);
|
||||||
jerr.pub.error_exit = my_error_exit;
|
jerr.pub.error_exit = my_error_exit;
|
||||||
jerr.pub.output_message = my_output_message;
|
jerr.pub.output_message = my_output_message;
|
||||||
|
|
||||||
gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
|
gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
|
||||||
gimp_filename_to_utf8 (filename));
|
g_file_get_parse_name (file));
|
||||||
|
|
||||||
/* Establish the setjmp return context for my_error_exit to use. */
|
/* Establish the setjmp return context for my_error_exit to use. */
|
||||||
if (setjmp (jerr.setjmp_buffer))
|
if (setjmp (jerr.setjmp_buffer))
|
||||||
|
@ -710,15 +586,15 @@ load_thumbnail_image (const gchar *filename,
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
gimp_image_delete (image_ID);
|
gimp_image_delete (image_ID);
|
||||||
|
|
||||||
if (exif_data)
|
if (metadata)
|
||||||
{
|
g_object_unref (metadata);
|
||||||
exif_data_unref (exif_data);
|
|
||||||
exif_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer)
|
if (buffer)
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
|
|
||||||
|
if (thumbnail_buffer)
|
||||||
|
g_free (thumbnail_buffer);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,11 +616,11 @@ load_thumbnail_image (const gchar *filename,
|
||||||
src->pub.resync_to_restart = jpeg_resync_to_restart;
|
src->pub.resync_to_restart = jpeg_resync_to_restart;
|
||||||
src->pub.term_source = term_source;
|
src->pub.term_source = term_source;
|
||||||
|
|
||||||
src->pub.bytes_in_buffer = exif_data->size;
|
src->pub.bytes_in_buffer = thumbnail_size;
|
||||||
src->pub.next_input_byte = exif_data->data;
|
src->pub.next_input_byte = thumbnail_buffer;
|
||||||
|
|
||||||
src->buffer = exif_data->data;
|
src->buffer = thumbnail_buffer;
|
||||||
src->size = exif_data->size;
|
src->size = thumbnail_size;
|
||||||
|
|
||||||
/* Step 3: read file parameters with jpeg_read_header() */
|
/* Step 3: read file parameters with jpeg_read_header() */
|
||||||
|
|
||||||
|
@ -808,11 +684,11 @@ load_thumbnail_image (const gchar *filename,
|
||||||
cinfo.output_components, cinfo.out_color_space,
|
cinfo.output_components, cinfo.out_color_space,
|
||||||
cinfo.jpeg_color_space);
|
cinfo.jpeg_color_space);
|
||||||
|
|
||||||
if (exif_data)
|
if (metadata)
|
||||||
{
|
g_object_unref (metadata);
|
||||||
exif_data_unref (exif_data);
|
|
||||||
exif_data = NULL;
|
if (thumbnail_buffer)
|
||||||
}
|
g_free (thumbnail_buffer);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
@ -822,7 +698,6 @@ load_thumbnail_image (const gchar *filename,
|
||||||
image_type);
|
image_type);
|
||||||
|
|
||||||
gimp_image_undo_disable (image_ID);
|
gimp_image_undo_disable (image_ID);
|
||||||
gimp_image_set_filename (image_ID, filename);
|
|
||||||
|
|
||||||
jpeg_load_resolution (image_ID, &cinfo);
|
jpeg_load_resolution (image_ID, &cinfo);
|
||||||
|
|
||||||
|
@ -877,7 +752,9 @@ load_thumbnail_image (const gchar *filename,
|
||||||
*/
|
*/
|
||||||
jpeg_destroy_decompress (&cinfo);
|
jpeg_destroy_decompress (&cinfo);
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
|
g_free (thumbnail_buffer);
|
||||||
|
|
||||||
/* free up the temporary buffers */
|
/* free up the temporary buffers */
|
||||||
g_free (rowbuf);
|
g_free (rowbuf);
|
||||||
|
@ -897,17 +774,14 @@ load_thumbnail_image (const gchar *filename,
|
||||||
jerr.pub.error_exit = my_error_exit;
|
jerr.pub.error_exit = my_error_exit;
|
||||||
jerr.pub.output_message = my_output_message;
|
jerr.pub.output_message = my_output_message;
|
||||||
|
|
||||||
if ((infile = g_fopen (filename, "rb")) == NULL)
|
if ((infile = g_fopen (g_file_get_path (file), "rb")) == NULL)
|
||||||
{
|
{
|
||||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||||
_("Could not open '%s' for reading: %s"),
|
_("Could not open '%s' for reading: %s"),
|
||||||
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
g_file_get_parse_name (file), g_strerror (errno));
|
||||||
|
|
||||||
if (exif_data)
|
if (image_ID != -1)
|
||||||
{
|
gimp_image_delete (image_ID);
|
||||||
exif_data_unref (exif_data);
|
|
||||||
exif_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -924,12 +798,6 @@ load_thumbnail_image (const gchar *filename,
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
gimp_image_delete (image_ID);
|
gimp_image_delete (image_ID);
|
||||||
|
|
||||||
if (exif_data)
|
|
||||||
{
|
|
||||||
exif_data_unref (exif_data);
|
|
||||||
exif_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,22 +826,15 @@ load_thumbnail_image (const gchar *filename,
|
||||||
|
|
||||||
fclose (infile);
|
fclose (infile);
|
||||||
|
|
||||||
if (exif_data)
|
#if 0
|
||||||
{
|
|
||||||
exif_data_unref (exif_data);
|
|
||||||
exif_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jpeg_exif_rotate (image_ID, orientation);
|
jpeg_exif_rotate (image_ID, orientation);
|
||||||
|
#endif
|
||||||
|
|
||||||
*type = layer_type;
|
*type = layer_type;
|
||||||
|
|
||||||
return image_ID;
|
return image_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
|
|
||||||
static gpointer
|
static gpointer
|
||||||
jpeg_load_cmyk_transform (guint8 *profile_data,
|
jpeg_load_cmyk_transform (guint8 *profile_data,
|
||||||
gsize profile_len)
|
gsize profile_len)
|
||||||
|
|
|
@ -23,15 +23,10 @@ gint32 load_image (const gchar *filename,
|
||||||
gboolean preview,
|
gboolean preview,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
gint32 load_thumbnail_image (GFile *file,
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
gint32 load_thumbnail_image (const gchar *filename,
|
|
||||||
gint *width,
|
gint *width,
|
||||||
gint *height,
|
gint *height,
|
||||||
GimpImageType *type,
|
GimpImageType *type,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
#endif /* __JPEG_LOAD_H__ */
|
#endif /* __JPEG_LOAD_H__ */
|
||||||
|
|
|
@ -33,10 +33,6 @@
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
#include <jerror.h>
|
#include <jerror.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
#include <libgimp/gimp.h>
|
||||||
#include <libgimp/gimpui.h>
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
@ -47,10 +43,6 @@
|
||||||
#include "jpeg-load.h"
|
#include "jpeg-load.h"
|
||||||
#include "jpeg-save.h"
|
#include "jpeg-save.h"
|
||||||
#include "jpeg-settings.h"
|
#include "jpeg-settings.h"
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include "jpeg-exif.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define SCALE_WIDTH 125
|
#define SCALE_WIDTH 125
|
||||||
|
|
||||||
|
@ -69,6 +61,7 @@
|
||||||
#define DEFAULT_EXIF TRUE
|
#define DEFAULT_EXIF TRUE
|
||||||
#define DEFAULT_THUMBNAIL FALSE
|
#define DEFAULT_THUMBNAIL FALSE
|
||||||
#define DEFAULT_XMP TRUE
|
#define DEFAULT_XMP TRUE
|
||||||
|
#define DEFAULT_IPTC TRUE
|
||||||
#define DEFAULT_USE_ORIG_QUALITY FALSE
|
#define DEFAULT_USE_ORIG_QUALITY FALSE
|
||||||
|
|
||||||
#define JPEG_DEFAULTS_PARASITE "jpeg-save-defaults"
|
#define JPEG_DEFAULTS_PARASITE "jpeg-save-defaults"
|
||||||
|
@ -111,6 +104,7 @@ typedef struct
|
||||||
GtkWidget *save_exif;
|
GtkWidget *save_exif;
|
||||||
GtkWidget *save_thumbnail;
|
GtkWidget *save_thumbnail;
|
||||||
GtkWidget *save_xmp;
|
GtkWidget *save_xmp;
|
||||||
|
GtkWidget *save_iptc;
|
||||||
GtkWidget *use_orig_quality; /*quant tables toggle*/
|
GtkWidget *use_orig_quality; /*quant tables toggle*/
|
||||||
} JpegSaveGui;
|
} JpegSaveGui;
|
||||||
|
|
||||||
|
@ -127,15 +121,6 @@ static void use_orig_qual_changed (GtkWidget *toggle,
|
||||||
static void use_orig_qual_changed2 (GtkWidget *toggle,
|
static void use_orig_qual_changed2 (GtkWidget *toggle,
|
||||||
GtkWidget *combo);
|
GtkWidget *combo);
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
static gint create_thumbnail (gint32 image_ID,
|
|
||||||
gint32 drawable_ID,
|
|
||||||
gdouble quality,
|
|
||||||
guchar **thumbnail_buffer);
|
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
|
|
||||||
static GtkWidget *restart_markers_scale = NULL;
|
static GtkWidget *restart_markers_scale = NULL;
|
||||||
static GtkWidget *restart_markers_label = NULL;
|
static GtkWidget *restart_markers_label = NULL;
|
||||||
|
@ -527,82 +512,6 @@ save_image (const gchar *filename,
|
||||||
*/
|
*/
|
||||||
jpeg_start_compress (&cinfo, TRUE);
|
jpeg_start_compress (&cinfo, TRUE);
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
/* Create the thumbnail JPEG in a buffer */
|
|
||||||
if ((jsvals.save_exif && exif_data) || jsvals.save_thumbnail)
|
|
||||||
{
|
|
||||||
ExifData *exif_data_tmp = NULL;
|
|
||||||
guchar *exif_buf = NULL;
|
|
||||||
guchar *thumbnail_buffer = NULL;
|
|
||||||
gint thumbnail_buffer_length = 0;
|
|
||||||
guint exif_buf_len;
|
|
||||||
gdouble quality = MIN (75.0, jsvals.quality);
|
|
||||||
|
|
||||||
if ( (! jsvals.save_exif) || (! exif_data))
|
|
||||||
exif_data_tmp = exif_data_new ();
|
|
||||||
else
|
|
||||||
exif_data_tmp = exif_data;
|
|
||||||
|
|
||||||
/* avoid saving markers longer than 65533, gradually decrease
|
|
||||||
* quality in steps of 5 until exif_buf_len is lower than that.
|
|
||||||
*/
|
|
||||||
for (exif_buf_len = 65535;
|
|
||||||
exif_buf_len > 65533 && quality > 0.0;
|
|
||||||
quality -= 5.0)
|
|
||||||
{
|
|
||||||
if (jsvals.save_thumbnail)
|
|
||||||
thumbnail_buffer_length = create_thumbnail (image_ID, drawable_ID,
|
|
||||||
quality,
|
|
||||||
&thumbnail_buffer);
|
|
||||||
|
|
||||||
exif_data_tmp->data = thumbnail_buffer;
|
|
||||||
exif_data_tmp->size = thumbnail_buffer_length;
|
|
||||||
|
|
||||||
if (exif_buf)
|
|
||||||
free (exif_buf);
|
|
||||||
|
|
||||||
exif_data_save_data (exif_data_tmp, &exif_buf, &exif_buf_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exif_buf_len > 65533)
|
|
||||||
{
|
|
||||||
/* last attempt with quality 0.0 */
|
|
||||||
if (jsvals.save_thumbnail)
|
|
||||||
thumbnail_buffer_length = create_thumbnail (image_ID, drawable_ID,
|
|
||||||
0.0,
|
|
||||||
&thumbnail_buffer);
|
|
||||||
exif_data_tmp->data = thumbnail_buffer;
|
|
||||||
exif_data_tmp->size = thumbnail_buffer_length;
|
|
||||||
|
|
||||||
if (exif_buf)
|
|
||||||
free (exif_buf);
|
|
||||||
|
|
||||||
exif_data_save_data (exif_data_tmp, &exif_buf, &exif_buf_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exif_buf_len > 65533)
|
|
||||||
{
|
|
||||||
/* still no go? save without thumbnail */
|
|
||||||
exif_data_tmp->data = NULL;
|
|
||||||
exif_data_tmp->size = 0;
|
|
||||||
|
|
||||||
if (exif_buf)
|
|
||||||
free (exif_buf);
|
|
||||||
|
|
||||||
exif_data_save_data (exif_data_tmp, &exif_buf, &exif_buf_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef GIMP_UNSTABLE
|
|
||||||
g_print ("jpeg-save: saving EXIF block (%d bytes)\n", exif_buf_len);
|
|
||||||
#endif
|
|
||||||
jpeg_write_marker (&cinfo, JPEG_APP0 + 1, exif_buf, exif_buf_len);
|
|
||||||
|
|
||||||
if (exif_buf)
|
|
||||||
free (exif_buf);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
/* Step 4.1: Write the comment out - pw */
|
/* Step 4.1: Write the comment out - pw */
|
||||||
if (image_comment && *image_comment)
|
if (image_comment && *image_comment)
|
||||||
{
|
{
|
||||||
|
@ -614,36 +523,7 @@ save_image (const gchar *filename,
|
||||||
(guchar *) image_comment, strlen (image_comment));
|
(guchar *) image_comment, strlen (image_comment));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 4.2: Write the XMP packet in an APP1 marker */
|
/* Step 4.2: store the color profile if there is one */
|
||||||
if (jsvals.save_xmp)
|
|
||||||
{
|
|
||||||
/* FIXME: temporary hack until the right thing is done by a library */
|
|
||||||
parasite = gimp_image_get_parasite (orig_image_ID, "gimp-metadata");
|
|
||||||
if (parasite)
|
|
||||||
{
|
|
||||||
const gchar *xmp_data;
|
|
||||||
glong xmp_data_size;
|
|
||||||
guchar *app_block;
|
|
||||||
|
|
||||||
xmp_data = ((const gchar *) gimp_parasite_data (parasite)) + 10;
|
|
||||||
xmp_data_size = gimp_parasite_data_size (parasite) - 10;
|
|
||||||
#ifdef GIMP_UNSTABLE
|
|
||||||
g_print ("jpeg-save: saving XMP packet (%d bytes)\n",
|
|
||||||
(int) xmp_data_size);
|
|
||||||
#endif
|
|
||||||
app_block = g_malloc (sizeof (JPEG_APP_HEADER_XMP) + xmp_data_size);
|
|
||||||
memcpy (app_block, JPEG_APP_HEADER_XMP,
|
|
||||||
sizeof (JPEG_APP_HEADER_XMP));
|
|
||||||
memcpy (app_block + sizeof (JPEG_APP_HEADER_XMP), xmp_data,
|
|
||||||
xmp_data_size);
|
|
||||||
jpeg_write_marker (&cinfo, JPEG_APP0 + 1, app_block,
|
|
||||||
sizeof (JPEG_APP_HEADER_XMP) + xmp_data_size);
|
|
||||||
g_free (app_block);
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step 4.3: store the color profile if there is one */
|
|
||||||
parasite = gimp_image_get_parasite (orig_image_ID, "icc-profile");
|
parasite = gimp_image_get_parasite (orig_image_ID, "icc-profile");
|
||||||
if (parasite)
|
if (parasite)
|
||||||
{
|
{
|
||||||
|
@ -913,7 +793,7 @@ save_dialog (void)
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||||
gtk_widget_show (frame);
|
gtk_widget_show (frame);
|
||||||
|
|
||||||
table = gtk_table_new (4, 7, FALSE);
|
table = gtk_table_new (4, 8, FALSE);
|
||||||
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
||||||
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
||||||
gtk_table_set_col_spacing (GTK_TABLE (table), 1, 12);
|
gtk_table_set_col_spacing (GTK_TABLE (table), 1, 12);
|
||||||
|
@ -1000,9 +880,9 @@ save_dialog (void)
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
||||||
jsvals.progressive);
|
jsvals.progressive);
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
pg.save_exif = toggle =
|
pg.save_exif = toggle =
|
||||||
gtk_check_button_new_with_mnemonic (_("Save _EXIF data"));
|
gtk_check_button_new_with_mnemonic (_("Save _EXIF data"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_exif);
|
||||||
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
|
||||||
gtk_widget_show (toggle);
|
gtk_widget_show (toggle);
|
||||||
|
|
||||||
|
@ -1013,13 +893,11 @@ save_dialog (void)
|
||||||
G_CALLBACK (make_preview),
|
G_CALLBACK (make_preview),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
gtk_widget_set_sensitive (toggle, TRUE);
|
||||||
jsvals.save_exif && exif_data);
|
|
||||||
|
|
||||||
gtk_widget_set_sensitive (toggle, exif_data != NULL);
|
|
||||||
|
|
||||||
pg.save_thumbnail = toggle =
|
pg.save_thumbnail = toggle =
|
||||||
gtk_check_button_new_with_mnemonic (_("Save _thumbnail"));
|
gtk_check_button_new_with_mnemonic (_("Save _thumbnail"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_thumbnail);
|
||||||
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
|
||||||
gtk_widget_show (toggle);
|
gtk_widget_show (toggle);
|
||||||
|
|
||||||
|
@ -1030,13 +908,10 @@ save_dialog (void)
|
||||||
G_CALLBACK (make_preview),
|
G_CALLBACK (make_preview),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
|
||||||
jsvals.save_thumbnail);
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
/* XMP metadata */
|
/* XMP metadata */
|
||||||
pg.save_xmp = toggle =
|
pg.save_xmp = toggle =
|
||||||
gtk_check_button_new_with_mnemonic (_("Save _XMP data"));
|
gtk_check_button_new_with_mnemonic (_("Save _XMP data"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_xmp);
|
||||||
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 4, 5, GTK_FILL, 0, 0, 0);
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 4, 5, GTK_FILL, 0, 0, 0);
|
||||||
gtk_widget_show (toggle);
|
gtk_widget_show (toggle);
|
||||||
|
|
||||||
|
@ -1047,16 +922,29 @@ save_dialog (void)
|
||||||
G_CALLBACK (make_preview),
|
G_CALLBACK (make_preview),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
gtk_widget_set_sensitive (toggle, TRUE);
|
||||||
jsvals.save_xmp && has_metadata);
|
|
||||||
|
|
||||||
gtk_widget_set_sensitive (toggle, has_metadata);
|
/* IPTC metadata */
|
||||||
|
pg.save_iptc = toggle =
|
||||||
|
gtk_check_button_new_with_mnemonic (_("Save _IPTC data"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_iptc);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 5, 6, GTK_FILL, 0, 0, 0);
|
||||||
|
gtk_widget_show (toggle);
|
||||||
|
|
||||||
|
g_signal_connect (toggle, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
&jsvals.save_iptc);
|
||||||
|
g_signal_connect (toggle, "toggled",
|
||||||
|
G_CALLBACK (make_preview),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_widget_set_sensitive (toggle, TRUE);
|
||||||
|
|
||||||
/* custom quantization tables - now used also for original quality */
|
/* custom quantization tables - now used also for original quality */
|
||||||
pg.use_orig_quality = toggle =
|
pg.use_orig_quality = toggle =
|
||||||
gtk_check_button_new_with_mnemonic (_("_Use quality settings from original "
|
gtk_check_button_new_with_mnemonic (_("_Use quality settings from original "
|
||||||
"image"));
|
"image"));
|
||||||
gtk_table_attach (GTK_TABLE (table), toggle, 0, 4, 5, 6, GTK_FILL, 0, 0, 0);
|
gtk_table_attach (GTK_TABLE (table), toggle, 0, 4, 6, 7, GTK_FILL, 0, 0, 0);
|
||||||
gtk_widget_show (toggle);
|
gtk_widget_show (toggle);
|
||||||
|
|
||||||
gimp_help_set_help_data (toggle,
|
gimp_help_set_help_data (toggle,
|
||||||
|
@ -1266,13 +1154,9 @@ load_defaults (void)
|
||||||
jsvals.save_exif = DEFAULT_EXIF;
|
jsvals.save_exif = DEFAULT_EXIF;
|
||||||
jsvals.save_thumbnail = DEFAULT_THUMBNAIL;
|
jsvals.save_thumbnail = DEFAULT_THUMBNAIL;
|
||||||
jsvals.save_xmp = DEFAULT_XMP;
|
jsvals.save_xmp = DEFAULT_XMP;
|
||||||
|
jsvals.save_iptc = DEFAULT_IPTC;
|
||||||
jsvals.use_orig_quality = DEFAULT_USE_ORIG_QUALITY;
|
jsvals.use_orig_quality = DEFAULT_USE_ORIG_QUALITY;
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
if (exif_data && (exif_data->data))
|
|
||||||
jsvals.save_thumbnail = TRUE;
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
parasite = gimp_get_parasite (JPEG_DEFAULTS_PARASITE);
|
parasite = gimp_get_parasite (JPEG_DEFAULTS_PARASITE);
|
||||||
|
|
||||||
if (! parasite)
|
if (! parasite)
|
||||||
|
@ -1283,7 +1167,7 @@ load_defaults (void)
|
||||||
|
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
|
|
||||||
num_fields = sscanf (def_str, "%lf %lf %d %d %d %d %d %d %d %d %d %d %d",
|
num_fields = sscanf (def_str, "%lf %lf %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||||
&tmpvals.quality,
|
&tmpvals.quality,
|
||||||
&tmpvals.smoothing,
|
&tmpvals.smoothing,
|
||||||
&tmpvals.optimize,
|
&tmpvals.optimize,
|
||||||
|
@ -1296,12 +1180,15 @@ load_defaults (void)
|
||||||
&tmpvals.save_exif,
|
&tmpvals.save_exif,
|
||||||
&tmpvals.save_thumbnail,
|
&tmpvals.save_thumbnail,
|
||||||
&tmpvals.save_xmp,
|
&tmpvals.save_xmp,
|
||||||
&tmpvals.use_orig_quality);
|
&tmpvals.use_orig_quality,
|
||||||
|
&tmpvals.save_iptc);
|
||||||
|
|
||||||
tmpvals.subsmp = subsampling;
|
tmpvals.subsmp = subsampling;
|
||||||
|
|
||||||
if (num_fields == 13)
|
if (num_fields == 13 || num_fields == 14)
|
||||||
memcpy (&jsvals, &tmpvals, sizeof (tmpvals));
|
{
|
||||||
|
memcpy (&jsvals, &tmpvals, sizeof (tmpvals));
|
||||||
|
}
|
||||||
|
|
||||||
g_free (def_str);
|
g_free (def_str);
|
||||||
}
|
}
|
||||||
|
@ -1312,7 +1199,7 @@ save_defaults (void)
|
||||||
GimpParasite *parasite;
|
GimpParasite *parasite;
|
||||||
gchar *def_str;
|
gchar *def_str;
|
||||||
|
|
||||||
def_str = g_strdup_printf ("%lf %lf %d %d %d %d %d %d %d %d %d %d %d",
|
def_str = g_strdup_printf ("%lf %lf %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||||
jsvals.quality,
|
jsvals.quality,
|
||||||
jsvals.smoothing,
|
jsvals.smoothing,
|
||||||
jsvals.optimize,
|
jsvals.optimize,
|
||||||
|
@ -1325,7 +1212,8 @@ save_defaults (void)
|
||||||
jsvals.save_exif,
|
jsvals.save_exif,
|
||||||
jsvals.save_thumbnail,
|
jsvals.save_thumbnail,
|
||||||
jsvals.save_xmp,
|
jsvals.save_xmp,
|
||||||
jsvals.use_orig_quality);
|
jsvals.use_orig_quality,
|
||||||
|
jsvals.save_iptc);
|
||||||
parasite = gimp_parasite_new (JPEG_DEFAULTS_PARASITE,
|
parasite = gimp_parasite_new (JPEG_DEFAULTS_PARASITE,
|
||||||
GIMP_PARASITE_PERSISTENT,
|
GIMP_PARASITE_PERSISTENT,
|
||||||
strlen (def_str), def_str);
|
strlen (def_str), def_str);
|
||||||
|
@ -1350,11 +1238,10 @@ load_gui_defaults (JpegSaveGui *pg)
|
||||||
SET_ACTIVE_BTTN (progressive);
|
SET_ACTIVE_BTTN (progressive);
|
||||||
SET_ACTIVE_BTTN (use_orig_quality);
|
SET_ACTIVE_BTTN (use_orig_quality);
|
||||||
SET_ACTIVE_BTTN (preview);
|
SET_ACTIVE_BTTN (preview);
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
SET_ACTIVE_BTTN (save_exif);
|
SET_ACTIVE_BTTN (save_exif);
|
||||||
SET_ACTIVE_BTTN (save_thumbnail);
|
SET_ACTIVE_BTTN (save_thumbnail);
|
||||||
#endif
|
|
||||||
SET_ACTIVE_BTTN (save_xmp);
|
SET_ACTIVE_BTTN (save_xmp);
|
||||||
|
SET_ACTIVE_BTTN (save_iptc);
|
||||||
|
|
||||||
#undef SET_ACTIVE_BTTN
|
#undef SET_ACTIVE_BTTN
|
||||||
|
|
||||||
|
@ -1447,218 +1334,3 @@ use_orig_qual_changed2 (GtkWidget *toggle,
|
||||||
gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), orig_subsmp);
|
gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), orig_subsmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
static guchar *tbuffer = NULL;
|
|
||||||
static guchar *tbuffer2 = NULL;
|
|
||||||
|
|
||||||
static gint tbuffer_count = 0;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
struct jpeg_destination_mgr pub; /* public fields */
|
|
||||||
guchar *buffer;
|
|
||||||
gint size;
|
|
||||||
} my_destination_mgr;
|
|
||||||
|
|
||||||
typedef my_destination_mgr *my_dest_ptr;
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_destination (j_compress_ptr cinfo)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
empty_output_buffer (j_compress_ptr cinfo)
|
|
||||||
{
|
|
||||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
|
||||||
|
|
||||||
tbuffer_count = tbuffer_count + 16384;
|
|
||||||
tbuffer = g_renew (guchar, tbuffer, tbuffer_count);
|
|
||||||
g_memmove (tbuffer + tbuffer_count - 16384, tbuffer2, 16384);
|
|
||||||
|
|
||||||
dest->pub.next_output_byte = tbuffer2;
|
|
||||||
dest->pub.free_in_buffer = 16384;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
term_destination (j_compress_ptr cinfo)
|
|
||||||
{
|
|
||||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
|
||||||
|
|
||||||
tbuffer_count = (tbuffer_count + 16384) - (dest->pub.free_in_buffer);
|
|
||||||
|
|
||||||
tbuffer = g_renew (guchar, tbuffer, tbuffer_count);
|
|
||||||
g_memmove (tbuffer + tbuffer_count - (16384 - dest->pub.free_in_buffer),
|
|
||||||
tbuffer2, 16384 - dest->pub.free_in_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
create_thumbnail (gint32 image_ID,
|
|
||||||
gint32 drawable_ID,
|
|
||||||
gdouble quality,
|
|
||||||
guchar **thumbnail_buffer)
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
gint req_width, req_height, bpp, rbpp;
|
|
||||||
guchar *thumbnail_data = NULL;
|
|
||||||
struct jpeg_compress_struct cinfo;
|
|
||||||
struct my_error_mgr jerr;
|
|
||||||
my_dest_ptr dest;
|
|
||||||
JSAMPROW scanline[1];
|
|
||||||
guchar *buf = NULL;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
{
|
|
||||||
GeglBuffer *buffer = gimp_drawable_get_buffer (drawable_ID);
|
|
||||||
width = gegl_buffer_get_width (buffer);
|
|
||||||
height = gegl_buffer_get_height (buffer);
|
|
||||||
g_object_unref (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
req_width = 196;
|
|
||||||
req_height = 196;
|
|
||||||
|
|
||||||
if (MIN (width, height) < 196)
|
|
||||||
req_width = req_height = MIN(width, height);
|
|
||||||
|
|
||||||
thumbnail_data = gimp_drawable_get_thumbnail_data (drawable_ID,
|
|
||||||
&req_width, &req_height,
|
|
||||||
&bpp);
|
|
||||||
|
|
||||||
if (! thumbnail_data)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rbpp = bpp;
|
|
||||||
|
|
||||||
if ((bpp == 2) || (bpp == 4))
|
|
||||||
{
|
|
||||||
rbpp = bpp - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = g_new (guchar, req_width * bpp);
|
|
||||||
tbuffer2 = g_new (guchar, 16384);
|
|
||||||
|
|
||||||
tbuffer_count = 0;
|
|
||||||
|
|
||||||
cinfo.err = jpeg_std_error (&jerr.pub);
|
|
||||||
jerr.pub.error_exit = my_error_exit;
|
|
||||||
|
|
||||||
/* Establish the setjmp return context for my_error_exit to use. */
|
|
||||||
if (setjmp (jerr.setjmp_buffer))
|
|
||||||
{
|
|
||||||
/* If we get here, the JPEG code has signaled an error.
|
|
||||||
* We need to clean up the JPEG object, free memory, and return.
|
|
||||||
*/
|
|
||||||
jpeg_destroy_compress (&cinfo);
|
|
||||||
|
|
||||||
if (thumbnail_data)
|
|
||||||
{
|
|
||||||
g_free (thumbnail_data);
|
|
||||||
thumbnail_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf)
|
|
||||||
{
|
|
||||||
g_free (buf);
|
|
||||||
buf = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tbuffer2)
|
|
||||||
{
|
|
||||||
g_free (tbuffer2);
|
|
||||||
tbuffer2 = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we can initialize the JPEG compression object. */
|
|
||||||
jpeg_create_compress (&cinfo);
|
|
||||||
|
|
||||||
if (cinfo.dest == NULL)
|
|
||||||
cinfo.dest = (struct jpeg_destination_mgr *)
|
|
||||||
(*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
|
|
||||||
sizeof(my_destination_mgr));
|
|
||||||
|
|
||||||
dest = (my_dest_ptr) cinfo.dest;
|
|
||||||
dest->pub.init_destination = init_destination;
|
|
||||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
|
||||||
dest->pub.term_destination = term_destination;
|
|
||||||
|
|
||||||
dest->pub.next_output_byte = tbuffer2;
|
|
||||||
dest->pub.free_in_buffer = 16384;
|
|
||||||
|
|
||||||
dest->buffer = tbuffer2;
|
|
||||||
dest->size = 16384;
|
|
||||||
|
|
||||||
cinfo.input_components = rbpp;
|
|
||||||
cinfo.image_width = req_width;
|
|
||||||
cinfo.image_height = req_height;
|
|
||||||
|
|
||||||
/* colorspace of input image */
|
|
||||||
cinfo.in_color_space = (rbpp == 3) ? JCS_RGB : JCS_GRAYSCALE;
|
|
||||||
|
|
||||||
/* Now use the library's routine to set default compression parameters.
|
|
||||||
* (You must set at least cinfo.in_color_space before calling this,
|
|
||||||
* since the defaults depend on the source color space.)
|
|
||||||
*/
|
|
||||||
jpeg_set_defaults (&cinfo);
|
|
||||||
|
|
||||||
jpeg_set_quality (&cinfo, (gint) (quality + 0.5), jsvals.baseline);
|
|
||||||
|
|
||||||
/* Step 4: Start compressor */
|
|
||||||
|
|
||||||
/* TRUE ensures that we will write a complete interchange-JPEG file.
|
|
||||||
* Pass TRUE unless you are very sure of what you're doing.
|
|
||||||
*/
|
|
||||||
jpeg_start_compress (&cinfo, TRUE);
|
|
||||||
|
|
||||||
while (cinfo.next_scanline < (unsigned int) req_height)
|
|
||||||
{
|
|
||||||
for (i = 0; i < req_width; i++)
|
|
||||||
{
|
|
||||||
buf[(i * rbpp) + 0] = thumbnail_data[(cinfo.next_scanline * req_width * bpp) + (i * bpp) + 0];
|
|
||||||
|
|
||||||
if (rbpp == 3)
|
|
||||||
{
|
|
||||||
buf[(i * rbpp) + 1] = thumbnail_data[(cinfo.next_scanline * req_width * bpp) + (i * bpp) + 1];
|
|
||||||
buf[(i * rbpp) + 2] = thumbnail_data[(cinfo.next_scanline * req_width * bpp) + (i * bpp) + 2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scanline[0] = buf;
|
|
||||||
jpeg_write_scanlines (&cinfo, scanline, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step 6: Finish compression */
|
|
||||||
jpeg_finish_compress (&cinfo);
|
|
||||||
|
|
||||||
/* Step 7: release JPEG compression object */
|
|
||||||
|
|
||||||
/* This is an important step since it will release a good deal of memory. */
|
|
||||||
jpeg_destroy_compress (&cinfo);
|
|
||||||
|
|
||||||
/* And we're done! */
|
|
||||||
|
|
||||||
if (thumbnail_data)
|
|
||||||
{
|
|
||||||
g_free (thumbnail_data);
|
|
||||||
thumbnail_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf)
|
|
||||||
{
|
|
||||||
g_free (buf);
|
|
||||||
buf = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*thumbnail_buffer = tbuffer;
|
|
||||||
|
|
||||||
return tbuffer_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ typedef struct
|
||||||
gboolean save_exif;
|
gboolean save_exif;
|
||||||
gboolean save_thumbnail;
|
gboolean save_thumbnail;
|
||||||
gboolean save_xmp;
|
gboolean save_xmp;
|
||||||
|
gboolean save_iptc;
|
||||||
gboolean use_orig_quality;
|
gboolean use_orig_quality;
|
||||||
} JpegSaveVals;
|
} JpegSaveVals;
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,6 @@
|
||||||
|
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
#include <libgimp/gimp.h>
|
||||||
|
|
||||||
#include "libgimp/stdplugins-intl.h"
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
#include <jerror.h>
|
#include <jerror.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
#include <libgimp/gimp.h>
|
||||||
#include <libgimp/gimpui.h>
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
@ -37,11 +33,6 @@
|
||||||
#include "jpeg-settings.h"
|
#include "jpeg-settings.h"
|
||||||
#include "jpeg-load.h"
|
#include "jpeg-load.h"
|
||||||
#include "jpeg-save.h"
|
#include "jpeg-save.h"
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include "jpeg-exif.h"
|
|
||||||
#include "gimpexif.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Declare local functions.
|
/* Declare local functions.
|
||||||
*/
|
*/
|
||||||
|
@ -66,10 +57,6 @@ JpegSubsampling orig_subsmp;
|
||||||
gint num_quant_tables;
|
gint num_quant_tables;
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
ExifData *exif_data = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const GimpPlugInInfo PLUG_IN_INFO =
|
const GimpPlugInInfo PLUG_IN_INFO =
|
||||||
{
|
{
|
||||||
NULL, /* init_proc */
|
NULL, /* init_proc */
|
||||||
|
@ -96,8 +83,6 @@ query (void)
|
||||||
{ GIMP_PDB_IMAGE, "image", "Output image" }
|
{ GIMP_PDB_IMAGE, "image", "Output image" }
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
static const GimpParamDef thumb_args[] =
|
static const GimpParamDef thumb_args[] =
|
||||||
{
|
{
|
||||||
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
|
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
|
||||||
|
@ -110,8 +95,6 @@ query (void)
|
||||||
{ GIMP_PDB_INT32, "image-height", "Height of full-sized image" }
|
{ GIMP_PDB_INT32, "image-height", "Height of full-sized image" }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
static const GimpParamDef save_args[] =
|
static const GimpParamDef save_args[] =
|
||||||
{
|
{
|
||||||
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
|
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
|
||||||
|
@ -149,8 +132,6 @@ query (void)
|
||||||
"",
|
"",
|
||||||
"6,string,JFIF,6,string,Exif");
|
"6,string,JFIF,6,string,Exif");
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
gimp_install_procedure (LOAD_THUMB_PROC,
|
gimp_install_procedure (LOAD_THUMB_PROC,
|
||||||
"Loads a thumbnail from a JPEG image",
|
"Loads a thumbnail from a JPEG image",
|
||||||
"Loads a thumbnail from a JPEG image (only if it exists)",
|
"Loads a thumbnail from a JPEG image (only if it exists)",
|
||||||
|
@ -166,8 +147,6 @@ query (void)
|
||||||
|
|
||||||
gimp_register_thumbnail_loader (LOAD_PROC, LOAD_THUMB_PROC);
|
gimp_register_thumbnail_loader (LOAD_PROC, LOAD_THUMB_PROC);
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
gimp_install_procedure (SAVE_PROC,
|
gimp_install_procedure (SAVE_PROC,
|
||||||
"saves files in the JPEG file format",
|
"saves files in the JPEG file format",
|
||||||
"saves files in the lossy, widely supported JPEG format",
|
"saves files in the lossy, widely supported JPEG format",
|
||||||
|
@ -237,6 +216,13 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
{
|
{
|
||||||
|
GFile *file = g_file_new_for_path (param[1].data.d_string);
|
||||||
|
|
||||||
|
gimp_image_metadata_load (image_ID, "image/jpeg", file,
|
||||||
|
load_interactive);
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
*nreturn_vals = 2;
|
*nreturn_vals = 2;
|
||||||
values[1].type = GIMP_PDB_IMAGE;
|
values[1].type = GIMP_PDB_IMAGE;
|
||||||
values[1].data.d_image = image_ID;
|
values[1].data.d_image = image_ID;
|
||||||
|
@ -247,9 +233,6 @@ run (const gchar *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
|
|
||||||
else if (strcmp (name, LOAD_THUMB_PROC) == 0)
|
else if (strcmp (name, LOAD_THUMB_PROC) == 0)
|
||||||
{
|
{
|
||||||
if (nparams < 2)
|
if (nparams < 2)
|
||||||
|
@ -258,14 +241,16 @@ run (const gchar *name,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const gchar *filename = param[0].data.d_string;
|
GFile *file = g_file_new_for_path (param[0].data.d_string);
|
||||||
gint width = 0;
|
gint width = 0;
|
||||||
gint height = 0;
|
gint height = 0;
|
||||||
GimpImageType type = -1;
|
GimpImageType type = -1;
|
||||||
|
|
||||||
image_ID = load_thumbnail_image (filename, &width, &height, &type,
|
image_ID = load_thumbnail_image (file, &width, &height, &type,
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
{
|
{
|
||||||
*nreturn_vals = 6;
|
*nreturn_vals = 6;
|
||||||
|
@ -286,9 +271,6 @@ run (const gchar *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
else if (strcmp (name, SAVE_PROC) == 0)
|
else if (strcmp (name, SAVE_PROC) == 0)
|
||||||
{
|
{
|
||||||
image_ID = orig_image_ID = param[1].data.d_int32;
|
image_ID = orig_image_ID = param[1].data.d_int32;
|
||||||
|
@ -348,14 +330,7 @@ run (const gchar *name,
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
/* load defaults from gimp parasite */
|
||||||
|
|
||||||
exif_data = gimp_metadata_generate_exif (orig_image_ID);
|
|
||||||
if (exif_data)
|
|
||||||
jpeg_setup_exif_for_save (exif_data, orig_image_ID);
|
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
load_defaults ();
|
load_defaults ();
|
||||||
|
|
||||||
switch (run_mode)
|
switch (run_mode)
|
||||||
|
@ -427,6 +402,7 @@ run (const gchar *name,
|
||||||
jsvals.save_exif = save_vals->save_exif;
|
jsvals.save_exif = save_vals->save_exif;
|
||||||
jsvals.save_thumbnail = save_vals->save_thumbnail;
|
jsvals.save_thumbnail = save_vals->save_thumbnail;
|
||||||
jsvals.save_xmp = save_vals->save_xmp;
|
jsvals.save_xmp = save_vals->save_xmp;
|
||||||
|
jsvals.save_iptc = save_vals->save_iptc;
|
||||||
jsvals.use_orig_quality = save_vals->use_orig_quality;
|
jsvals.use_orig_quality = save_vals->use_orig_quality;
|
||||||
|
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
|
@ -511,9 +487,12 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (status == GIMP_PDB_SUCCESS)
|
if (status == GIMP_PDB_SUCCESS)
|
||||||
{
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
/* pw - now we need to change the defaults to be whatever
|
/* pw - now we need to change the defaults to be whatever
|
||||||
* was used to save this image. Dump the old parasites
|
* was used to save this image. Dump the old parasites
|
||||||
* and add new ones. */
|
* and add new ones.
|
||||||
|
*/
|
||||||
|
|
||||||
gimp_image_detach_parasite (orig_image_ID, "gimp-comment");
|
gimp_image_detach_parasite (orig_image_ID, "gimp-comment");
|
||||||
if (image_comment && strlen (image_comment))
|
if (image_comment && strlen (image_comment))
|
||||||
|
@ -526,11 +505,36 @@ run (const gchar *name,
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
}
|
}
|
||||||
|
|
||||||
gimp_image_detach_parasite (orig_image_ID, "jpeg-save-options");
|
|
||||||
parasite = gimp_parasite_new ("jpeg-save-options",
|
parasite = gimp_parasite_new ("jpeg-save-options",
|
||||||
0, sizeof (jsvals), &jsvals);
|
0, sizeof (jsvals), &jsvals);
|
||||||
gimp_image_attach_parasite (orig_image_ID, parasite);
|
gimp_image_attach_parasite (orig_image_ID, parasite);
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
|
|
||||||
|
/* write metadata */
|
||||||
|
metadata = gimp_image_metadata_save_prepare (image_ID,
|
||||||
|
"image/jpeg");
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
GimpMetadataSaveFlags flags = 0;
|
||||||
|
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 8);
|
||||||
|
|
||||||
|
if (jsvals.save_exif) flags |= GIMP_METADATA_SAVE_EXIF;
|
||||||
|
if (jsvals.save_xmp) flags |= GIMP_METADATA_SAVE_XMP;
|
||||||
|
if (jsvals.save_iptc) flags |= GIMP_METADATA_SAVE_IPTC;
|
||||||
|
if (jsvals.save_thumbnail) flags |= GIMP_METADATA_SAVE_THUMBNAIL;
|
||||||
|
|
||||||
|
file = g_file_new_for_path (param[3].data.d_string);
|
||||||
|
gimp_image_metadata_save_finish (image_ID,
|
||||||
|
"image/jpeg",
|
||||||
|
metadata, file, flags,
|
||||||
|
NULL);
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -94,9 +94,6 @@
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
#include <jerror.h>
|
#include <jerror.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
#include <libexif/exif-data.h>
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
#ifdef HAVE_IPTCDATA
|
#ifdef HAVE_IPTCDATA
|
||||||
#include <libiptcdata/iptc-data.h>
|
#include <libiptcdata/iptc-data.h>
|
||||||
#endif /* HAVE_IPTCDATA */
|
#endif /* HAVE_IPTCDATA */
|
||||||
|
@ -196,11 +193,6 @@ static gint load_resource_1058 (const PSDimageres *res_a,
|
||||||
FILE *f,
|
FILE *f,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
static gint load_resource_1060 (const PSDimageres *res_a,
|
|
||||||
const gint32 image_id,
|
|
||||||
FILE *f,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
static gint load_resource_2000 (const PSDimageres *res_a,
|
static gint load_resource_2000 (const PSDimageres *res_a,
|
||||||
const gint32 image_id,
|
const gint32 image_id,
|
||||||
FILE *f,
|
FILE *f,
|
||||||
|
@ -353,7 +345,6 @@ load_image_resource (PSDimageres *res_a,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PSD_XMP_DATA:
|
case PSD_XMP_DATA:
|
||||||
load_resource_1060 (res_a, image_id, f, error);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1209,21 +1200,7 @@ load_resource_1058 (const PSDimageres *res_a,
|
||||||
FILE *f,
|
FILE *f,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
/* Load EXIF data block */
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
ExifData *exif_data;
|
|
||||||
ExifEntry *exif_entry;
|
|
||||||
guchar *exif_buf;
|
|
||||||
guchar *tmp_data;
|
|
||||||
guint exif_buf_len;
|
|
||||||
gint16 jpeg_len;
|
|
||||||
gint16 jpeg_fill = 0;
|
|
||||||
GimpParam *return_vals;
|
|
||||||
gint nreturn_vals;
|
|
||||||
#else
|
|
||||||
gchar *name;
|
gchar *name;
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
GimpParasite *parasite;
|
GimpParasite *parasite;
|
||||||
gchar *res_data;
|
gchar *res_data;
|
||||||
|
@ -1238,79 +1215,6 @@ load_resource_1058 (const PSDimageres *res_a,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBEXIF
|
|
||||||
/* Add JPEG header & trailer to the TIFF Exif data held in PSD
|
|
||||||
resource to allow us to use libexif to serialize the data
|
|
||||||
in the same manner as the JPEG load.
|
|
||||||
*/
|
|
||||||
jpeg_len = res_a->data_len + 8;
|
|
||||||
tmp_data = g_malloc (res_a->data_len + 12);
|
|
||||||
/* SOI & APP1 markers */
|
|
||||||
memcpy (tmp_data, "\xFF\xD8\xFF\xE1", 4);
|
|
||||||
/* APP1 block len */
|
|
||||||
memcpy (tmp_data + 4, &jpeg_len, 2);
|
|
||||||
/* Exif marker */
|
|
||||||
memcpy (tmp_data + 6, "Exif", 4);
|
|
||||||
/* Filler */
|
|
||||||
memcpy (tmp_data + 10, &jpeg_fill, 2);
|
|
||||||
/* Exif data */
|
|
||||||
memcpy (tmp_data + 12, res_data, res_a->data_len);
|
|
||||||
|
|
||||||
/* Create Exif data structure */
|
|
||||||
exif_data = exif_data_new_from_data (tmp_data, res_a->data_len + 12);
|
|
||||||
g_free (tmp_data);
|
|
||||||
IFDBG (3) exif_data_dump (exif_data);
|
|
||||||
|
|
||||||
/* Check for XMP data block in Exif data - PS7 */
|
|
||||||
if ((exif_entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_XML_PACKET)))
|
|
||||||
{
|
|
||||||
IFDBG(3) g_debug ("Processing Exif XMP data block");
|
|
||||||
/*Create NULL terminated EXIF data block */
|
|
||||||
tmp_data = g_malloc (exif_entry->size + 1);
|
|
||||||
memcpy (tmp_data, exif_entry->data, exif_entry->size);
|
|
||||||
tmp_data[exif_entry->size] = 0;
|
|
||||||
/* Merge with existing XMP data block */
|
|
||||||
return_vals = gimp_run_procedure (DECODE_XMP_PROC,
|
|
||||||
&nreturn_vals,
|
|
||||||
GIMP_PDB_IMAGE, image_id,
|
|
||||||
GIMP_PDB_STRING, tmp_data,
|
|
||||||
GIMP_PDB_END);
|
|
||||||
g_free (tmp_data);
|
|
||||||
gimp_destroy_params (return_vals, nreturn_vals);
|
|
||||||
IFDBG(3) g_debug ("Deleting XMP block from Exif data");
|
|
||||||
/* Delete XMP data from Exif block */
|
|
||||||
exif_content_remove_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
exif_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for Photoshp Image Resource data block in Exif data - PS7 */
|
|
||||||
if ((exif_entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
EXIF_TAG_IMAGE_RESOURCES)))
|
|
||||||
{
|
|
||||||
IFDBG(3) g_debug ("Deleting PS Image Resource block from Exif data");
|
|
||||||
/* Delete PS Image Resource data from Exif block */
|
|
||||||
exif_content_remove_entry (exif_data->ifd[EXIF_IFD_0],
|
|
||||||
exif_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
IFDBG (3) exif_data_dump (exif_data);
|
|
||||||
/* Store resource data as a GIMP Exif parasite */
|
|
||||||
IFDBG (2) g_debug ("Processing exif data as GIMP Exif parasite");
|
|
||||||
/* Serialize exif data */
|
|
||||||
exif_data_save_data (exif_data, &exif_buf, &exif_buf_len);
|
|
||||||
if (exif_buf_len > EXIF_HEADER_SIZE)
|
|
||||||
{
|
|
||||||
parasite = gimp_parasite_new (GIMP_PARASITE_EXIF,
|
|
||||||
GIMP_PARASITE_PERSISTENT,
|
|
||||||
exif_buf_len, exif_buf);
|
|
||||||
gimp_image_attach_parasite (image_id, parasite);
|
|
||||||
gimp_parasite_free (parasite);
|
|
||||||
}
|
|
||||||
exif_data_unref (exif_data);
|
|
||||||
g_free (exif_buf);
|
|
||||||
|
|
||||||
#else
|
|
||||||
/* Store resource data as a standard psd parasite */
|
/* Store resource data as a standard psd parasite */
|
||||||
IFDBG (2) g_debug ("Processing exif data as psd parasite");
|
IFDBG (2) g_debug ("Processing exif data as psd parasite");
|
||||||
name = g_strdup_printf ("psd-image-resource-%.4s-%.4x",
|
name = g_strdup_printf ("psd-image-resource-%.4s-%.4x",
|
||||||
|
@ -1322,45 +1226,10 @@ load_resource_1058 (const PSDimageres *res_a,
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
#endif /* HAVE_LIBEXIF */
|
|
||||||
|
|
||||||
g_free (res_data);
|
g_free (res_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
|
||||||
load_resource_1060 (const PSDimageres *res_a,
|
|
||||||
const gint32 image_id,
|
|
||||||
FILE *f,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
/* Load XMP Metadata block */
|
|
||||||
GimpParam *return_vals;
|
|
||||||
gint nreturn_vals;
|
|
||||||
gchar *res_data;
|
|
||||||
|
|
||||||
IFDBG(2) g_debug ("Process image resource block: 1060: XMP Data");
|
|
||||||
|
|
||||||
res_data = g_malloc (res_a->data_len + 1);
|
|
||||||
if (fread (res_data, res_a->data_len, 1, f) < 1)
|
|
||||||
{
|
|
||||||
psd_set_error (feof (f), errno, error);
|
|
||||||
g_free (res_data);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* Null terminate metadata block for decode procedure */
|
|
||||||
res_data[res_a->data_len] = 0;
|
|
||||||
|
|
||||||
return_vals = gimp_run_procedure (DECODE_XMP_PROC,
|
|
||||||
&nreturn_vals,
|
|
||||||
GIMP_PDB_IMAGE, image_id,
|
|
||||||
GIMP_PDB_STRING, res_data,
|
|
||||||
GIMP_PDB_END);
|
|
||||||
g_free (res_data);
|
|
||||||
gimp_destroy_params (return_vals, nreturn_vals);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
load_resource_2000 (const PSDimageres *res_a,
|
load_resource_2000 (const PSDimageres *res_a,
|
||||||
const gint32 image_id,
|
const gint32 image_id,
|
||||||
|
|
|
@ -293,6 +293,33 @@ run (const gchar *name,
|
||||||
|
|
||||||
if (save_image (param[3].data.d_string, image_id, &error))
|
if (save_image (param[3].data.d_string, image_id, &error))
|
||||||
{
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
|
||||||
|
metadata = gimp_image_metadata_save_prepare (image_id,
|
||||||
|
"image/x-psd");
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
GimpMetadataSaveFlags flags = 0;
|
||||||
|
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 8);
|
||||||
|
|
||||||
|
if (TRUE) flags |= GIMP_METADATA_SAVE_EXIF;
|
||||||
|
if (TRUE) flags |= GIMP_METADATA_SAVE_XMP;
|
||||||
|
if (TRUE) flags |= GIMP_METADATA_SAVE_IPTC;
|
||||||
|
if (TRUE) flags |= GIMP_METADATA_SAVE_THUMBNAIL;
|
||||||
|
|
||||||
|
file = g_file_new_for_path (param[3].data.d_string);
|
||||||
|
gimp_image_metadata_save_finish (image_id,
|
||||||
|
"image/x-psd",
|
||||||
|
metadata, file, flags,
|
||||||
|
NULL);
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
values[0].data.d_status = GIMP_PDB_SUCCESS;
|
values[0].data.d_status = GIMP_PDB_SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
#include "psd.h"
|
#include "psd.h"
|
||||||
#include "psd-load.h"
|
#include "psd-load.h"
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
|
|
||||||
#include "libgimp/stdplugins-intl.h"
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
||||||
|
|
||||||
/* Local function prototypes */
|
/* Local function prototypes */
|
||||||
|
|
||||||
static void query (void);
|
static void query (void);
|
||||||
|
@ -168,6 +170,7 @@ run (const gchar *name,
|
||||||
GimpParam **return_vals)
|
GimpParam **return_vals)
|
||||||
{
|
{
|
||||||
static GimpParam values[4];
|
static GimpParam values[4];
|
||||||
|
GimpRunMode run_mode;
|
||||||
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
||||||
gint32 image_ID;
|
gint32 image_ID;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
@ -176,6 +179,8 @@ run (const gchar *name,
|
||||||
GimpExportReturn export = GIMP_EXPORT_CANCEL;
|
GimpExportReturn export = GIMP_EXPORT_CANCEL;
|
||||||
#endif /* PSD_SAVE */
|
#endif /* PSD_SAVE */
|
||||||
|
|
||||||
|
run_mode = param[0].data.d_int32;
|
||||||
|
|
||||||
INIT_I18N ();
|
INIT_I18N ();
|
||||||
|
|
||||||
*nreturn_vals = 1;
|
*nreturn_vals = 1;
|
||||||
|
@ -187,10 +192,31 @@ run (const gchar *name,
|
||||||
/* File load */
|
/* File load */
|
||||||
if (strcmp (name, LOAD_PROC) == 0)
|
if (strcmp (name, LOAD_PROC) == 0)
|
||||||
{
|
{
|
||||||
|
gboolean interactive;
|
||||||
|
|
||||||
|
switch (run_mode)
|
||||||
|
{
|
||||||
|
case GIMP_RUN_INTERACTIVE:
|
||||||
|
case GIMP_RUN_WITH_LAST_VALS:
|
||||||
|
gimp_ui_init (PLUG_IN_BINARY, FALSE);
|
||||||
|
interactive = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interactive = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
image_ID = load_image (param[1].data.d_string, &error);
|
image_ID = load_image (param[1].data.d_string, &error);
|
||||||
|
|
||||||
if (image_ID != -1)
|
if (image_ID != -1)
|
||||||
{
|
{
|
||||||
|
GFile *file = g_file_new_for_path (param[1].data.d_string);
|
||||||
|
|
||||||
|
gimp_image_metadata_load (image_ID, "image/x-psd", file,
|
||||||
|
interactive);
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
|
||||||
*nreturn_vals = 2;
|
*nreturn_vals = 2;
|
||||||
values[1].type = GIMP_PDB_IMAGE;
|
values[1].type = GIMP_PDB_IMAGE;
|
||||||
values[1].data.d_image = image_ID;
|
values[1].data.d_image = image_ID;
|
||||||
|
@ -237,9 +263,6 @@ run (const gchar *name,
|
||||||
/* File save */
|
/* File save */
|
||||||
else if (strcmp (name, SAVE_PROC) == 0)
|
else if (strcmp (name, SAVE_PROC) == 0)
|
||||||
{
|
{
|
||||||
GimpRunMode run_mode;
|
|
||||||
|
|
||||||
run_mode = param[0].data.d_int32;
|
|
||||||
image_ID = param[1].data.d_int32;
|
image_ID = param[1].data.d_int32;
|
||||||
drawable_ID = param[2].data.d_int32;
|
drawable_ID = param[2].data.d_int32;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ uidatadir = $(gimpdatadir)/ui/plug-ins
|
||||||
|
|
||||||
uidata_DATA = \
|
uidata_DATA = \
|
||||||
plug-in-file-gif.ui \
|
plug-in-file-gif.ui \
|
||||||
plug-in-file-png.ui
|
plug-in-file-png.ui \
|
||||||
|
plug-in-file-tiff.ui \
|
||||||
|
plug-in-metadata.ui
|
||||||
|
|
||||||
EXTRA_DIST = $(uidata_DATA)
|
EXTRA_DIST = $(uidata_DATA)
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<interface>
|
<interface>
|
||||||
<!-- interface-requires gtk+ 2.12 -->
|
<requires lib="gtk+" version="2.24"/>
|
||||||
<!-- interface-naming-policy project-wide -->
|
<!-- interface-naming-policy project-wide -->
|
||||||
<object class="GtkAdjustment" id="compression-level">
|
<object class="GtkAdjustment" id="compression-level">
|
||||||
<property name="upper">9</property>
|
<property name="upper">9</property>
|
||||||
|
|
||||||
<!-- NOTE: Set value _after_ upper so the value don't get clamped -->
|
|
||||||
<property name="value">9</property>
|
<property name="value">9</property>
|
||||||
|
|
||||||
<property name="step_increment">1</property>
|
<property name="step_increment">1</property>
|
||||||
<property name="page_increment">1</property>
|
<property name="page_increment">1</property>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkTable" id="table">
|
<object class="GtkTable" id="table">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
<property name="border_width">12</property>
|
<property name="border_width">12</property>
|
||||||
<property name="n_rows">10</property>
|
<property name="n_rows">11</property>
|
||||||
<property name="n_columns">3</property>
|
<property name="n_columns">3</property>
|
||||||
<property name="column_spacing">6</property>
|
<property name="column_spacing">6</property>
|
||||||
<property name="row_spacing">6</property>
|
<property name="row_spacing">6</property>
|
||||||
|
@ -25,6 +23,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -38,6 +37,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -52,6 +52,7 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -67,6 +68,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -82,6 +84,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -97,6 +100,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -112,6 +116,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -128,6 +133,7 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -139,6 +145,7 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel" id="compression-level-label">
|
<object class="GtkLabel" id="compression-level-label">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
<property name="label" translatable="yes">Co_mpression level:</property>
|
<property name="label" translatable="yes">Co_mpression level:</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
@ -147,7 +154,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="top_attach">8</property>
|
<property name="top_attach">8</property>
|
||||||
<property name="bottom_attach">9</property>
|
<property name="bottom_attach">9</property>
|
||||||
<property name="x_options"></property>
|
<property name="x_options"/>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -170,7 +177,9 @@
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="has_tooltip">True</property>
|
<property name="has_tooltip">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Choose a high compression level for small file size</property>
|
<property name="tooltip_text" translatable="yes">Choose a high compression level for small file size</property>
|
||||||
<property name="invisible_char">●</property>
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="primary_icon_activatable">False</property>
|
||||||
|
<property name="secondary_icon_activatable">False</property>
|
||||||
<property name="adjustment">compression-level</property>
|
<property name="adjustment">compression-level</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
</object>
|
</object>
|
||||||
|
@ -179,12 +188,13 @@
|
||||||
<property name="right_attach">3</property>
|
<property name="right_attach">3</property>
|
||||||
<property name="top_attach">8</property>
|
<property name="top_attach">8</property>
|
||||||
<property name="bottom_attach">9</property>
|
<property name="bottom_attach">9</property>
|
||||||
<property name="x_options"></property>
|
<property name="x_options"/>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkHButtonBox" id="hbuttonbox">
|
<object class="GtkHButtonBox" id="hbuttonbox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
<property name="spacing">6</property>
|
<property name="spacing">6</property>
|
||||||
<property name="layout_style">start</property>
|
<property name="layout_style">start</property>
|
||||||
<child>
|
<child>
|
||||||
|
@ -216,6 +226,94 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="top_attach">10</property>
|
||||||
|
<property name="bottom_attach">11</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkExpander" id="expander1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_exif">
|
||||||
|
<property name="label" translatable="yes">Save EXIF data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_xmp">
|
||||||
|
<property name="label" translatable="yes">Save XMP data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_iptc">
|
||||||
|
<property name="label" translatable="yes">Save IPTC data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_thumbnail">
|
||||||
|
<property name="label" translatable="yes">Save thumbnail</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Advanced</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="right_attach">3</property>
|
<property name="right_attach">3</property>
|
||||||
<property name="top_attach">9</property>
|
<property name="top_attach">9</property>
|
||||||
|
|
404
plug-ins/ui/plug-in-file-tiff.ui
Normal file
404
plug-ins/ui/plug-in-file-tiff.ui
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.24"/>
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkVBox" id="tiff_export_vbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="frame1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_none">
|
||||||
|
<property name="label" translatable="yes">no compression</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_lzw">
|
||||||
|
<property name="label" translatable="yes">LZW</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">cmp_none</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_packbits">
|
||||||
|
<property name="label" translatable="yes">PackBits</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">cmp_none</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_deflate">
|
||||||
|
<property name="label" translatable="yes">Deflate</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">cmp_none</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_jpeg">
|
||||||
|
<property name="label" translatable="yes">JPEG</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">cmp_none</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">3</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_g3">
|
||||||
|
<property name="label" translatable="yes">CCITT Group 3 fax</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">cmp_none</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="cmp_g4">
|
||||||
|
<property name="label" translatable="yes">CCITT Group _4 fax</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">cmp_none</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">3</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="compresslabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes"><b>Compression</b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">3</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox7">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_alpha">
|
||||||
|
<property name="label" translatable="yes">Save color values from transparent pixels</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">6</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="frame2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="commentfield">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
<property name="primary_icon_activatable">False</property>
|
||||||
|
<property name="secondary_icon_activatable">False</property>
|
||||||
|
<property name="primary_icon_sensitive">True</property>
|
||||||
|
<property name="secondary_icon_sensitive">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">3</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="commentlabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes"><b>Comment</b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">3</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkExpander" id="expander1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_exif">
|
||||||
|
<property name="label" translatable="yes">save EXIF data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_xmp">
|
||||||
|
<property name="label" translatable="yes">save XMP data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox6">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_iptc">
|
||||||
|
<property name="label" translatable="yes">save IPTC data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="sv_thumbnail">
|
||||||
|
<property name="label" translatable="yes">save thumbnail</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="adv_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Advanced</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">3</property>
|
||||||
|
<property name="position">6</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
908
plug-ins/ui/plug-in-metadata.ui
Normal file
908
plug-ins/ui/plug-in-metadata.ui
Normal file
|
@ -0,0 +1,908 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<!-- interface-requires gtk+ 3.0 -->
|
||||||
|
<object class="GtkListStore" id="exif-liststore">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name c_exif_tag -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
<!-- column-name c_exif_value -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="xmp-liststore">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name c_xmp_tag -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
<!-- column-name c_xmp_value -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
</object>
|
||||||
|
<object class="GtkVBox" id="metadata-vbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkNotebook" id="metadata-notebook">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="scrollable">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="exif-scroll">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="exif-treeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="model">exif-liststore</property>
|
||||||
|
<property name="headers_clickable">False</property>
|
||||||
|
<property name="search_column">0</property>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection" id="exif-treeview-selection"/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="exif_tag_column">
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<property name="title" translatable="yes">EXIF Tag</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="exif_tag_cell_renderer"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="exif_value_column">
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<property name="title" translatable="yes">Value</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="exif_value_cell_renderer"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">1</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="exif">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">4</property>
|
||||||
|
<property name="ypad">4</property>
|
||||||
|
<property name="label" translatable="yes">EXIF</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="tab_expand">True</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="xmp-scroll">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="xm-ptreeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="model">xmp-liststore</property>
|
||||||
|
<property name="headers_clickable">False</property>
|
||||||
|
<property name="search_column">0</property>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection" id="xmp-treeview-selection"/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="xmp_tag_column">
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<property name="title" translatable="yes">XMP Tag</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="xmp_tag_cell_renderer"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="xmp_value_column">
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<property name="title" translatable="yes">Value</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="xmp_value_cell_renderer"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">1</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="xmp">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">4</property>
|
||||||
|
<property name="ypad">4</property>
|
||||||
|
<property name="label" translatable="yes">XMP</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="box1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkNotebook" id="iptc-notebook">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="box2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="desctable">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="n_rows">8</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<property name="column_spacing">3</property>
|
||||||
|
<property name="row_spacing">3</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_title">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Title</property>
|
||||||
|
<property name="single_line_mode">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_author">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Author</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_authortitle">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Authortitle</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_copyright">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Copyright</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_caption">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Caption</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
<property name="bottom_attach">5</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_captionwriter">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Captionwriter</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
<property name="bottom_attach">6</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_headline">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Headline</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">6</property>
|
||||||
|
<property name="bottom_attach">7</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_specialinstruct">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Special
|
||||||
|
Instructions</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">7</property>
|
||||||
|
<property name="bottom_attach">8</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.ObjectName">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Byline">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.BylineTitle">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Copyright">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Writer">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
<property name="bottom_attach">6</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="caption_scroll">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="Iptc.Application2.Caption">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
<property name="bottom_attach">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="headline_scroll">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="Iptc.Application2.Headline">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">6</property>
|
||||||
|
<property name="bottom_attach">7</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="instruct_scroll">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="Iptc.Application2.SpecialInstructions">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">7</property>
|
||||||
|
<property name="bottom_attach">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="iptcdesc">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">2</property>
|
||||||
|
<property name="ypad">2</property>
|
||||||
|
<property name="label" translatable="yes">Description</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="box3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="n_rows">4</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<property name="column_spacing">3</property>
|
||||||
|
<property name="row_spacing">3</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_keywords1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Keywords</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_category1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Category</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_suppcat1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Supplemental
|
||||||
|
Category</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_urgency1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Urgency</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolledwindow10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="Iptc.Application2.Keywords">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolledwindow12">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="Iptc.Application2.SuppCategory">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Urgency">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Category">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="iptckeys">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">2</property>
|
||||||
|
<property name="ypad">2</property>
|
||||||
|
<property name="label" translatable="yes">Keywords/Categories</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="box4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="n_rows">9</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<property name="column_spacing">3</property>
|
||||||
|
<property name="row_spacing">3</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_credit">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Credit</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_source">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Source</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Credit">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.Source">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_transmission">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Transmission
|
||||||
|
reference</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">8</property>
|
||||||
|
<property name="bottom_attach">9</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.TransmissionReference">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">8</property>
|
||||||
|
<property name="bottom_attach">9</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_city">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">City</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.City">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_sublocation">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Sublocation</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
<property name="bottom_attach">5</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.SubLocation">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
<property name="bottom_attach">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_province">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xpad">3</property>
|
||||||
|
<property name="ypad">3</property>
|
||||||
|
<property name="label" translatable="yes">Province/State</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
<property name="bottom_attach">6</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.ProvinceState">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
<property name="bottom_attach">6</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="l_country">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Country</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">6</property>
|
||||||
|
<property name="bottom_attach">7</property>
|
||||||
|
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="Iptc.Application2.CountryName">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">6</property>
|
||||||
|
<property name="bottom_attach">7</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">7</property>
|
||||||
|
<property name="bottom_attach">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="iptccredits">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">2</property>
|
||||||
|
<property name="ypad">2</property>
|
||||||
|
<property name="label" translatable="yes">Credits/Origin</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">2</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="iptc-write-button">
|
||||||
|
<property name="label" translatable="yes">Write IPTC Data</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="iptc">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xpad">4</property>
|
||||||
|
<property name="ypad">4</property>
|
||||||
|
<property name="label" translatable="yes">IPTC</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">2</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -11,6 +11,7 @@ libgimp/gimpfontselectbutton.c
|
||||||
libgimp/gimpgradientmenu.c
|
libgimp/gimpgradientmenu.c
|
||||||
libgimp/gimpgradientselectbutton.c
|
libgimp/gimpgradientselectbutton.c
|
||||||
libgimp/gimpmenu.c
|
libgimp/gimpmenu.c
|
||||||
|
libgimp/gimpmetadata.c
|
||||||
libgimp/gimppalettemenu.c
|
libgimp/gimppalettemenu.c
|
||||||
libgimp/gimppaletteselectbutton.c
|
libgimp/gimppaletteselectbutton.c
|
||||||
libgimp/gimppatternmenu.c
|
libgimp/gimppatternmenu.c
|
||||||
|
@ -22,6 +23,7 @@ libgimp/gimpunitcache.c
|
||||||
libgimpbase/gimpbaseenums.c
|
libgimpbase/gimpbaseenums.c
|
||||||
libgimpbase/gimpcpuaccel.c
|
libgimpbase/gimpcpuaccel.c
|
||||||
libgimpbase/gimpmemsize.c
|
libgimpbase/gimpmemsize.c
|
||||||
|
libgimpbase/gimpmetadata.c
|
||||||
libgimpbase/gimputils.c
|
libgimpbase/gimputils.c
|
||||||
|
|
||||||
libgimpconfig/gimpcolorconfig.c
|
libgimpconfig/gimpcolorconfig.c
|
||||||
|
|
|
@ -96,6 +96,7 @@ plug-ins/common/lens-apply.c
|
||||||
plug-ins/common/lens-flare.c
|
plug-ins/common/lens-flare.c
|
||||||
plug-ins/common/mail.c
|
plug-ins/common/mail.c
|
||||||
plug-ins/common/max-rgb.c
|
plug-ins/common/max-rgb.c
|
||||||
|
plug-ins/common/metadata.c
|
||||||
plug-ins/common/newsprint.c
|
plug-ins/common/newsprint.c
|
||||||
plug-ins/common/nl-filter.c
|
plug-ins/common/nl-filter.c
|
||||||
plug-ins/common/noise-rgb.c
|
plug-ins/common/noise-rgb.c
|
||||||
|
@ -141,7 +142,6 @@ plug-ins/file-ico/ico-dialog.c
|
||||||
plug-ins/file-ico/ico-load.c
|
plug-ins/file-ico/ico-load.c
|
||||||
plug-ins/file-ico/ico-save.c
|
plug-ins/file-ico/ico-save.c
|
||||||
plug-ins/file-ico/ico.c
|
plug-ins/file-ico/ico.c
|
||||||
plug-ins/file-jpeg/jpeg-exif.c
|
|
||||||
plug-ins/file-jpeg/jpeg-load.c
|
plug-ins/file-jpeg/jpeg-load.c
|
||||||
plug-ins/file-jpeg/jpeg-save.c
|
plug-ins/file-jpeg/jpeg-save.c
|
||||||
plug-ins/file-jpeg/jpeg.c
|
plug-ins/file-jpeg/jpeg.c
|
||||||
|
@ -187,6 +187,8 @@ plug-ins/gimpressionist/sizemap.c
|
||||||
plug-ins/gimpressionist/utils.c
|
plug-ins/gimpressionist/utils.c
|
||||||
[type: gettext/glade]plug-ins/ui/plug-in-file-gif.ui
|
[type: gettext/glade]plug-ins/ui/plug-in-file-gif.ui
|
||||||
[type: gettext/glade]plug-ins/ui/plug-in-file-png.ui
|
[type: gettext/glade]plug-ins/ui/plug-in-file-png.ui
|
||||||
|
[type: gettext/glade]plug-ins/ui/plug-in-file-tiff.ui
|
||||||
|
[type: gettext/glade]plug-ins/ui/plug-in-metadata.ui
|
||||||
plug-ins/gradient-flare/gradient-flare.c
|
plug-ins/gradient-flare/gradient-flare.c
|
||||||
plug-ins/help-browser/dialog.c
|
plug-ins/help-browser/dialog.c
|
||||||
plug-ins/help-browser/help-browser.c
|
plug-ins/help-browser/help-browser.c
|
||||||
|
|
|
@ -1625,6 +1625,61 @@ CODE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub image_get_metadata {
|
||||||
|
$blurb = "Returns the image's metadata.";
|
||||||
|
$help = 'Returns exif/iptc/xmp metadata from the image.';
|
||||||
|
|
||||||
|
&std_pdb_misc('2013', '2.10');
|
||||||
|
|
||||||
|
@inargs = (
|
||||||
|
{ name => 'image', type => 'image',
|
||||||
|
desc => 'The image' }
|
||||||
|
);
|
||||||
|
|
||||||
|
@outargs = (
|
||||||
|
{ name => 'metadata_string', type => 'string', wrap => 1,
|
||||||
|
desc => 'The exif/ptc/xmp metadata as a string'}
|
||||||
|
);
|
||||||
|
|
||||||
|
%invoke = (
|
||||||
|
code => <<'CODE'
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_image_get_metadata (image);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
metadata_string = gimp_metadata_serialize (metadata);
|
||||||
|
}
|
||||||
|
CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub image_set_metadata {
|
||||||
|
$blurb = "Set the image's metadata.";
|
||||||
|
$help = 'Sets exif/iptc/xmp metadata on the image.';
|
||||||
|
|
||||||
|
&std_pdb_misc('2013', '2.10');
|
||||||
|
|
||||||
|
@inargs = (
|
||||||
|
{ name => 'image', type => 'image',
|
||||||
|
desc => 'The image' },
|
||||||
|
{ name => 'metadata_string', type => 'string', wrap => 1,
|
||||||
|
desc => 'The exif/ptc/xmp metadata as a string' }
|
||||||
|
);
|
||||||
|
|
||||||
|
%invoke = (
|
||||||
|
code => <<'CODE'
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata = gimp_metadata_deserialize (metadata_string);
|
||||||
|
|
||||||
|
gimp_image_set_metadata (image, metadata, TRUE);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
sub image_clean_all {
|
sub image_clean_all {
|
||||||
$blurb = 'Set the image dirty count to 0.';
|
$blurb = 'Set the image dirty count to 0.';
|
||||||
|
|
||||||
|
@ -2988,6 +3043,7 @@ CODE
|
||||||
"libgimpbase/gimpbase.h"
|
"libgimpbase/gimpbase.h"
|
||||||
"core/gimp.h"
|
"core/gimp.h"
|
||||||
"core/gimpcontainer.h"
|
"core/gimpcontainer.h"
|
||||||
|
"core/gimpimage-metadata.h"
|
||||||
"core/gimpprogress.h"
|
"core/gimpprogress.h"
|
||||||
"core/gimptempbuf.h"
|
"core/gimptempbuf.h"
|
||||||
"core/gimpunit.h"
|
"core/gimpunit.h"
|
||||||
|
@ -3029,6 +3085,7 @@ CODE
|
||||||
image_flatten image_merge_visible_layers image_merge_down
|
image_flatten image_merge_visible_layers image_merge_down
|
||||||
image_add_layer_mask image_remove_layer_mask
|
image_add_layer_mask image_remove_layer_mask
|
||||||
image_get_colormap image_set_colormap
|
image_get_colormap image_set_colormap
|
||||||
|
image_get_metadata image_set_metadata
|
||||||
image_clean_all image_is_dirty
|
image_clean_all image_is_dirty
|
||||||
image_thumbnail
|
image_thumbnail
|
||||||
image_get_active_layer image_set_active_layer
|
image_get_active_layer image_set_active_layer
|
||||||
|
@ -3060,7 +3117,7 @@ CODE
|
||||||
# image_add_layer_mask and image_remove_layer_mask.
|
# image_add_layer_mask and image_remove_layer_mask.
|
||||||
# If adding or removing functions, make sure the range below is
|
# If adding or removing functions, make sure the range below is
|
||||||
# updated correctly!
|
# updated correctly!
|
||||||
%exports = (app => [@procs], lib => [@procs[0..44,47..85]]);
|
%exports = (app => [@procs], lib => [@procs[0..44,47..87]]);
|
||||||
|
|
||||||
$desc = 'Image';
|
$desc = 'Image';
|
||||||
$doc_title = 'gimpimage';
|
$doc_title = 'gimpimage';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue