10 imexif.c - EXIF support for Imager
14 if (i_int_decode_exif(im, app1data, app1datasize)) {
20 This code provides a basic EXIF data decoder. It is intended to be
21 called from the JPEG reader code when an APP1 data block is found, and
22 will set tags in the supplied image.
27 typedef enum tiff_type_tag {
45 ift_last = 12 /* keep the same as the highest type code */
48 static int type_sizes[] =
86 #define PASTE(left, right) PASTE_(left, right)
87 #define PASTE_(left, right) left##right
88 #define QUOTE(value) #value
90 #define VALUE_MAP_ENTRY(name) \
93 "exif_" QUOTE(name) "_name", \
94 PASTE(name, _values), \
95 ARRAY_COUNT(PASTE(name, _values)) \
98 /* we don't process every tag */
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
111 #define tag_exif_ifd 34665
112 #define tag_gps_ifd 34853
114 #define resunit_none 1
115 #define resunit_inch 2
116 #define resunit_centimeter 3
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
139 #define tag_iso_speed_ratings 0x8827
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
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
209 /* don't use this on pointers */
210 #define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array))
212 /* in memory tiff structure */
214 /* the data we use as a tiff */
218 /* intel or motorola byte order */
221 /* initial ifd offset */
222 unsigned long first_ifd_offset;
224 /* size (in entries) and data */
227 unsigned long next_ifd;
230 static int tiff_init(imtiff *tiff, unsigned char *base, size_t length);
231 static int tiff_load_ifd(imtiff *tiff, unsigned long offset);
232 static void tiff_final(imtiff *tiff);
233 static void tiff_clear_ifd(imtiff *tiff);
234 #if 0 /* currently unused, but that may change */
235 static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset,
238 static int tiff_get_tag_double(imtiff *, int index, double *result);
239 static int tiff_get_tag_int(imtiff *, int index, int *result);
240 static unsigned tiff_get16(imtiff *, unsigned long offset);
241 static unsigned tiff_get32(imtiff *, unsigned long offset);
242 static int tiff_get16s(imtiff *, unsigned long offset);
243 static int tiff_get32s(imtiff *, unsigned long offset);
244 static double tiff_get_rat(imtiff *, unsigned long offset);
245 static double tiff_get_rats(imtiff *, unsigned long offset);
246 static void save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset, unsigned long *gps_ifd_offset);
247 static void save_exif_ifd_tags(i_img *im, imtiff *tiff);
248 static void save_gps_ifd_tags(i_img *im, imtiff *tiff);
250 copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
252 copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
254 copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
256 copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
258 copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count);
259 static void process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size);
262 =head1 PUBLIC FUNCTIONS
264 These functions are available to other parts of Imager. They aren't
265 intended to be called from outside of Imager.
269 =item i_int_decode_exit
271 i_int_decode_exif(im, data_base, data_size);
273 The data from data_base for data_size bytes will be scanned for EXIF
276 Any data found will be used to set tags in the supplied image.
278 The intent is that invalid EXIF data will simply fail to set tags, and
279 write to the log. In no case should this code exit when supplied
282 Returns true if an Exif header was seen.
287 i_int_decode_exif(i_img *im, unsigned char *data, size_t length) {
289 unsigned long exif_ifd_offset = 0;
290 unsigned long gps_ifd_offset = 0;
291 /* basic checks - must start with "Exif\0\0" */
293 if (length < 6 || memcmp(data, "Exif\0\0", 6) != 0) {
300 if (!tiff_init(&tiff, data, length)) {
301 mm_log((2, "Exif header found, but no valid TIFF header\n"));
304 if (!tiff_load_ifd(&tiff, tiff.first_ifd_offset)) {
305 mm_log((2, "Exif header found, but could not load IFD 0\n"));
310 save_ifd0_tags(im, &tiff, &exif_ifd_offset, &gps_ifd_offset);
312 if (exif_ifd_offset) {
313 if (tiff_load_ifd(&tiff, exif_ifd_offset)) {
314 save_exif_ifd_tags(im, &tiff);
317 mm_log((2, "Could not load Exif IFD\n"));
321 if (gps_ifd_offset) {
322 if (tiff_load_ifd(&tiff, gps_ifd_offset)) {
323 save_gps_ifd_tags(im, &tiff);
326 mm_log((2, "Could not load GPS IFD\n"));
339 =head1 INTERNAL FUNCTIONS
341 =head2 EXIF Processing
347 save_ifd0_tags(im, tiff, &exif_ifd_offset, &gps_ifd_offset)
349 Scans the currently loaded IFD for tags expected in IFD0 and sets them
352 Sets *exif_ifd_offset to the offset of the EXIF IFD if found.
358 static tag_map ifd0_string_tags[] =
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" },
369 static const int ifd0_string_tag_count = ARRAY_COUNT(ifd0_string_tags);
371 static tag_map ifd0_int_tags[] =
373 { tag_orientation, "exif_orientation", },
374 { tag_resolution_unit, "exif_resolution_unit" },
377 static const int ifd0_int_tag_count = ARRAY_COUNT(ifd0_int_tags);
379 static tag_map ifd0_rat_tags[] =
381 { tag_x_resolution, "exif_x_resolution" },
382 { tag_y_resolution, "exif_y_resolution" },
385 static tag_map resolution_unit_values[] =
389 { 3, "centimeters" },
392 static tag_value_map ifd0_values[] =
394 VALUE_MAP_ENTRY(resolution_unit),
398 save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset,
399 unsigned long *gps_ifd_offset) {
404 for (tag_index = 0, entry = tiff->ifd;
405 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
406 switch (entry->tag) {
408 if (tiff_get_tag_int(tiff, tag_index, &work))
409 *exif_ifd_offset = work;
413 if (tiff_get_tag_int(tiff, tag_index, &work))
414 *gps_ifd_offset = work;
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));
423 /* copy_num_array_tags(im, tiff, ifd0_num_arrays, ARRAY_COUNT(ifd0_num_arrays)); */
427 =item save_exif_ifd_tags
429 save_exif_ifd_tags(im, tiff)
431 Scans the currently loaded IFD for the tags expected in the EXIF IFD
432 and sets them as tags in the image.
438 static tag_map exif_ifd_string_tags[] =
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" },
452 static const int exif_ifd_string_tag_count = ARRAY_COUNT(exif_ifd_string_tags);
454 static tag_map exif_ifd_int_tags[] =
456 { tag_color_space, "exif_color_space" },
457 { tag_exposure_program, "exif_exposure_program" },
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" },
476 static const int exif_ifd_int_tag_count = ARRAY_COUNT(exif_ifd_int_tags);
478 static tag_map exif_ifd_rat_tags[] =
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" },
497 static const int exif_ifd_rat_tag_count = ARRAY_COUNT(exif_ifd_rat_tags);
499 static tag_map exposure_mode_values[] =
501 { 0, "Auto exposure" },
502 { 1, "Manual exposure" },
503 { 2, "Auto bracket" },
505 static tag_map color_space_values[] =
508 { 0xFFFF, "Uncalibrated" },
511 static tag_map exposure_program_values[] =
513 { 0, "Not defined" },
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" },
524 static tag_map metering_mode_values[] =
528 { 2, "CenterWeightedAverage" },
536 static tag_map light_source_values[] =
540 { 2, "Fluorescent" },
541 { 3, "Tungsten (incandescent light)" },
543 { 9, "Fine weather" },
544 { 10, "Cloudy weather" },
546 { 12, "Daylight fluorescent (D 5700 Ã 7100K)" },
547 { 13, "Day white fluorescent (N 4600 Ã 5400K)" },
548 { 14, "Cool white fluorescent (W 3900 Ã 4500K)" },
549 { 15, "White fluorescent (WW 3200 Ã 3700K)" },
550 { 17, "Standard light A" },
551 { 18, "Standard light B" },
552 { 19, "Standard light C" },
557 { 24, "ISO studio tungsten" },
558 { 255, "other light source" },
561 static tag_map flash_values[] =
563 { 0x0000, "Flash did not fire." },
564 { 0x0001, "Flash fired." },
565 { 0x0005, "Strobe return light not detected." },
566 { 0x0007, "Strobe return light detected." },
567 { 0x0009, "Flash fired, compulsory flash mode" },
568 { 0x000D, "Flash fired, compulsory flash mode, return light not detected" },
569 { 0x000F, "Flash fired, compulsory flash mode, return light detected" },
570 { 0x0010, "Flash did not fire, compulsory flash mode" },
571 { 0x0018, "Flash did not fire, auto mode" },
572 { 0x0019, "Flash fired, auto mode" },
573 { 0x001D, "Flash fired, auto mode, return light not detected" },
574 { 0x001F, "Flash fired, auto mode, return light detected" },
575 { 0x0020, "No flash function" },
576 { 0x0041, "Flash fired, red-eye reduction mode" },
577 { 0x0045, "Flash fired, red-eye reduction mode, return light not detected" },
578 { 0x0047, "Flash fired, red-eye reduction mode, return light detected" },
579 { 0x0049, "Flash fired, compulsory flash mode, red-eye reduction mode" },
580 { 0x004D, "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected" },
581 { 0x004F, "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected" },
582 { 0x0059, "Flash fired, auto mode, red-eye reduction mode" },
583 { 0x005D, "Flash fired, auto mode, return light not detected, red-eye reduction mode" },
584 { 0x005F, "Flash fired, auto mode, return light detected, red-eye reduction mode" },
587 static tag_map sensing_method_values[] =
589 { 1, "Not defined" },
590 { 2, "One-chip color area sensor" },
591 { 3, "Two-chip color area sensor" },
592 { 4, "Three-chip color area sensor" },
593 { 5, "Color sequential area sensor" },
594 { 7, "Trilinear sensor" },
595 { 8, "Color sequential linear sensor" },
598 static tag_map custom_rendered_values[] =
600 { 0, "Normal process" },
601 { 1, "Custom process" },
604 static tag_map white_balance_values[] =
606 { 0, "Auto white balance" },
607 { 1, "Manual white balance" },
610 static tag_map scene_capture_type_values[] =
615 { 3, "Night scene" },
618 static tag_map gain_control_values[] =
621 { 1, "Low gain up" },
622 { 2, "High gain up" },
623 { 3, "Low gain down" },
624 { 4, "High gain down" },
627 static tag_map contrast_values[] =
634 static tag_map saturation_values[] =
637 { 1, "Low saturation" },
638 { 2, "High saturation" },
641 static tag_map sharpness_values[] =
648 static tag_map subject_distance_range_values[] =
653 { 3, "Distant view" },
656 #define focal_plane_resolution_unit_values resolution_unit_values
658 static tag_value_map exif_ifd_values[] =
660 VALUE_MAP_ENTRY(exposure_mode),
661 VALUE_MAP_ENTRY(color_space),
662 VALUE_MAP_ENTRY(exposure_program),
663 VALUE_MAP_ENTRY(metering_mode),
664 VALUE_MAP_ENTRY(light_source),
665 VALUE_MAP_ENTRY(flash),
666 VALUE_MAP_ENTRY(sensing_method),
667 VALUE_MAP_ENTRY(custom_rendered),
668 VALUE_MAP_ENTRY(white_balance),
669 VALUE_MAP_ENTRY(scene_capture_type),
670 VALUE_MAP_ENTRY(gain_control),
671 VALUE_MAP_ENTRY(contrast),
672 VALUE_MAP_ENTRY(saturation),
673 VALUE_MAP_ENTRY(sharpness),
674 VALUE_MAP_ENTRY(subject_distance_range),
675 VALUE_MAP_ENTRY(focal_plane_resolution_unit),
678 static tag_map exif_num_arrays[] =
680 { tag_iso_speed_ratings, "exif_iso_speed_ratings" },
681 { tag_subject_area, "exif_subject_area" },
682 { tag_subject_location, "exif_subject_location" },
686 save_exif_ifd_tags(i_img *im, imtiff *tiff) {
690 unsigned long maker_note_offset = 0;
691 size_t maker_note_size = 0;
693 for (tag_index = 0, entry = tiff->ifd;
694 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
695 switch (entry->tag) {
696 case tag_user_comment:
697 /* I don't want to trash the source, so work on a copy */
698 user_comment = mymalloc(entry->size);
699 memcpy(user_comment, tiff->base + entry->offset, entry->size);
700 /* the first 8 bytes indicate the encoding, make them into spaces
701 for better presentation */
702 for (i = 0; i < entry->size && i < 8; ++i) {
703 if (user_comment[i] == '\0')
704 user_comment[i] = ' ';
706 /* find the actual end of the string */
707 while (i < entry->size && user_comment[i])
709 i_tags_set(&im->tags, "exif_user_comment", user_comment, i);
710 myfree(user_comment);
714 maker_note_offset = entry->offset;
715 maker_note_size = entry->size;
718 /* the following aren't processed yet */
720 case tag_spatial_frequency_response:
721 case tag_file_source:
723 case tag_cfa_pattern:
724 case tag_device_setting_description:
725 case tag_subject_area:
730 copy_string_tags(im, tiff, exif_ifd_string_tags, exif_ifd_string_tag_count);
731 copy_int_tags(im, tiff, exif_ifd_int_tags, exif_ifd_int_tag_count);
732 copy_rat_tags(im, tiff, exif_ifd_rat_tags, exif_ifd_rat_tag_count);
733 copy_name_tags(im, tiff, exif_ifd_values, ARRAY_COUNT(exif_ifd_values));
734 copy_num_array_tags(im, tiff, exif_num_arrays, ARRAY_COUNT(exif_num_arrays));
736 /* This trashes the IFD - make sure it's done last */
737 if (maker_note_offset) {
738 process_maker_note(im, tiff, maker_note_offset, maker_note_size);
742 static tag_map gps_ifd_string_tags[] =
744 { tag_gps_version_id, "exif_gps_version_id" },
745 { tag_gps_latitude_ref, "exif_gps_latitude_ref" },
746 { tag_gps_longitude_ref, "exif_gps_longitude_ref" },
747 { tag_gps_altitude_ref, "exif_gps_altitude_ref" },
748 { tag_gps_satellites, "exif_gps_satellites" },
749 { tag_gps_status, "exif_gps_status" },
750 { tag_gps_measure_mode, "exif_gps_measure_mode" },
751 { tag_gps_speed_ref, "exif_gps_speed_ref" },
752 { tag_gps_track_ref, "exif_gps_track_ref" },
755 static tag_map gps_ifd_int_tags[] =
757 { tag_gps_differential, "exif_gps_differential" },
760 static tag_map gps_ifd_rat_tags[] =
762 { tag_gps_altitude, "exif_gps_altitude" },
763 { tag_gps_time_stamp, "exif_gps_time_stamp" },
764 { tag_gps_dop, "exif_gps_dop" },
765 { tag_gps_speed, "exif_gps_speed" },
766 { tag_gps_track, "exif_track" }
769 static tag_map gps_differential_values [] =
771 { 0, "without differential correction" },
772 { 1, "Differential correction applied" },
775 static tag_value_map gps_ifd_values[] =
777 VALUE_MAP_ENTRY(gps_differential),
780 static tag_map gps_num_arrays[] =
782 { tag_gps_latitude, "exif_gps_latitude" },
783 { tag_gps_longitude, "exif_gps_longitude" },
787 save_gps_ifd_tags(i_img *im, imtiff *tiff) {
792 /* for (tag_index = 0, entry = tiff->ifd;
793 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
794 switch (entry->tag) {
799 copy_string_tags(im, tiff, gps_ifd_string_tags,
800 ARRAY_COUNT(gps_ifd_string_tags));
801 copy_int_tags(im, tiff, gps_ifd_int_tags, ARRAY_COUNT(gps_ifd_int_tags));
802 copy_rat_tags(im, tiff, gps_ifd_rat_tags, ARRAY_COUNT(gps_ifd_rat_tags));
803 copy_name_tags(im, tiff, gps_ifd_values, ARRAY_COUNT(gps_ifd_values));
804 copy_num_array_tags(im, tiff, gps_num_arrays, ARRAY_COUNT(gps_num_arrays));
808 =item process_maker_note
810 This is a stub for processing the maker note tag.
812 Maker notes aren't covered by EXIF itself and in general aren't
813 documented by the manufacturers.
819 process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size) {
820 /* this will be added in a future release */
826 =head2 High level TIFF functions
828 To avoid relying upon tifflib when we're not processing an image we
829 have some simple in-memory TIFF file management.
836 if (tiff_init(tiff, data_base, data_size)) {
840 Initialize the tiff data structure.
842 Scans for the byte order and version markers, and stores the offset to
843 the first IFD (IFD0 in EXIF) in first_ifd_offset.
849 tiff_init(imtiff *tiff, unsigned char *data, size_t length) {
854 if (length < 8) /* well... would have to be much bigger to be useful */
856 if (data[0] == 'M' && data[1] == 'M')
857 tiff->type = tt_motorola;
858 else if (data[0] == 'I' && data[1] == 'I')
859 tiff->type = tt_intel;
861 return 0; /* invalid header */
863 version = tiff_get16(tiff, 2);
867 tiff->first_ifd_offset = tiff_get32(tiff, 4);
868 if (tiff->first_ifd_offset > length || tiff->first_ifd_offset < 8)
883 Clean up the tiff structure initialized by tiff_init()
889 tiff_final(imtiff *tiff) {
890 tiff_clear_ifd(tiff);
896 if (tiff_load_ifd(tiff, offset)) {
900 Loads the IFD from the given offset into the tiff objects ifd.
902 This can fail if the IFD extends beyond end of file, or if any data
903 offsets combined with their sizes, extends beyond end of file.
905 Returns true on success.
911 tiff_load_ifd(imtiff *tiff, unsigned long offset) {
914 ifd_entry *entries = NULL;
918 tiff_clear_ifd(tiff);
920 /* rough check count + 1 entry + next offset */
921 if (offset + (2+12+4) > tiff->size) {
922 mm_log((2, "offset %uld beyond end off Exif block"));
926 count = tiff_get16(tiff, offset);
928 /* check we can fit the whole thing */
929 ifd_size = 2 + count * 12 + 4; /* count + count entries + next offset */
930 if (offset + ifd_size > tiff->size) {
931 mm_log((2, "offset %uld beyond end off Exif block"));
935 entries = mymalloc(count * sizeof(ifd_entry));
936 memset(entries, 0, count * sizeof(ifd_entry));
938 for (i = 0; i < count; ++i) {
939 ifd_entry *entry = entries + i;
940 entry->tag = tiff_get16(tiff, base);
941 entry->type = tiff_get16(tiff, base+2);
942 entry->count = tiff_get32(tiff, base+4);
943 if (entry->type >= 1 && entry->type <= ift_last) {
944 entry->item_size = type_sizes[entry->type];
945 entry->size = entry->item_size * entry->count;
946 if (entry->size / entry->item_size != entry->count) {
948 mm_log((1, "Integer overflow calculating tag data size processing EXIF block\n"));
951 else if (entry->size <= 4) {
952 entry->offset = base + 8;
955 entry->offset = tiff_get32(tiff, base+8);
956 if (entry->offset + entry->size > tiff->size) {
957 mm_log((2, "Invalid data offset processing IFD\n"));
970 tiff->ifd_size = count;
972 tiff->next_ifd = tiff_get32(tiff, base);
982 Releases any memory associated with the stored IFD and resets the IFD
985 This is called by tiff_load_ifd() and tiff_final().
991 tiff_clear_ifd(imtiff *tiff) {
992 if (tiff->ifd_size && tiff->ifd) {
1000 =item tiff_get_tag_double
1003 if (tiff_get_tag(tiff, index, &value)) {
1007 Attempts to retrieve a double value from the given index in the
1010 The value must have a count of 1.
1016 tiff_get_tag_double_array(imtiff *tiff, int index, double *result,
1019 unsigned long offset;
1020 if (index < 0 || index >= tiff->ifd_size) {
1021 mm_log((3, "tiff_get_tag_double_array() tag index out of range"));
1025 entry = tiff->ifd + index;
1026 if (array_index < 0 || array_index >= entry->count) {
1027 mm_log((3, "tiff_get_tag_double_array() array index out of range"));
1031 offset = entry->offset + array_index * entry->item_size;
1033 switch (entry->type) {
1035 *result = tiff_get16(tiff, offset);
1039 *result = tiff_get32(tiff, offset);
1043 *result = tiff_get_rat(tiff, offset);
1047 *result = tiff_get16s(tiff, offset);
1051 *result = tiff_get32s(tiff, offset);
1055 *result = tiff_get_rats(tiff, offset);
1059 *result = *(tiff->base + offset);
1067 =item tiff_get_tag_double
1070 if (tiff_get_tag(tiff, index, &value)) {
1074 Attempts to retrieve a double value from the given index in the
1077 The value must have a count of 1.
1083 tiff_get_tag_double(imtiff *tiff, int index, double *result) {
1085 if (index < 0 || index >= tiff->ifd_size) {
1086 mm_log((3, "tiff_get_tag_double() index out of range"));
1090 entry = tiff->ifd + index;
1091 if (entry->count != 1) {
1092 mm_log((3, "tiff_get_tag_double() called on tag with multiple values"));
1096 return tiff_get_tag_double_array(tiff, index, result, 0);
1100 =item tiff_get_tag_int_array
1103 if (tiff_get_tag_int_array(tiff, index, &value, array_index)) {
1107 Attempts to retrieve an integer value from the given index in the
1114 tiff_get_tag_int_array(imtiff *tiff, int index, int *result, int array_index) {
1116 unsigned long offset;
1117 if (index < 0 || index >= tiff->ifd_size) {
1118 mm_log((3, "tiff_get_tag_int_array() tag index out of range"));
1122 entry = tiff->ifd + index;
1123 if (array_index < 0 || array_index >= entry->count) {
1124 mm_log((3, "tiff_get_tag_int_array() array index out of range"));
1128 offset = entry->offset + array_index * entry->item_size;
1130 switch (entry->type) {
1132 *result = tiff_get16(tiff, offset);
1136 *result = tiff_get32(tiff, offset);
1140 *result = tiff_get16s(tiff, offset);
1144 *result = tiff_get32s(tiff, offset);
1148 *result = *(tiff->base + offset);
1156 =item tiff_get_tag_int
1159 if (tiff_get_tag_int(tiff, index, &value)) {
1163 Attempts to retrieve an integer value from the given index in the
1166 The value must have a count of 1.
1172 tiff_get_tag_int(imtiff *tiff, int index, int *result) {
1174 if (index < 0 || index >= tiff->ifd_size) {
1175 mm_log((3, "tiff_get_tag_int() index out of range"));
1179 entry = tiff->ifd + index;
1180 if (entry->count != 1) {
1181 mm_log((3, "tiff_get_tag_int() called on tag with multiple values"));
1185 return tiff_get_tag_int_array(tiff, index, result, 0);
1191 =head2 Table-based tag setters
1193 This set of functions checks for matches between the current IFD and
1194 tags supplied in an array, when there's a match it sets the
1195 appropriate tag in the image.
1201 Scans the IFD for integer tags and sets them in the image,
1207 copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1211 for (tag_index = 0, entry = tiff->ifd;
1212 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1213 for (i = 0; i < map_count; ++i) {
1215 if (map[i].tag == entry->tag
1216 && tiff_get_tag_int(tiff, tag_index, &value)) {
1217 i_tags_setn(&im->tags, map[i].name, value);
1227 Scans the IFD for rational tags and sets them in the image.
1233 copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1237 for (tag_index = 0, entry = tiff->ifd;
1238 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1239 for (i = 0; i < map_count; ++i) {
1241 if (map[i].tag == entry->tag
1242 && tiff_get_tag_double(tiff, tag_index, &value)) {
1243 i_tags_set_float2(&im->tags, map[i].name, 0, value, 6);
1251 =item copy_string_tags
1253 Scans the IFD for string tags and sets them in the image.
1259 copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1263 for (tag_index = 0, entry = tiff->ifd;
1264 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1265 for (i = 0; i < map_count; ++i) {
1266 if (map[i].tag == entry->tag) {
1267 int len = entry->type == ift_ascii ? entry->size - 1 : entry->size;
1268 i_tags_set(&im->tags, map[i].name,
1269 (char const *)(tiff->base + entry->offset), len);
1277 =item copy_num_array_tags
1279 Scans the IFD for arrays of numbers and sets them in the image.
1284 /* a more general solution would be better in some ways, but we don't need it */
1285 #define MAX_ARRAY_VALUES 10
1286 #define MAX_ARRAY_STRING (MAX_ARRAY_VALUES * 20)
1289 copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1290 int i, j, tag_index;
1293 for (tag_index = 0, entry = tiff->ifd;
1294 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1295 for (i = 0; i < map_count; ++i) {
1296 if (map[i].tag == entry->tag && entry->count <= MAX_ARRAY_VALUES) {
1297 if (entry->type == ift_rational || entry->type == ift_srational) {
1299 char workstr[MAX_ARRAY_STRING];
1301 for (j = 0; j < entry->count; ++j) {
1302 if (!tiff_get_tag_double_array(tiff, tag_index, &value, j)) {
1303 mm_log((3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j));
1307 strcat(workstr, " ");
1308 sprintf(workstr + strlen(workstr), "%.6g", value);
1310 i_tags_set(&im->tags, map[i].name, workstr, -1);
1312 else if (entry->type == ift_short || entry->type == ift_long
1313 || entry->type == ift_sshort || entry->type == ift_slong
1314 || entry->type == ift_byte) {
1316 char workstr[MAX_ARRAY_STRING];
1318 for (j = 0; j < entry->count; ++j) {
1319 if (!tiff_get_tag_int_array(tiff, tag_index, &value, j)) {
1320 mm_log((3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j));
1324 strcat(workstr, " ");
1325 sprintf(workstr + strlen(workstr), "%d", value);
1327 i_tags_set(&im->tags, map[i].name, workstr, -1);
1336 =item copy_name_tags
1338 This function maps integer values to descriptions for those values.
1340 In general we handle the integer value through copy_int_tags() and
1341 then the same tage with a "_name" suffix here.
1347 copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count) {
1348 int i, j, tag_index;
1351 for (tag_index = 0, entry = tiff->ifd;
1352 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1353 for (i = 0; i < map_count; ++i) {
1355 if (map[i].tag == entry->tag
1356 && tiff_get_tag_int(tiff, tag_index, &value)) {
1357 tag_map const *found = NULL;
1358 for (j = 0; j < map[i].map_count; ++j) {
1359 if (value == map[i].map[j].tag) {
1360 found = map[i].map + j;
1365 i_tags_set(&im->tags, map[i].name, found->name, -1);
1377 =head2 Low level data access functions
1379 These functions use the byte order in the tiff object to extract
1380 various types of data from the tiff data.
1382 These functions will abort if called with an out of range offset.
1384 The intent is that any offset checks should have been done by the caller.
1390 Retrieve a 16 bit unsigned integer from offset.
1396 tiff_get16(imtiff *tiff, unsigned long offset) {
1397 if (offset + 2 > tiff->size) {
1398 mm_log((3, "attempt to get16 at %uld in %uld image", offset, tiff->size));
1402 if (tiff->type == tt_intel)
1403 return tiff->base[offset] + 0x100 * tiff->base[offset+1];
1405 return tiff->base[offset+1] + 0x100 * tiff->base[offset];
1411 Retrieve a 32-bit unsigned integer from offset.
1417 tiff_get32(imtiff *tiff, unsigned long offset) {
1418 if (offset + 4 > tiff->size) {
1419 mm_log((3, "attempt to get16 at %uld in %uld image", offset, tiff->size));
1423 if (tiff->type == tt_intel)
1424 return tiff->base[offset] + 0x100 * tiff->base[offset+1]
1425 + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1427 return tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1428 + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1431 #if 0 /* currently unused, but that may change */
1434 =item tiff_get_bytes
1436 Retrieve a byte string from offset.
1438 This isn't used much, you can usually deal with the data in-situ.
1439 This is intended for use when you need to modify the data in some way.
1445 tiff_get_bytes(imtiff *tiff, unsigned char *data, size_t offset,
1447 if (offset + size > tiff->size)
1450 memcpy(data, tiff->base+offset, size);
1460 Retrieve a 16-bit signed integer from offset.
1466 tiff_get16s(imtiff *tiff, unsigned long offset) {
1469 if (offset + 2 > tiff->size) {
1470 mm_log((3, "attempt to get16 at %uld in %uld image", offset, tiff->size));
1474 if (tiff->type == tt_intel)
1475 result = tiff->base[offset] + 0x100 * tiff->base[offset+1];
1477 result = tiff->base[offset+1] + 0x100 * tiff->base[offset];
1479 if (result > 0x7FFF)
1488 Retrieve a 32-bit signed integer from offset.
1494 tiff_get32s(imtiff *tiff, unsigned long offset) {
1497 if (offset + 4 > tiff->size) {
1498 mm_log((3, "attempt to get16 at %uld in %uld image", offset, tiff->size));
1502 if (tiff->type == tt_intel)
1503 work = tiff->base[offset] + 0x100 * tiff->base[offset+1]
1504 + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1506 work = tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1507 + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1509 /* not really needed on 32-bit int machines */
1510 if (work > 0x7FFFFFFFUL)
1511 return work - 0x80000000UL;
1519 Retrieve an unsigned rational from offset.
1525 tiff_get_rat(imtiff *tiff, unsigned long offset) {
1526 unsigned long numer, denom;
1527 if (offset + 8 > tiff->size) {
1528 mm_log((3, "attempt to get_rat at %lu in %lu image", offset, tiff->size));
1532 numer = tiff_get32(tiff, offset);
1533 denom = tiff_get32(tiff, offset+4);
1539 return (double)numer / denom;
1545 Retrieve an signed rational from offset.
1551 tiff_get_rats(imtiff *tiff, unsigned long offset) {
1553 if (offset + 8 > tiff->size) {
1554 mm_log((3, "attempt to get_rat at %lu in %lu image", offset, tiff->size));
1558 numer = tiff_get32s(tiff, offset);
1559 denom = tiff_get32s(tiff, offset+4);
1565 return (double)numer / denom;
1575 http://www.exif.org/
1579 Tony Cook <tony@imager.perl.org>