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