]> git.imager.perl.org - imager.git/blame - imexif.c
C<> filter keywords to avoid trying to spellcheck them
[imager.git] / imexif.c
CommitLineData
75e155e1 1#include "imager.h"
f7450478
TC
2#include "imexif.h"
3#include <stdlib.h>
4#include <float.h>
797a9f9c 5#include <string.h>
8d14daab 6#include <stdio.h>
f7450478
TC
7
8/*
9=head1 NAME
10
11imexif.c - EXIF support for Imager
12
13=head1 SYNOPSIS
14
75e155e1 15 if (im_decode_exif(im, app1data, app1datasize)) {
f7450478
TC
16 // exif block seen
17 }
18
19=head1 DESCRIPTION
20
21This code provides a basic EXIF data decoder. It is intended to be
22called from the JPEG reader code when an APP1 data block is found, and
23will set tags in the supplied image.
24
25=cut
26*/
27
28typedef enum tiff_type_tag {
29 tt_intel = 'I',
30 tt_motorola = 'M'
31} tiff_type;
32
33typedef enum {
34 ift_byte = 1,
35 ift_ascii = 2,
36 ift_short = 3,
37 ift_long = 4,
38 ift_rational = 5,
39 ift_sbyte = 6,
40 ift_undefined = 7,
41 ift_sshort = 8,
42 ift_slong = 9,
43 ift_srational = 10,
44 ift_float = 11,
45 ift_double = 12,
46 ift_last = 12 /* keep the same as the highest type code */
47} ifd_entry_type;
48
49static int type_sizes[] =
50 {
51 0, /* not used */
52 1, /* byte */
53 1, /* ascii */
54 2, /* short */
55 4, /* long */
56 8, /* rational */
57 1, /* sbyte */
58 1, /* undefined */
59 2, /* sshort */
60 4, /* slong */
61 8, /* srational */
62 4, /* float */
63 8, /* double */
64 };
65
66typedef struct {
67 int tag;
68 int type;
69 int count;
59957854 70 int item_size;
f7450478
TC
71 int size;
72 int offset;
73} ifd_entry;
74
75typedef struct {
76 int tag;
77 char const *name;
78} tag_map;
79
80typedef struct {
81 int tag;
82 char const *name;
83 tag_map const *map;
84 int map_count;
85} tag_value_map;
86
87#define PASTE(left, right) PASTE_(left, right)
88#define PASTE_(left, right) left##right
89#define QUOTE(value) #value
90
91#define VALUE_MAP_ENTRY(name) \
92 { \
93 PASTE(tag_, name), \
94 "exif_" QUOTE(name) "_name", \
95 PASTE(name, _values), \
96 ARRAY_COUNT(PASTE(name, _values)) \
97 }
98
99/* we don't process every tag */
100#define tag_make 271
101#define tag_model 272
102#define tag_orientation 274
103#define tag_x_resolution 282
104#define tag_y_resolution 283
105#define tag_resolution_unit 296
106#define tag_copyright 33432
107#define tag_software 305
108#define tag_artist 315
109#define tag_date_time 306
110#define tag_image_description 270
111
112#define tag_exif_ifd 34665
113#define tag_gps_ifd 34853
114
115#define resunit_none 1
116#define resunit_inch 2
117#define resunit_centimeter 3
118
119/* tags from the EXIF ifd */
120#define tag_exif_version 0x9000
121#define tag_flashpix_version 0xA000
122#define tag_color_space 0xA001
123#define tag_component_configuration 0x9101
124#define tag_component_bits_per_pixel 0x9102
125#define tag_pixel_x_dimension 0xA002
126#define tag_pixel_y_dimension 0xA003
127#define tag_maker_note 0x927C
128#define tag_user_comment 0x9286
129#define tag_related_sound_file 0xA004
130#define tag_date_time_original 0x9003
131#define tag_date_time_digitized 0x9004
132#define tag_sub_sec_time 0x9290
133#define tag_sub_sec_time_original 0x9291
134#define tag_sub_sec_time_digitized 0x9292
135#define tag_image_unique_id 0xA420
136#define tag_exposure_time 0x829a
137#define tag_f_number 0x829D
138#define tag_exposure_program 0x8822
139#define tag_spectral_sensitivity 0x8824
59957854 140#define tag_iso_speed_ratings 0x8827
f7450478
TC
141#define tag_oecf 0x8828
142#define tag_shutter_speed 0x9201
143#define tag_aperture 0x9202
144#define tag_brightness 0x9203
145#define tag_exposure_bias 0x9204
146#define tag_max_aperture 0x9205
147#define tag_subject_distance 0x9206
148#define tag_metering_mode 0x9207
149#define tag_light_source 0x9208
150#define tag_flash 0x9209
151#define tag_focal_length 0x920a
152#define tag_subject_area 0x9214
153#define tag_flash_energy 0xA20B
154#define tag_spatial_frequency_response 0xA20C
155#define tag_focal_plane_x_resolution 0xA20e
156#define tag_focal_plane_y_resolution 0xA20F
157#define tag_focal_plane_resolution_unit 0xA210
158#define tag_subject_location 0xA214
159#define tag_exposure_index 0xA215
160#define tag_sensing_method 0xA217
161#define tag_file_source 0xA300
162#define tag_scene_type 0xA301
163#define tag_cfa_pattern 0xA302
164#define tag_custom_rendered 0xA401
165#define tag_exposure_mode 0xA402
166#define tag_white_balance 0xA403
167#define tag_digital_zoom_ratio 0xA404
168#define tag_focal_length_in_35mm_film 0xA405
169#define tag_scene_capture_type 0xA406
170#define tag_gain_control 0xA407
171#define tag_contrast 0xA408
172#define tag_saturation 0xA409
173#define tag_sharpness 0xA40A
174#define tag_device_setting_description 0xA40B
175#define tag_subject_distance_range 0xA40C
176
59957854
TC
177/* GPS tags */
178#define tag_gps_version_id 0
179#define tag_gps_latitude_ref 1
180#define tag_gps_latitude 2
181#define tag_gps_longitude_ref 3
182#define tag_gps_longitude 4
183#define tag_gps_altitude_ref 5
184#define tag_gps_altitude 6
185#define tag_gps_time_stamp 7
186#define tag_gps_satellites 8
187#define tag_gps_status 9
188#define tag_gps_measure_mode 10
189#define tag_gps_dop 11
190#define tag_gps_speed_ref 12
191#define tag_gps_speed 13
192#define tag_gps_track_ref 14
193#define tag_gps_track 15
194#define tag_gps_img_direction_ref 16
195#define tag_gps_img_direction 17
196#define tag_gps_map_datum 18
197#define tag_gps_dest_latitude_ref 19
198#define tag_gps_dest_latitude 20
199#define tag_gps_dest_longitude_ref 21
200#define tag_gps_dest_longitude 22
201#define tag_gps_dest_bearing_ref 23
202#define tag_gps_dest_bearing 24
203#define tag_gps_dest_distance_ref 25
204#define tag_gps_dest_distance 26
205#define tag_gps_processing_method 27
206#define tag_gps_area_information 28
207#define tag_gps_date_stamp 29
208#define tag_gps_differential 30
209
f7450478
TC
210/* don't use this on pointers */
211#define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array))
212
213/* in memory tiff structure */
214typedef struct {
215 /* the data we use as a tiff */
0b365b7f 216 const unsigned char *base;
f7450478
TC
217 size_t size;
218
219 /* intel or motorola byte order */
220 tiff_type type;
221
222 /* initial ifd offset */
223 unsigned long first_ifd_offset;
224
225 /* size (in entries) and data */
226 int ifd_size;
227 ifd_entry *ifd;
228 unsigned long next_ifd;
229} imtiff;
230
0b365b7f 231static int tiff_init(imtiff *tiff, const unsigned char *base, size_t length);
f7450478
TC
232static int tiff_load_ifd(imtiff *tiff, unsigned long offset);
233static void tiff_final(imtiff *tiff);
234static void tiff_clear_ifd(imtiff *tiff);
e4bf9335 235#if 0 /* currently unused, but that may change */
f7450478
TC
236static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset,
237 size_t count);
e4bf9335 238#endif
f7450478
TC
239static int tiff_get_tag_double(imtiff *, int index, double *result);
240static int tiff_get_tag_int(imtiff *, int index, int *result);
241static unsigned tiff_get16(imtiff *, unsigned long offset);
242static unsigned tiff_get32(imtiff *, unsigned long offset);
243static int tiff_get16s(imtiff *, unsigned long offset);
244static int tiff_get32s(imtiff *, unsigned long offset);
245static double tiff_get_rat(imtiff *, unsigned long offset);
246static double tiff_get_rats(imtiff *, unsigned long offset);
59957854 247static void save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset, unsigned long *gps_ifd_offset);
f7450478 248static void save_exif_ifd_tags(i_img *im, imtiff *tiff);
59957854 249static void save_gps_ifd_tags(i_img *im, imtiff *tiff);
f7450478
TC
250static void
251copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
252static void
253copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
254static void
255copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
256static void
59957854
TC
257copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
258static void
f7450478
TC
259copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count);
260static void process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size);
261
262/*
263=head1 PUBLIC FUNCTIONS
264
265These functions are available to other parts of Imager. They aren't
266intended to be called from outside of Imager.
267
268=over
269
75e155e1 270=item im_decode_exif
f7450478 271
75e155e1 272im_decode_exif(im, data_base, data_size);
f7450478 273
75e155e1
TC
274The data from C<data_base> for C<data_size> bytes will be scanned for
275EXIF data.
f7450478
TC
276
277Any data found will be used to set tags in the supplied image.
278
279The intent is that invalid EXIF data will simply fail to set tags, and
280write to the log. In no case should this code exit when supplied
281invalid data.
282
75e155e1 283Returns true if an EXIF header was seen.
f7450478 284
12db268a 285=cut
f7450478
TC
286*/
287
288int
0b365b7f 289im_decode_exif(i_img *im, const unsigned char *data, size_t length) {
f7450478
TC
290 imtiff tiff;
291 unsigned long exif_ifd_offset = 0;
59957854 292 unsigned long gps_ifd_offset = 0;
f7450478
TC
293
294 if (!tiff_init(&tiff, data, length)) {
295 mm_log((2, "Exif header found, but no valid TIFF header\n"));
296 return 1;
297 }
298 if (!tiff_load_ifd(&tiff, tiff.first_ifd_offset)) {
299 mm_log((2, "Exif header found, but could not load IFD 0\n"));
300 tiff_final(&tiff);
301 return 1;
302 }
303
59957854 304 save_ifd0_tags(im, &tiff, &exif_ifd_offset, &gps_ifd_offset);
f7450478
TC
305
306 if (exif_ifd_offset) {
307 if (tiff_load_ifd(&tiff, exif_ifd_offset)) {
308 save_exif_ifd_tags(im, &tiff);
309 }
310 else {
311 mm_log((2, "Could not load Exif IFD\n"));
312 }
313 }
314
59957854
TC
315 if (gps_ifd_offset) {
316 if (tiff_load_ifd(&tiff, gps_ifd_offset)) {
317 save_gps_ifd_tags(im, &tiff);
318 }
319 else {
320 mm_log((2, "Could not load GPS IFD\n"));
321 }
322 }
323
f7450478
TC
324 tiff_final(&tiff);
325
326 return 1;
327}
328
329/*
330
331=back
332
333=head1 INTERNAL FUNCTIONS
334
335=head2 EXIF Processing
336
337=over
338
339=item save_ifd0_tags
340
59957854 341save_ifd0_tags(im, tiff, &exif_ifd_offset, &gps_ifd_offset)
f7450478
TC
342
343Scans the currently loaded IFD for tags expected in IFD0 and sets them
344in the image.
345
346Sets *exif_ifd_offset to the offset of the EXIF IFD if found.
347
348=cut
349
350*/
351
352static tag_map ifd0_string_tags[] =
353 {
af070d99
TC
354 { tag_make, "exif_make" },
355 { tag_model, "exif_model" },
356 { tag_copyright, "exif_copyright" },
357 { tag_software, "exif_software" },
358 { tag_artist, "exif_artist" },
359 { tag_date_time, "exif_date_time" },
360 { tag_image_description, "exif_image_description" },
f7450478
TC
361 };
362
363static const int ifd0_string_tag_count = ARRAY_COUNT(ifd0_string_tags);
364
365static tag_map ifd0_int_tags[] =
366 {
367 { tag_orientation, "exif_orientation", },
368 { tag_resolution_unit, "exif_resolution_unit" },
369 };
370
371static const int ifd0_int_tag_count = ARRAY_COUNT(ifd0_int_tags);
372
373static tag_map ifd0_rat_tags[] =
374 {
375 { tag_x_resolution, "exif_x_resolution" },
376 { tag_y_resolution, "exif_y_resolution" },
377 };
378
379static tag_map resolution_unit_values[] =
380 {
381 { 1, "none" },
382 { 2, "inches" },
383 { 3, "centimeters" },
384 };
385
386static tag_value_map ifd0_values[] =
387 {
388 VALUE_MAP_ENTRY(resolution_unit),
389 };
390
391static void
59957854
TC
392save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset,
393 unsigned long *gps_ifd_offset) {
af070d99 394 int tag_index;
f7450478
TC
395 int work;
396 ifd_entry *entry;
397
398 for (tag_index = 0, entry = tiff->ifd;
399 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
400 switch (entry->tag) {
401 case tag_exif_ifd:
402 if (tiff_get_tag_int(tiff, tag_index, &work))
403 *exif_ifd_offset = work;
404 break;
59957854
TC
405
406 case tag_gps_ifd:
407 if (tiff_get_tag_int(tiff, tag_index, &work))
408 *gps_ifd_offset = work;
409 break;
f7450478
TC
410 }
411 }
412
413 copy_string_tags(im, tiff, ifd0_string_tags, ifd0_string_tag_count);
414 copy_int_tags(im, tiff, ifd0_int_tags, ifd0_int_tag_count);
415 copy_rat_tags(im, tiff, ifd0_rat_tags, ARRAY_COUNT(ifd0_rat_tags));
416 copy_name_tags(im, tiff, ifd0_values, ARRAY_COUNT(ifd0_values));
59957854 417 /* copy_num_array_tags(im, tiff, ifd0_num_arrays, ARRAY_COUNT(ifd0_num_arrays)); */
f7450478
TC
418}
419
420/*
421=item save_exif_ifd_tags
422
423save_exif_ifd_tags(im, tiff)
424
425Scans the currently loaded IFD for the tags expected in the EXIF IFD
426and sets them as tags in the image.
427
428=cut
429
430*/
431
432static tag_map exif_ifd_string_tags[] =
433 {
434 { tag_exif_version, "exif_version", },
435 { tag_flashpix_version, "exif_flashpix_version", },
436 { tag_related_sound_file, "exif_related_sound_file", },
437 { tag_date_time_original, "exif_date_time_original", },
438 { tag_date_time_digitized, "exif_date_time_digitized", },
439 { tag_sub_sec_time, "exif_sub_sec_time" },
440 { tag_sub_sec_time_original, "exif_sub_sec_time_original" },
441 { tag_sub_sec_time_digitized, "exif_sub_sec_time_digitized" },
442 { tag_image_unique_id, "exif_image_unique_id" },
443 { tag_spectral_sensitivity, "exif_spectral_sensitivity" },
444 };
445
446static const int exif_ifd_string_tag_count = ARRAY_COUNT(exif_ifd_string_tags);
447
448static tag_map exif_ifd_int_tags[] =
449 {
450 { tag_color_space, "exif_color_space" },
451 { tag_exposure_program, "exif_exposure_program" },
f7450478
TC
452 { tag_metering_mode, "exif_metering_mode" },
453 { tag_light_source, "exif_light_source" },
454 { tag_flash, "exif_flash" },
455 { tag_focal_plane_resolution_unit, "exif_focal_plane_resolution_unit" },
456 { tag_subject_location, "exif_subject_location" },
457 { tag_sensing_method, "exif_sensing_method" },
458 { tag_custom_rendered, "exif_custom_rendered" },
459 { tag_exposure_mode, "exif_exposure_mode" },
460 { tag_white_balance, "exif_white_balance" },
461 { tag_focal_length_in_35mm_film, "exif_focal_length_in_35mm_film" },
462 { tag_scene_capture_type, "exif_scene_capture_type" },
463 { tag_contrast, "exif_contrast" },
464 { tag_saturation, "exif_saturation" },
465 { tag_sharpness, "exif_sharpness" },
466 { tag_subject_distance_range, "exif_subject_distance_range" },
467 };
468
469
470static const int exif_ifd_int_tag_count = ARRAY_COUNT(exif_ifd_int_tags);
471
472static tag_map exif_ifd_rat_tags[] =
473 {
474 { tag_exposure_time, "exif_exposure_time" },
475 { tag_f_number, "exif_f_number" },
476 { tag_shutter_speed, "exif_shutter_speed" },
477 { tag_aperture, "exif_aperture" },
478 { tag_brightness, "exif_brightness" },
479 { tag_exposure_bias, "exif_exposure_bias" },
480 { tag_max_aperture, "exif_max_aperture" },
481 { tag_subject_distance, "exif_subject_distance" },
482 { tag_focal_length, "exif_focal_length" },
483 { tag_flash_energy, "exif_flash_energy" },
484 { tag_focal_plane_x_resolution, "exif_focal_plane_x_resolution" },
485 { tag_focal_plane_y_resolution, "exif_focal_plane_y_resolution" },
486 { tag_exposure_index, "exif_exposure_index" },
487 { tag_digital_zoom_ratio, "exif_digital_zoom_ratio" },
488 { tag_gain_control, "exif_gain_control" },
489 };
490
491static const int exif_ifd_rat_tag_count = ARRAY_COUNT(exif_ifd_rat_tags);
492
493static tag_map exposure_mode_values[] =
494 {
495 { 0, "Auto exposure" },
496 { 1, "Manual exposure" },
497 { 2, "Auto bracket" },
498 };
499static tag_map color_space_values[] =
500 {
501 { 1, "sRGB" },
502 { 0xFFFF, "Uncalibrated" },
503 };
504
505static tag_map exposure_program_values[] =
506 {
507 { 0, "Not defined" },
508 { 1, "Manual" },
509 { 2, "Normal program" },
510 { 3, "Aperture priority" },
511 { 4, "Shutter priority" },
512 { 5, "Creative program" },
513 { 6, "Action program" },
514 { 7, "Portrait mode" },
515 { 8, "Landscape mode" },
516 };
517
518static tag_map metering_mode_values[] =
519 {
520 { 0, "unknown" },
521 { 1, "Average" },
522 { 2, "CenterWeightedAverage" },
523 { 3, "Spot" },
524 { 4, "MultiSpot" },
525 { 5, "Pattern" },
526 { 6, "Partial" },
527 { 255, "other" },
528 };
529
530static tag_map light_source_values[] =
531 {
532 { 0, "unknown" },
533 { 1, "Daylight" },
534 { 2, "Fluorescent" },
535 { 3, "Tungsten (incandescent light)" },
536 { 4, "Flash" },
537 { 9, "Fine weather" },
538 { 10, "Cloudy weather" },
539 { 11, "Shade" },
540