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