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