~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to plug-ins/jpeg/jpeg-exif.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIMP - The GNU Image Manipulation Program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 */
 
18
 
 
19
/*
 
20
 * EXIF-handling code for the jpeg plugin.  May eventually be better
 
21
 * to move this stuff into libgimpbase and make it available for
 
22
 * other plugins.
 
23
 */
 
24
 
 
25
#include "config.h"
 
26
 
 
27
#include <stdio.h>
 
28
#include <string.h>
 
29
#include <setjmp.h>
 
30
 
 
31
#include <jpeglib.h>
 
32
#include <jerror.h>
 
33
 
 
34
#ifdef HAVE_EXIF
 
35
 
 
36
#include <libexif/exif-content.h>
 
37
#include <libexif/exif-data.h>
 
38
#include <libexif/exif-utils.h>
 
39
 
 
40
#define EXIF_HEADER_SIZE 8
 
41
 
 
42
#include <libgimp/gimp.h>
 
43
#include <libgimp/gimpui.h>
 
44
 
 
45
#include "gimpexif.h"
 
46
 
 
47
#include "jpeg.h"
 
48
 
 
49
#include "libgimp/stdplugins-intl.h"
 
50
 
 
51
 
 
52
#define THUMBNAIL_SIZE             128
 
53
#define JPEG_EXIF_ROTATE_PARASITE  "exif-orientation-rotate"
 
54
 
 
55
 
 
56
static void      jpeg_exif_rotate       (gint32 image_ID,
 
57
                                         gint   orientation);
 
58
static gboolean  jpeg_exif_rotate_query (gint32 image_ID);
 
59
 
 
60
 
 
61
/*  Replacement for exif_data_new_from_file() to work around
 
62
 *  filename encoding problems (see bug #335391).
 
63
 */
 
64
ExifData *
 
65
jpeg_exif_data_new_from_file (const gchar  *filename,
 
66
                              GError      **error)
 
67
{
 
68
  ExifData    *data;
 
69
  GMappedFile *file;
 
70
 
 
71
  g_return_val_if_fail (filename != NULL, NULL);
 
72
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
73
 
 
74
  file = g_mapped_file_new (filename, FALSE, error);
 
75
  if (! file)
 
76
    return NULL;
 
77
 
 
78
  data = exif_data_new_from_data ((guchar *) g_mapped_file_get_contents (file),
 
79
                                  g_mapped_file_get_length (file));
 
80
 
 
81
  g_mapped_file_free (file);
 
82
 
 
83
  return data;
 
84
}
 
85
 
 
86
void
 
87
jpeg_apply_exif_data_to_image (const gchar  *filename,
 
88
                               const gint32  image_ID)
 
89
{
 
90
  ExifData     *exif_data     = NULL;
 
91
  ExifEntry    *entry;
 
92
  gint          byte_order;
 
93
 
 
94
  exif_data = jpeg_exif_data_new_from_file (filename, NULL);
 
95
  if (!exif_data)
 
96
    return;
 
97
 
 
98
  /* return if there is no thumbnail, to work around bug #358117 */
 
99
  if (!exif_data->data || exif_data->size == 0)
 
100
    return;
 
101
 
 
102
  /*
 
103
   * Unfortunately libexif may return a non-null exif_data even if the file
 
104
   * contains no exif data.  We check for validity by making sure it
 
105
   * has an ExifVersion tag.
 
106
  */
 
107
  if (! exif_content_get_entry (exif_data->ifd[EXIF_IFD_EXIF],
 
108
                                EXIF_TAG_EXIF_VERSION))
 
109
    return;
 
110
 
 
111
  gimp_metadata_store_exif (image_ID, exif_data);
 
112
 
 
113
  byte_order = exif_data_get_byte_order (exif_data);
 
114
 
 
115
  /* get orientation and rotate image accordingly if necessary */
 
116
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
117
                                       EXIF_TAG_ORIENTATION)))
 
118
    {
 
119
      jpeg_exif_rotate (image_ID, exif_get_short (entry->data, byte_order));
 
120
    }
 
121
 
 
122
  exif_data_unref (exif_data);
 
123
}
 
124
 
 
125
 
 
126
void
 
127
jpeg_setup_exif_for_save (ExifData      *exif_data,
 
128
                          const gint32   image_ID)
 
129
{
 
130
  ExifRational  r;
 
131
  gdouble       xres, yres;
 
132
  ExifEntry    *entry;
 
133
  gint          byte_order = exif_data_get_byte_order (exif_data);
 
134
 
 
135
  /* set orientation to top - left */
 
136
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
137
                                       EXIF_TAG_ORIENTATION)))
 
138
    {
 
139
      exif_set_short (entry->data, byte_order, (ExifShort) 1);
 
140
    }
 
141
 
 
142
  /* set x and y resolution */
 
143
  gimp_image_get_resolution (image_ID, &xres, &yres);
 
144
  r.numerator =   xres;
 
145
  r.denominator = 1;
 
146
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
147
                                       EXIF_TAG_X_RESOLUTION)))
 
148
    {
 
149
      exif_set_rational (entry->data, byte_order, r);
 
150
    }
 
151
  r.numerator = yres;
 
152
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
153
                                       EXIF_TAG_Y_RESOLUTION)))
 
154
    {
 
155
      exif_set_rational (entry->data, byte_order, r);
 
156
    }
 
157
 
 
158
  /* set resolution unit, always inches */
 
159
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
160
                                       EXIF_TAG_RESOLUTION_UNIT)))
 
161
    {
 
162
      exif_set_short (entry->data, byte_order, (ExifShort) 2);
 
163
    }
 
164
 
 
165
  /* set software to "GIMP" */
 
166
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
167
                                       EXIF_TAG_SOFTWARE)))
 
168
    {
 
169
      const gchar *name = "GIMP";
 
170
 
 
171
      entry->data = (guchar *) g_strdup (name);
 
172
      entry->size = strlen (name) + 1;
 
173
      entry->components = entry->size;
 
174
    }
 
175
 
 
176
  /* set the width and height */
 
177
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
178
                                       EXIF_TAG_PIXEL_X_DIMENSION)))
 
179
    {
 
180
      exif_set_long (entry->data, byte_order,
 
181
                     (ExifLong) gimp_image_width (image_ID));
 
182
    }
 
183
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
184
                                       EXIF_TAG_PIXEL_Y_DIMENSION)))
 
185
    {
 
186
      exif_set_long (entry->data, byte_order,
 
187
                     (ExifLong) gimp_image_height (image_ID));
 
188
    }
 
189
 
 
190
  /*
 
191
   * set the date & time image was saved
 
192
   * note, date & time of original photo is stored elsewwhere, we
 
193
   * aren't losing it.
 
194
   */
 
195
  if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0],
 
196
                                       EXIF_TAG_DATE_TIME)))
 
197
    {
 
198
      /* small memory leak here */
 
199
      entry->data = NULL;
 
200
      exif_entry_initialize (entry, EXIF_TAG_DATE_TIME);
 
201
    }
 
202
 
 
203
  /* should set components configuration, don't know how */
 
204
 
 
205
  /*
 
206
   *remove entries that don't apply to jpeg
 
207
   *(may have come from tiff or raw)
 
208
  */
 
209
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_COMPRESSION);
 
210
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH);
 
211
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH);
 
212
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_BITS_PER_SAMPLE);
 
213
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_SAMPLES_PER_PIXEL);
 
214
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_PHOTOMETRIC_INTERPRETATION);
 
215
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_STRIP_OFFSETS);
 
216
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_PLANAR_CONFIGURATION);
 
217
  gimp_exif_data_remove_entry(exif_data, EXIF_IFD_0, EXIF_TAG_YCBCR_SUB_SAMPLING);
 
218
 
 
219
  /* should set thumbnail attributes */
 
220
}
 
221
 
 
222
 
 
223
static void
 
224
jpeg_exif_rotate (gint32 image_ID,
 
225
                  gint   orientation)
 
226
{
 
227
  GimpParasite *parasite;
 
228
  gboolean      query = load_interactive;
 
229
 
 
230
  if (orientation < 2 || orientation > 8)
 
231
    return;
 
232
 
 
233
  parasite = gimp_parasite_find (JPEG_EXIF_ROTATE_PARASITE);
 
234
 
 
235
  if (parasite)
 
236
    {
 
237
      if (strncmp (gimp_parasite_data (parasite), "yes",
 
238
                   gimp_parasite_data_size (parasite)) == 0)
 
239
        {
 
240
          query = FALSE;
 
241
        }
 
242
      else if (strncmp (gimp_parasite_data (parasite), "no",
 
243
                        gimp_parasite_data_size (parasite)) == 0)
 
244
        {
 
245
          gimp_parasite_free (parasite);
 
246
          return;
 
247
        }
 
248
 
 
249
      gimp_parasite_free (parasite);
 
250
    }
 
251
 
 
252
  if (query && ! jpeg_exif_rotate_query (image_ID))
 
253
    return;
 
254
 
 
255
  switch (orientation)
 
256
    {
 
257
    case 1:  /* standard orientation, do nothing */
 
258
      break;
 
259
 
 
260
    case 2:  /* flipped right-left               */
 
261
      gimp_image_flip (image_ID, GIMP_ORIENTATION_HORIZONTAL);
 
262
      break;
 
263
 
 
264
    case 3:  /* rotated 180                      */
 
265
      gimp_image_rotate (image_ID, GIMP_ROTATE_180);
 
266
      break;
 
267
 
 
268
    case 4:  /* flipped top-bottom               */
 
269
      gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);
 
270
      break;
 
271
 
 
272
    case 5:  /* flipped diagonally around '\'    */
 
273
      gimp_image_rotate (image_ID, GIMP_ROTATE_90);
 
274
      gimp_image_flip (image_ID, GIMP_ORIENTATION_HORIZONTAL);
 
275
      break;
 
276
 
 
277
    case 6:  /* 90 CW                            */
 
278
      gimp_image_rotate (image_ID, GIMP_ROTATE_90);
 
279
      break;
 
280
 
 
281
    case 7:  /* flipped diagonally around '/'    */
 
282
      gimp_image_rotate (image_ID, GIMP_ROTATE_90);
 
283
      gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);
 
284
      break;
 
285
 
 
286
    case 8:  /* 90 CCW                           */
 
287
      gimp_image_rotate (image_ID, GIMP_ROTATE_270);
 
288
      break;
 
289
 
 
290
    default: /* can't happen                     */
 
291
      break;
 
292
    }
 
293
}
 
294
 
 
295
static gboolean
 
296
jpeg_exif_rotate_query (gint32 image_ID)
 
297
{
 
298
  GtkWidget *dialog;
 
299
  GtkWidget *hbox;
 
300
  GtkWidget *vbox;
 
301
  GtkWidget *label;
 
302
  GtkWidget *toggle;
 
303
  GdkPixbuf *pixbuf;
 
304
  gint       response;
 
305
 
 
306
  dialog = gimp_dialog_new (_("Rotate Image?"), PLUG_IN_BINARY,
 
307
                            NULL, 0, NULL, NULL,
 
308
 
 
309
                            _("_Keep Orientation"), GTK_RESPONSE_CANCEL,
 
310
                            GIMP_STOCK_TOOL_ROTATE, GTK_RESPONSE_OK,
 
311
 
 
312
                            NULL);
 
313
 
 
314
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
 
315
                                           GTK_RESPONSE_OK,
 
316
                                           GTK_RESPONSE_CANCEL,
 
317
                                           -1);
 
318
 
 
319
  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
320
  gimp_window_set_transient (GTK_WINDOW (dialog));
 
321
 
 
322
  hbox = gtk_hbox_new (FALSE, 12);
 
323
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
 
324
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
 
325
                      hbox, FALSE, FALSE, 0);
 
326
  gtk_widget_show (hbox);
 
327
 
 
328
  vbox = gtk_vbox_new (FALSE, 6);
 
329
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
 
330
  gtk_widget_show (vbox);
 
331
 
 
332
  pixbuf = gimp_image_get_thumbnail (image_ID,
 
333
                                     THUMBNAIL_SIZE, THUMBNAIL_SIZE,
 
334
                                     GIMP_PIXBUF_SMALL_CHECKS);
 
335
 
 
336
  if (pixbuf)
 
337
    {
 
338
      GtkWidget *image;
 
339
      gchar     *name;
 
340
 
 
341
      image = gtk_image_new_from_pixbuf (pixbuf);
 
342
      g_object_unref (pixbuf);
 
343
 
 
344
      gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
 
345
      gtk_widget_show (image);
 
346
 
 
347
      name = gimp_image_get_name (image_ID);
 
348
 
 
349
      label = gtk_label_new (name);
 
350
      gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
 
351
      gimp_label_set_attributes (GTK_LABEL (label),
 
352
                                 PANGO_ATTR_STYLE,  PANGO_STYLE_ITALIC,
 
353
                                 -1);
 
354
      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
355
      gtk_widget_show (label);
 
356
 
 
357
      g_free (name);
 
358
    }
 
359
 
 
360
  vbox = gtk_vbox_new (FALSE, 12);
 
361
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
 
362
  gtk_widget_show (vbox);
 
363
 
 
364
  label = g_object_new (GTK_TYPE_LABEL,
 
365
                        "label",   _("According to the EXIF data, "
 
366
                                     "this image is rotated."),
 
367
                        "wrap",    TRUE,
 
368
                        "justify", GTK_JUSTIFY_LEFT,
 
369
                        "xalign",  0.0,
 
370
                        "yalign",  0.5,
 
371
                        NULL);
 
372
  gimp_label_set_attributes (GTK_LABEL (label),
 
373
                             PANGO_ATTR_SCALE,  PANGO_SCALE_LARGE,
 
374
                             PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
 
375
                             -1);
 
376
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
377
  gtk_widget_show (label);
 
378
 
 
379
  label = g_object_new (GTK_TYPE_LABEL,
 
380
                        "label",   _("Would you like GIMP to rotate it "
 
381
                                     "into the standard orientation?"),
 
382
                        "wrap",    TRUE,
 
383
                        "justify", GTK_JUSTIFY_LEFT,
 
384
                        "xalign",  0.0,
 
385
                        "yalign",  0.5,
 
386
                        NULL);
 
387
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
388
  gtk_widget_show (label);
 
389
 
 
390
  toggle = gtk_check_button_new_with_mnemonic (_("_Don't ask me again"));
 
391
  gtk_box_pack_end (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
 
392
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE);
 
393
  gtk_widget_show (toggle);
 
394
 
 
395
  response = gimp_dialog_run (GIMP_DIALOG (dialog));
 
396
 
 
397
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)))
 
398
    {
 
399
      GimpParasite *parasite;
 
400
      const gchar  *str = (response == GTK_RESPONSE_OK) ? "yes" : "no";
 
401
 
 
402
      parasite = gimp_parasite_new (JPEG_EXIF_ROTATE_PARASITE,
 
403
                                    GIMP_PARASITE_PERSISTENT,
 
404
                                    strlen (str), str);
 
405
      gimp_parasite_attach (parasite);
 
406
      gimp_parasite_free (parasite);
 
407
    }
 
408
 
 
409
  gtk_widget_destroy (dialog);
 
410
 
 
411
  return (response == GTK_RESPONSE_OK);
 
412
}
 
413
 
 
414
 
 
415
#endif /* HAVE_EXIF */