1
/* metadata.c - main() for the metadata editor
3
* Copyright (C) 2004-2005, Raphaël Quinet <raphael@gimp.org>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
27
#include <libgimp/gimp.h>
28
#include <libgimp/gimpui.h>
30
#include "libgimp/stdplugins-intl.h"
32
#include "interface.h"
34
#include "xmp-encode.h"
35
/* FIXME: uncomment when these are working
36
#include "exif-decode.h"
37
#include "exif-encode.h"
38
#include "iptc-decode.h"
42
#define METADATA_PARASITE "gimp-metadata"
43
#define METADATA_MARKER "GIMP_XMP_1"
44
#define METADATA_MARKER_LEN (sizeof (METADATA_MARKER) - 1)
47
/* prototypes of local functions */
48
static void query (void);
49
static void run (const gchar *name,
51
const GimpParam *param,
53
GimpParam **return_vals);
56
const GimpPlugInInfo PLUG_IN_INFO =
60
query, /* query_proc */
70
static const GimpParamDef editor_args[] =
72
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
73
{ GIMP_PDB_IMAGE, "image", "Input image" },
74
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)" }
77
static const GimpParamDef decode_xmp_args[] =
79
{ GIMP_PDB_IMAGE, "image", "Input image" },
80
{ GIMP_PDB_STRING, "xmp", "XMP packet" }
83
static const GimpParamDef encode_xmp_args[] =
85
{ GIMP_PDB_IMAGE, "image", "Input image" }
87
static const GimpParamDef encode_xmp_return_vals[] =
89
{ GIMP_PDB_STRING, "xmp", "XMP packet" }
92
/* FIXME: uncomment when these are working
93
static const GimpParamDef decode_exif_args[] =
95
{ GIMP_PDB_IMAGE, "image", "Input image" },
96
{ GIMP_PDB_INT32, "exif-size", "size of the EXIF block" },
97
{ GIMP_PDB_INT8ARRAY, "exif", "EXIF block" }
100
static const GimpParamDef encode_exif_args[] =
102
{ GIMP_PDB_IMAGE, "image", "Input image" }
104
static const GimpParamDef encode_exif_return_vals[] =
106
{ GIMP_PDB_INT32, "exif-size", "size of the EXIF block" },
107
{ GIMP_PDB_INT8ARRAY, "exif", "EXIF block" }
111
static const GimpParamDef get_args[] =
113
{ GIMP_PDB_IMAGE, "image", "Input image" },
114
{ GIMP_PDB_STRING, "schema", "XMP schema prefix or URI" },
115
{ GIMP_PDB_STRING, "property", "XMP property name" }
117
static const GimpParamDef get_return_vals[] =
119
{ GIMP_PDB_INT32, "type", "XMP property type" },
120
{ GIMP_PDB_INT32, "num-vals", "number of values" },
121
{ GIMP_PDB_STRINGARRAY, "vals", "XMP property values" }
124
static const GimpParamDef set_args[] =
126
{ GIMP_PDB_IMAGE, "image", "Input image" },
127
{ GIMP_PDB_STRING, "schema", "XMP schema prefix or URI" },
128
{ GIMP_PDB_STRING, "property", "XMP property name" },
129
{ GIMP_PDB_INT32, "type", "XMP property type" },
130
{ GIMP_PDB_INT32, "num-vals", "number of values" },
131
{ GIMP_PDB_STRINGARRAY, "vals", "XMP property values" }
134
static const GimpParamDef get_simple_args[] =
136
{ GIMP_PDB_IMAGE, "image", "Input image" },
137
{ GIMP_PDB_STRING, "schema", "XMP schema prefix or URI" },
138
{ GIMP_PDB_STRING, "property", "XMP property name" }
140
static const GimpParamDef get_simple_return_vals[] =
142
{ GIMP_PDB_STRING, "value", "XMP property value" }
145
static const GimpParamDef set_simple_args[] =
147
{ GIMP_PDB_IMAGE, "image", "Input image" },
148
{ GIMP_PDB_STRING, "schema", "XMP schema prefix or URI" },
149
{ GIMP_PDB_STRING, "property", "XMP property name" },
150
{ GIMP_PDB_STRING, "value", "XMP property value" }
153
/* FIXME: uncomment when these are working
154
static const GimpParamDef delete_args[] =
156
{ GIMP_PDB_IMAGE, "image", "Input image" },
157
{ GIMP_PDB_STRING, "schema", "XMP schema prefix or URI" },
158
{ GIMP_PDB_STRING, "property", "XMP property name" }
161
static const GimpParamDef add_schema_args[] =
163
{ GIMP_PDB_IMAGE, "image", "Input image" },
164
{ GIMP_PDB_STRING, "prefix", "XMP schema prefix" },
165
{ GIMP_PDB_STRING, "uri", "XMP schema URI" }
169
static const GimpParamDef import_args[] =
171
{ GIMP_PDB_IMAGE, "image", "Input image" },
172
{ GIMP_PDB_STRING, "filename", "The name of the XMP file to import" }
175
static const GimpParamDef export_args[] =
177
{ GIMP_PDB_IMAGE, "image", "Input image" },
178
{ GIMP_PDB_STRING, "filename", "The name of the file to save the XMP packet in" },
179
{ GIMP_PDB_INT32, "overwrite", "Overwrite existing file: { FALSE (0), TRUE (1) }" }
182
gimp_install_procedure (EDITOR_PROC,
183
N_("View and edit metadata (EXIF, IPTC, XMP)"),
184
"View and edit metadata information attached to the "
185
"current image. This can include EXIF, IPTC and/or "
186
"XMP information. Some or all of this metadata "
187
"will be saved in the file, depending on the output "
189
"Raphaël Quinet <raphael@gimp.org>",
190
"Raphaël Quinet <raphael@gimp.org>",
193
"RGB*, INDEXED*, GRAY*",
195
G_N_ELEMENTS (editor_args), 0,
198
gimp_plugin_menu_register (EDITOR_PROC, "<Image>/File/Info");
199
gimp_plugin_icon_register (EDITOR_PROC, GIMP_ICON_TYPE_STOCK_ID,
200
(const guint8 *) GTK_STOCK_PROPERTIES);
201
/* FIXME: The GNOME HIG recommends using the accel Alt+Return for this */
203
gimp_install_procedure (DECODE_XMP_PROC,
204
"Decode an XMP packet",
205
"Parse an XMP packet and merge the results with "
206
"any metadata already attached to the image. This "
207
"should be used when an XMP packet is read from an "
209
"Raphaël Quinet <raphael@gimp.org>",
210
"Raphaël Quinet <raphael@gimp.org>",
215
G_N_ELEMENTS (decode_xmp_args), 0,
216
decode_xmp_args, NULL);
218
gimp_install_procedure (ENCODE_XMP_PROC,
219
"Encode metadata into an XMP packet",
220
"Generate an XMP packet from the metadata "
221
"information attached to the image. The new XMP "
222
"packet can then be saved into a file.",
223
"Raphaël Quinet <raphael@gimp.org>",
224
"Raphaël Quinet <raphael@gimp.org>",
229
G_N_ELEMENTS (encode_xmp_args),
230
G_N_ELEMENTS (encode_xmp_return_vals),
231
encode_xmp_args, encode_xmp_return_vals);
233
/* FIXME: uncomment when these are working
234
gimp_install_procedure (DECODE_EXIF_PROC,
235
"Decode an EXIF block",
236
"Parse an EXIF block and merge the results with "
237
"any metadata already attached to the image. This "
238
"should be used when an EXIF block is read from an "
240
"Raphaël Quinet <raphael@gimp.org>",
241
"Raphaël Quinet <raphael@gimp.org>",
246
G_N_ELEMENTS (decode_exif_args), 0,
247
decode_exif_args, NULL);
249
gimp_install_procedure (ENCODE_EXIF_PROC,
250
"Encode metadata into an EXIF block",
251
"Generate an EXIF block from the metadata "
252
"information attached to the image. The new EXIF "
253
"block can then be saved into a file.",
254
"Raphaël Quinet <raphael@gimp.org>",
255
"Raphaël Quinet <raphael@gimp.org>",
260
G_N_ELEMENTS (encode_exif_args),
261
G_N_ELEMENTS (encode_exif_return_vals),
262
encode_exif_args, encode_exif_return_vals);
265
gimp_install_procedure (GET_PROC,
266
"Retrieve the values of an XMP property",
267
"Retrieve the list of values associated with "
269
"Raphaël Quinet <raphael@gimp.org>",
270
"Raphaël Quinet <raphael@gimp.org>",
275
G_N_ELEMENTS (get_args),
276
G_N_ELEMENTS (get_return_vals),
277
get_args, get_return_vals);
279
gimp_install_procedure (SET_PROC,
280
"Set the values of an XMP property",
281
"Set the list of values associated with "
282
"an XMP property. If a property with the same "
283
"name already exists, it will be replaced.",
284
"Raphaël Quinet <raphael@gimp.org>",
285
"Raphaël Quinet <raphael@gimp.org>",
290
G_N_ELEMENTS (set_args), 0,
293
gimp_install_procedure (GET_SIMPLE_PROC,
294
"Retrieve the value of an XMP property",
295
"Retrieve value associated with a scalar XMP "
296
"property. This can only be done for simple "
297
"property types such as text or integers. "
298
"Structured types must be retrieved with "
299
"plug_in_metadata_get().",
300
"Raphaël Quinet <raphael@gimp.org>",
301
"Raphaël Quinet <raphael@gimp.org>",
306
G_N_ELEMENTS (get_simple_args),
307
G_N_ELEMENTS (get_simple_return_vals),
308
get_simple_args, get_simple_return_vals);
310
gimp_install_procedure (SET_SIMPLE_PROC,
311
"Set the value of an XMP property",
312
"Set the value of a scalar XMP property. This "
313
"can only be done for simple property types such "
314
"as text or integers. Structured types need to "
315
"be set with plug_in_metadata_set().",
316
"Raphaël Quinet <raphael@gimp.org>",
317
"Raphaël Quinet <raphael@gimp.org>",
322
G_N_ELEMENTS (set_simple_args), 0,
323
set_simple_args, NULL);
325
gimp_install_procedure (IMPORT_PROC,
326
"Import XMP from a file into the current image",
327
"Load an XMP packet from a file and import it into "
328
"the current image. This can be used to add a "
329
"license statement or some other predefined "
330
"metadata to an image",
331
"Raphaël Quinet <raphael@gimp.org>",
332
"Raphaël Quinet <raphael@gimp.org>",
337
G_N_ELEMENTS (import_args), 0,
340
gimp_install_procedure (EXPORT_PROC,
341
"Export XMP from the current image to a file",
342
"Export the metadata associated with the current "
343
"image into a file. The metadata will be saved as "
344
"an XMP packet. If overwrite is TRUE, then any "
345
"existing file will be overwritten without warning. "
346
"If overwrite is FALSE, then an error will occur if "
347
"the file already exists.",
348
"Raphaël Quinet <raphael@gimp.org>",
349
"Raphaël Quinet <raphael@gimp.org>",
354
G_N_ELEMENTS (export_args), 0,
359
run (const gchar *name,
361
const GimpParam *param,
363
GimpParam **return_vals)
365
static GimpParam values[4];
368
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
369
GimpParasite *parasite = NULL;
372
*return_vals = values;
374
values[0].type = GIMP_PDB_STATUS;
375
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
379
if (! strcmp (name, EDITOR_PROC))
380
image_ID = param[1].data.d_image;
382
image_ID = param[0].data.d_image;
384
xmp_model = xmp_model_new ();
386
/* if there is already a metadata parasite, load it */
387
parasite = gimp_image_parasite_find (image_ID, METADATA_PARASITE);
390
GError *error = NULL;
392
if (!! strncmp (gimp_parasite_data (parasite),
393
METADATA_MARKER, METADATA_MARKER_LEN)
394
|| ! xmp_model_parse_buffer (xmp_model,
395
(const gchar *)gimp_parasite_data (parasite)
396
+ METADATA_MARKER_LEN,
397
gimp_parasite_data_size (parasite)
398
- METADATA_MARKER_LEN,
401
g_warning ("Metadata parasite seems to be corrupt");
402
/* continue anyway, we will attach a clean parasite later */
404
gimp_parasite_free (parasite);
407
/* If we have no metadata yet, try to find an XMP packet in the file
408
* (but ignore errors if nothing is found).
410
* FIXME: This is a workaround until all file plug-ins do the right
411
* thing when loading their files.
413
if (xmp_model_is_empty (xmp_model)
414
&& !! strcmp (name, DECODE_XMP_PROC))
416
const gchar *filename;
417
GError *error = NULL;
419
filename = gimp_image_get_filename (image_ID);
420
if (filename != NULL)
421
if (xmp_model_parse_file (xmp_model, filename, &error))
422
/* g_message ("XMP loaded from file '%s'\n", filename) */;
425
/* Now check what we are supposed to do */
426
if (! strcmp (name, EDITOR_PROC))
428
GimpRunMode run_mode;
430
run_mode = param[0].data.d_int32;
431
if (run_mode == GIMP_RUN_INTERACTIVE)
434
if (! metadata_dialog (image_ID, xmp_model))
435
status = GIMP_PDB_CANCEL;
438
else if (! strcmp (name, DECODE_XMP_PROC))
441
GError *error = NULL;
443
buffer = param[1].data.d_string;
444
if (! xmp_model_parse_buffer (xmp_model, buffer, strlen (buffer),
446
status = GIMP_PDB_EXECUTION_ERROR;
448
else if (! strcmp (name, ENCODE_XMP_PROC))
450
/* done below together with the parasite */
452
else if (! strcmp (name, GET_PROC))
454
g_warning ("Not implemented yet\n"); /* FIXME */
455
status = GIMP_PDB_EXECUTION_ERROR;
457
else if (! strcmp (name, SET_PROC))
459
g_warning ("Not implemented yet\n"); /* FIXME */
460
status = GIMP_PDB_EXECUTION_ERROR;
462
else if (! strcmp (name, GET_SIMPLE_PROC))
464
const gchar *schema_name;
465
const gchar *property_name;
468
schema_name = param[1].data.d_string;
469
property_name = param[2].data.d_string;
470
value = xmp_model_get_scalar_property (xmp_model, schema_name,
475
values[1].type = GIMP_PDB_STRING;
476
values[1].data.d_string = g_strdup (value);
479
status = GIMP_PDB_EXECUTION_ERROR;
481
else if (! strcmp (name, SET_SIMPLE_PROC))
483
const gchar *schema_name;
484
const gchar *property_name;
485
const gchar *property_value;
487
schema_name = param[1].data.d_string;
488
property_name = param[2].data.d_string;
489
property_value = param[3].data.d_string;
490
if (! xmp_model_set_scalar_property (xmp_model, schema_name,
491
property_name, property_value))
492
status = GIMP_PDB_EXECUTION_ERROR;
494
else if (! strcmp (name, IMPORT_PROC))
496
const gchar *filename;
499
GError *error = NULL;
501
filename = param[1].data.d_string;
502
if (! g_file_get_contents (filename, &buffer, &buffer_length, &error))
504
g_error_free (error);
505
status = GIMP_PDB_EXECUTION_ERROR;
507
else if (! xmp_model_parse_buffer (xmp_model, buffer, buffer_length,
510
g_error_free (error);
511
status = GIMP_PDB_EXECUTION_ERROR;
515
else if (! strcmp (name, EXPORT_PROC))
517
/* FIXME: this is easy to implement, but the first thing to do is */
518
/* to improve the code of export_dialog_response() in interface.c */
519
g_warning ("Not implemented yet\n");
520
status = GIMP_PDB_EXECUTION_ERROR;
524
status = GIMP_PDB_CALLING_ERROR;
527
if (status == GIMP_PDB_SUCCESS)
531
/* Generate the updated parasite and attach it to the image */
532
buffer = g_string_new (METADATA_MARKER);
533
xmp_generate_packet (xmp_model, buffer);
534
parasite = gimp_parasite_new (METADATA_PARASITE,
535
GIMP_PARASITE_PERSISTENT,
537
(gpointer) buffer->str);
538
gimp_image_parasite_attach (image_ID, parasite);
539
if (! strcmp (name, ENCODE_XMP_PROC))
542
values[1].type = GIMP_PDB_STRING;
543
values[1].data.d_string = g_strdup (buffer->str
544
+ METADATA_MARKER_LEN);
546
g_string_free (buffer, TRUE);
547
xmp_model_free (xmp_model);
550
values[0].data.d_status = status;