11 imexif.c - EXIF support for Imager
15 if (i_int_decode_exif(im, app1data, app1datasize)) {
21 This code provides a basic EXIF data decoder. It is intended to be
22 called from the JPEG reader code when an APP1 data block is found, and
23 will set tags in the supplied image.
28 typedef enum tiff_type_tag {
46 ift_last = 12 /* keep the same as the highest type code */
49 static int type_sizes[] =
87 #define PASTE(left, right) PASTE_(left, right)
88 #define PASTE_(left, right) left##right
89 #define QUOTE(value) #value
91 #define VALUE_MAP_ENTRY(name) \
94 "exif_" QUOTE(name) "_name", \
95 PASTE(name, _values), \
96 ARRAY_COUNT(PASTE(name, _values)) \
99 /* we don't process every tag */
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
112 #define tag_exif_ifd 34665
113 #define tag_gps_ifd 34853
115 #define resunit_none 1
116 #define resunit_inch 2
117 #define resunit_centimeter 3
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
140 #define tag_iso_speed_ratings 0x8827
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
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
210 /* don't use this on pointers */
211 #define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array))
213 /* in memory tiff structure */
215 /* the data we use as a tiff */
219 /* intel or motorola byte order */
222 /* initial ifd offset */
223 unsigned long first_ifd_offset;
225 /* size (in entries) and data */
228 unsigned long next_ifd;
231 static int tiff_init(imtiff *tiff, unsigned char *base, size_t length);
232 static int tiff_load_ifd(imtiff *tiff, unsigned long offset);
233 static void tiff_final(imtiff *tiff);
234 static void tiff_clear_ifd(imtiff *tiff);
235 #if 0 /* currently unused, but that may change */
236 static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset,
239 static int tiff_get_tag_double(imtiff *, int index, double *result);
240 static int tiff_get_tag_int(imtiff *, int index, int *result);
241 static unsigned tiff_get16(imtiff *, unsigned long offset);
242 static unsigned tiff_get32(imtiff *, unsigned long offset);
243 static int tiff_get16s(imtiff *, unsigned long offset);
244 static int tiff_get32s(imtiff *, unsigned long offset);
245 static double tiff_get_rat(imtiff *, unsigned long offset);
246 static double tiff_get_rats(imtiff *, unsigned long offset);
247 static void save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset, unsigned long *gps_ifd_offset);
248 static void save_exif_ifd_tags(i_img *im, imtiff *tiff);
249 static void save_gps_ifd_tags(i_img *im, imtiff *tiff);
251 copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
253 copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
255 copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
257 copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count);
259 copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count);
260 static void process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size);
263 =head1 PUBLIC FUNCTIONS
265 These functions are available to other parts of Imager. They aren't
266 intended to be called from outside of Imager.
270 =item i_int_decode_exit
272 i_int_decode_exif(im, data_base, data_size);
274 The data from data_base for data_size bytes will be scanned for EXIF
277 Any data found will be used to set tags in the supplied image.
279 The intent is that invalid EXIF data will simply fail to set tags, and
280 write to the log. In no case should this code exit when supplied
283 Returns true if an Exif header was seen.
289 i_int_decode_exif(i_img *im, unsigned char *data, size_t length) {
291 unsigned long exif_ifd_offset = 0;
292 unsigned long gps_ifd_offset = 0;
293 /* basic checks - must start with "Exif\0\0" */
295 if (length < 6 || memcmp(data, "Exif\0\0", 6) != 0) {
302 if (!tiff_init(&tiff, data, length)) {
303 mm_log((2, "Exif header found, but no valid TIFF header\n"));
306 if (!tiff_load_ifd(&tiff, tiff.first_ifd_offset)) {
307 mm_log((2, "Exif header found, but could not load IFD 0\n"));
312 save_ifd0_tags(im, &tiff, &exif_ifd_offset, &gps_ifd_offset);
314 if (exif_ifd_offset) {
315 if (tiff_load_ifd(&tiff, exif_ifd_offset)) {
316 save_exif_ifd_tags(im, &tiff);
319 mm_log((2, "Could not load Exif IFD\n"));
323 if (gps_ifd_offset) {
324 if (tiff_load_ifd(&tiff, gps_ifd_offset)) {
325 save_gps_ifd_tags(im, &tiff);
328 mm_log((2, "Could not load GPS IFD\n"));
341 =head1 INTERNAL FUNCTIONS
343 =head2 EXIF Processing
349 save_ifd0_tags(im, tiff, &exif_ifd_offset, &gps_ifd_offset)
351 Scans the currently loaded IFD for tags expected in IFD0 and sets them
354 Sets *exif_ifd_offset to the offset of the EXIF IFD if found.
360 static tag_map ifd0_string_tags[] =
362 { tag_make, "exif_make" },
363 { tag_model, "exif_model" },
364 { tag_copyright, "exif_copyright" },
365 { tag_software, "exif_software" },
366 { tag_artist, "exif_artist" },
367 { tag_date_time, "exif_date_time" },
368 { tag_image_description, "exif_image_description" },
371 static const int ifd0_string_tag_count = ARRAY_COUNT(ifd0_string_tags);
373 static tag_map ifd0_int_tags[] =
375 { tag_orientation, "exif_orientation", },
376 { tag_resolution_unit, "exif_resolution_unit" },
379 static const int ifd0_int_tag_count = ARRAY_COUNT(ifd0_int_tags);
381 static tag_map ifd0_rat_tags[] =
383 { tag_x_resolution, "exif_x_resolution" },
384 { tag_y_resolution, "exif_y_resolution" },
387 static tag_map resolution_unit_values[] =
391 { 3, "centimeters" },
394 static tag_value_map ifd0_values[] =
396 VALUE_MAP_ENTRY(resolution_unit),
400 save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset,
401 unsigned long *gps_ifd_offset) {
406 for (tag_index = 0, entry = tiff->ifd;
407 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
408 switch (entry->tag) {
410 if (tiff_get_tag_int(tiff, tag_index, &work))
411 *exif_ifd_offset = work;
415 if (tiff_get_tag_int(tiff, tag_index, &work))
416 *gps_ifd_offset = work;
421 copy_string_tags(im, tiff, ifd0_string_tags, ifd0_string_tag_count);
422 copy_int_tags(im, tiff, ifd0_int_tags, ifd0_int_tag_count);
423 copy_rat_tags(im, tiff, ifd0_rat_tags, ARRAY_COUNT(ifd0_rat_tags));
424 copy_name_tags(im, tiff, ifd0_values, ARRAY_COUNT(ifd0_values));
425 /* copy_num_array_tags(im, tiff, ifd0_num_arrays, ARRAY_COUNT(ifd0_num_arrays)); */
429 =item save_exif_ifd_tags
431 save_exif_ifd_tags(im, tiff)
433 Scans the currently loaded IFD for the tags expected in the EXIF IFD
434 and sets them as tags in the image.
440 static tag_map exif_ifd_string_tags[] =
442 { tag_exif_version, "exif_version", },
443 { tag_flashpix_version, "exif_flashpix_version", },
444 { tag_related_sound_file, "exif_related_sound_file", },
445 { tag_date_time_original, "exif_date_time_original", },
446 { tag_date_time_digitized, "exif_date_time_digitized", },
447 { tag_sub_sec_time, "exif_sub_sec_time" },
448 { tag_sub_sec_time_original, "exif_sub_sec_time_original" },
449 { tag_sub_sec_time_digitized, "exif_sub_sec_time_digitized" },
450 { tag_image_unique_id, "exif_image_unique_id" },
451 { tag_spectral_sensitivity, "exif_spectral_sensitivity" },
454 static const int exif_ifd_string_tag_count = ARRAY_COUNT(exif_ifd_string_tags);
456 static tag_map exif_ifd_int_tags[] =
458 { tag_color_space, "exif_color_space" },
459 { tag_exposure_program, "exif_exposure_program" },
460 { tag_metering_mode, "exif_metering_mode" },
461 { tag_light_source, "exif_light_source" },
462 { tag_flash, "exif_flash" },
463 { tag_focal_plane_resolution_unit, "exif_focal_plane_resolution_unit" },
464 { tag_subject_location, "exif_subject_location" },
465 { tag_sensing_method, "exif_sensing_method" },
466 { tag_custom_rendered, "exif_custom_rendered" },
467 { tag_exposure_mode, "exif_exposure_mode" },
468 { tag_white_balance, "exif_white_balance" },
469 { tag_focal_length_in_35mm_film, "exif_focal_length_in_35mm_film" },
470 { tag_scene_capture_type, "exif_scene_capture_type" },
471 { tag_contrast, "exif_contrast" },
472 { tag_saturation, "exif_saturation" },
473 { tag_sharpness, "exif_sharpness" },
474 { tag_subject_distance_range, "exif_subject_distance_range" },
478 static const int exif_ifd_int_tag_count = ARRAY_COUNT(exif_ifd_int_tags);
480 static tag_map exif_ifd_rat_tags[] =
482 { tag_exposure_time, "exif_exposure_time" },
483 { tag_f_number, "exif_f_number" },
484 { tag_shutter_speed, "exif_shutter_speed" },
485 { tag_aperture, "exif_aperture" },
486 { tag_brightness, "exif_brightness" },
487 { tag_exposure_bias, "exif_exposure_bias" },
488 { tag_max_aperture, "exif_max_aperture" },
489 { tag_subject_distance, "exif_subject_distance" },
490 { tag_focal_length, "exif_focal_length" },
491 { tag_flash_energy, "exif_flash_energy" },
492 { tag_focal_plane_x_resolution, "exif_focal_plane_x_resolution" },
493 { tag_focal_plane_y_resolution, "exif_focal_plane_y_resolution" },
494 { tag_exposure_index, "exif_exposure_index" },
495 { tag_digital_zoom_ratio, "exif_digital_zoom_ratio" },
496 { tag_gain_control, "exif_gain_control" },
499 static const int exif_ifd_rat_tag_count = ARRAY_COUNT(exif_ifd_rat_tags);
501 static tag_map exposure_mode_values[] =
503 { 0, "Auto exposure" },
504 { 1, "Manual exposure" },
505 { 2, "Auto bracket" },
507 static tag_map color_space_values[] =
510 { 0xFFFF, "Uncalibrated" },
513 static tag_map exposure_program_values[] =
515 { 0, "Not defined" },
517 { 2, "Normal program" },
518 { 3, "Aperture priority" },
519 { 4, "Shutter priority" },
520 { 5, "Creative program" },
521 { 6, "Action program" },
522 { 7, "Portrait mode" },
523 { 8, "Landscape mode" },
526 static tag_map metering_mode_values[] =
530 { 2, "CenterWeightedAverage" },
538 static tag_map light_source_values[] =
542 { 2, "Fluorescent" },
543 { 3, "Tungsten (incandescent light)" },
545 { 9, "Fine weather" },
546 { 10, "Cloudy weather" },
548 { 12, "Daylight fluorescent (D 5700 Ã 7100K)" },
549 { 13, "Day white fluorescent (N 4600 Ã 5400K)" },
550 { 14, "Cool white fluorescent (W 3900 Ã 4500K)" },
551 { 15, "White fluorescent (WW 3200 Ã 3700K)" },
552 { 17, "Standard light A" },
553 { 18, "Standard light B" },
554 { 19, "Standard light C" },
559 { 24, "ISO studio tungsten" },
560 { 255, "other light source" },
563 static tag_map flash_values[] =
565 { 0x0000, "Flash did not fire." },
566 { 0x0001, "Flash fired." },
567 { 0x0005, "Strobe return light not detected." },
568 { 0x0007, "Strobe return light detected." },
569 { 0x0009, "Flash fired, compulsory flash mode" },
570 { 0x000D, "Flash fired, compulsory flash mode, return light not detected" },
571 { 0x000F, "Flash fired, compulsory flash mode, return light detected" },
572 { 0x0010, "Flash did not fire, compulsory flash mode" },
573 { 0x0018, "Flash did not fire, auto mode" },
574 { 0x0019, "Flash fired, auto mode" },
575 { 0x001D, "Flash fired, auto mode, return light not detected" },
576 { 0x001F, "Flash fired, auto mode, return light detected" },
577 { 0x0020, "No flash function" },
578 { 0x0041, "Flash fired, red-eye reduction mode" },
579 { 0x0045, "Flash fired, red-eye reduction mode, return light not detected" },
580 { 0x0047, "Flash fired, red-eye reduction mode, return light detected" },
581 { 0x0049, "Flash fired, compulsory flash mode, red-eye reduction mode" },
582 { 0x004D, "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected" },
583 { 0x004F, "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected" },
584 { 0x0059, "Flash fired, auto mode, red-eye reduction mode" },
585 { 0x005D, "Flash fired, auto mode, return light not detected, red-eye reduction mode" },
586 { 0x005F, "Flash fired, auto mode, return light detected, red-eye reduction mode" },
589 static tag_map sensing_method_values[] =
591 { 1, "Not defined" },
592 { 2, "One-chip color area sensor" },
593 { 3, "Two-chip color area sensor" },
594 { 4, "Three-chip color area sensor" },
595 { 5, "Color sequential area sensor" },
596 { 7, "Trilinear sensor" },
597 { 8, "Color sequential linear sensor" },
600 static tag_map custom_rendered_values[] =
602 { 0, "Normal process" },
603 { 1, "Custom process" },
606 static tag_map white_balance_values[] =
608 { 0, "Auto white balance" },
609 { 1, "Manual white balance" },
612 static tag_map scene_capture_type_values[] =
617 { 3, "Night scene" },
620 static tag_map gain_control_values[] =
623 { 1, "Low gain up" },
624 { 2, "High gain up" },
625 { 3, "Low gain down" },
626 { 4, "High gain down" },
629 static tag_map contrast_values[] =
636 static tag_map saturation_values[] =
639 { 1, "Low saturation" },
640 { 2, "High saturation" },
643 static tag_map sharpness_values[] =
650 static tag_map subject_distance_range_values[] =
655 { 3, "Distant view" },
658 #define focal_plane_resolution_unit_values resolution_unit_values
660 static tag_value_map exif_ifd_values[] =
662 VALUE_MAP_ENTRY(exposure_mode),
663 VALUE_MAP_ENTRY(color_space),
664 VALUE_MAP_ENTRY(exposure_program),
665 VALUE_MAP_ENTRY(metering_mode),
666 VALUE_MAP_ENTRY(light_source),
667 VALUE_MAP_ENTRY(flash),
668 VALUE_MAP_ENTRY(sensing_method),
669 VALUE_MAP_ENTRY(custom_rendered),
670 VALUE_MAP_ENTRY(white_balance),
671 VALUE_MAP_ENTRY(scene_capture_type),
672 VALUE_MAP_ENTRY(gain_control),
673 VALUE_MAP_ENTRY(contrast),
674 VALUE_MAP_ENTRY(saturation),
675 VALUE_MAP_ENTRY(sharpness),
676 VALUE_MAP_ENTRY(subject_distance_range),
677 VALUE_MAP_ENTRY(focal_plane_resolution_unit),
680 static tag_map exif_num_arrays[] =
682 { tag_iso_speed_ratings, "exif_iso_speed_ratings" },
683 { tag_subject_area, "exif_subject_area" },
684 { tag_subject_location, "exif_subject_location" },
688 save_exif_ifd_tags(i_img *im, imtiff *tiff) {
692 unsigned long maker_note_offset = 0;
693 size_t maker_note_size = 0;
695 for (tag_index = 0, entry = tiff->ifd;
696 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
697 switch (entry->tag) {
698 case tag_user_comment:
699 /* I don't want to trash the source, so work on a copy */
700 user_comment = mymalloc(entry->size);
701 memcpy(user_comment, tiff->base + entry->offset, entry->size);
702 /* the first 8 bytes indicate the encoding, make them into spaces
703 for better presentation */
704 for (i = 0; i < entry->size && i < 8; ++i) {
705 if (user_comment[i] == '\0')
706 user_comment[i] = ' ';
708 /* find the actual end of the string */
709 while (i < entry->size && user_comment[i])
711 i_tags_set(&im->tags, "exif_user_comment", user_comment, i);
712 myfree(user_comment);
716 maker_note_offset = entry->offset;
717 maker_note_size = entry->size;
720 /* the following aren't processed yet */
722 case tag_spatial_frequency_response:
723 case tag_file_source:
725 case tag_cfa_pattern:
726 case tag_device_setting_description:
727 case tag_subject_area:
732 copy_string_tags(im, tiff, exif_ifd_string_tags, exif_ifd_string_tag_count);
733 copy_int_tags(im, tiff, exif_ifd_int_tags, exif_ifd_int_tag_count);
734 copy_rat_tags(im, tiff, exif_ifd_rat_tags, exif_ifd_rat_tag_count);
735 copy_name_tags(im, tiff, exif_ifd_values, ARRAY_COUNT(exif_ifd_values));
736 copy_num_array_tags(im, tiff, exif_num_arrays, ARRAY_COUNT(exif_num_arrays));
738 /* This trashes the IFD - make sure it's done last */
739 if (maker_note_offset) {
740 process_maker_note(im, tiff, maker_note_offset, maker_note_size);
744 static tag_map gps_ifd_string_tags[] =
746 { tag_gps_version_id, "exif_gps_version_id" },
747 { tag_gps_latitude_ref, "exif_gps_latitude_ref" },
748 { tag_gps_longitude_ref, "exif_gps_longitude_ref" },
749 { tag_gps_altitude_ref, "exif_gps_altitude_ref" },
750 { tag_gps_satellites, "exif_gps_satellites" },
751 { tag_gps_status, "exif_gps_status" },
752 { tag_gps_measure_mode, "exif_gps_measure_mode" },
753 { tag_gps_speed_ref, "exif_gps_speed_ref" },
754 { tag_gps_track_ref, "exif_gps_track_ref" },
757 static tag_map gps_ifd_int_tags[] =
759 { tag_gps_differential, "exif_gps_differential" },
762 static tag_map gps_ifd_rat_tags[] =
764 { tag_gps_altitude, "exif_gps_altitude" },
765 { tag_gps_time_stamp, "exif_gps_time_stamp" },
766 { tag_gps_dop, "exif_gps_dop" },
767 { tag_gps_speed, "exif_gps_speed" },
768 { tag_gps_track, "exif_track" }
771 static tag_map gps_differential_values [] =
773 { 0, "without differential correction" },
774 { 1, "Differential correction applied" },
777 static tag_value_map gps_ifd_values[] =
779 VALUE_MAP_ENTRY(gps_differential),
782 static tag_map gps_num_arrays[] =
784 { tag_gps_latitude, "exif_gps_latitude" },
785 { tag_gps_longitude, "exif_gps_longitude" },
789 save_gps_ifd_tags(i_img *im, imtiff *tiff) {
794 /* for (tag_index = 0, entry = tiff->ifd;
795 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
796 switch (entry->tag) {
801 copy_string_tags(im, tiff, gps_ifd_string_tags,
802 ARRAY_COUNT(gps_ifd_string_tags));
803 copy_int_tags(im, tiff, gps_ifd_int_tags, ARRAY_COUNT(gps_ifd_int_tags));
804 copy_rat_tags(im, tiff, gps_ifd_rat_tags, ARRAY_COUNT(gps_ifd_rat_tags));
805 copy_name_tags(im, tiff, gps_ifd_values, ARRAY_COUNT(gps_ifd_values));
806 copy_num_array_tags(im, tiff, gps_num_arrays, ARRAY_COUNT(gps_num_arrays));
810 =item process_maker_note
812 This is a stub for processing the maker note tag.
814 Maker notes aren't covered by EXIF itself and in general aren't
815 documented by the manufacturers.
821 process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size) {
822 /* this will be added in a future release */
828 =head2 High level TIFF functions
830 To avoid relying upon tifflib when we're not processing an image we
831 have some simple in-memory TIFF file management.
838 if (tiff_init(tiff, data_base, data_size)) {
842 Initialize the tiff data structure.
844 Scans for the byte order and version markers, and stores the offset to
845 the first IFD (IFD0 in EXIF) in first_ifd_offset.
851 tiff_init(imtiff *tiff, unsigned char *data, size_t length) {
856 if (length < 8) /* well... would have to be much bigger to be useful */
858 if (data[0] == 'M' && data[1] == 'M')
859 tiff->type = tt_motorola;
860 else if (data[0] == 'I' && data[1] == 'I')
861 tiff->type = tt_intel;
863 return 0; /* invalid header */
865 version = tiff_get16(tiff, 2);
869 tiff->first_ifd_offset = tiff_get32(tiff, 4);
870 if (tiff->first_ifd_offset > length || tiff->first_ifd_offset < 8)
885 Clean up the tiff structure initialized by tiff_init()
891 tiff_final(imtiff *tiff) {
892 tiff_clear_ifd(tiff);
898 if (tiff_load_ifd(tiff, offset)) {
902 Loads the IFD from the given offset into the tiff objects ifd.
904 This can fail if the IFD extends beyond end of file, or if any data
905 offsets combined with their sizes, extends beyond end of file.
907 Returns true on success.
913 tiff_load_ifd(imtiff *tiff, unsigned long offset) {
916 ifd_entry *entries = NULL;
920 tiff_clear_ifd(tiff);
922 /* rough check count + 1 entry + next offset */
923 if (offset + (2+12+4) > tiff->size) {
924 mm_log((2, "offset %lu beyond end off Exif block", offset));
928 count = tiff_get16(tiff, offset);
930 /* check we can fit the whole thing */
931 ifd_size = 2 + count * 12 + 4; /* count + count entries + next offset */
932 if (offset + ifd_size > tiff->size) {
933 mm_log((2, "offset %lu beyond end off Exif block", offset));
937 entries = mymalloc(count * sizeof(ifd_entry));
938 memset(entries, 0, count * sizeof(ifd_entry));
940 for (i = 0; i < count; ++i) {
941 ifd_entry *entry = entries + i;
942 entry->tag = tiff_get16(tiff, base);
943 entry->type = tiff_get16(tiff, base+2);
944 entry->count = tiff_get32(tiff, base+4);
945 if (entry->type >= 1 && entry->type <= ift_last) {
946 entry->item_size = type_sizes[entry->type];
947 entry->size = entry->item_size * entry->count;
948 if (entry->size / entry->item_size != entry->count) {
950 mm_log((1, "Integer overflow calculating tag data size processing EXIF block\n"));
953 else if (entry->size <= 4) {
954 entry->offset = base + 8;
957 entry->offset = tiff_get32(tiff, base+8);
958 if (entry->offset + entry->size > tiff->size) {
959 mm_log((2, "Invalid data offset processing IFD\n"));
972 tiff->ifd_size = count;
974 tiff->next_ifd = tiff_get32(tiff, base);
984 Releases any memory associated with the stored IFD and resets the IFD
987 This is called by tiff_load_ifd() and tiff_final().
993 tiff_clear_ifd(imtiff *tiff) {
994 if (tiff->ifd_size && tiff->ifd) {
1002 =item tiff_get_tag_double
1005 if (tiff_get_tag(tiff, index, &value)) {
1009 Attempts to retrieve a double value from the given index in the
1012 The value must have a count of 1.
1018 tiff_get_tag_double_array(imtiff *tiff, int index, double *result,
1021 unsigned long offset;
1022 if (index < 0 || index >= tiff->ifd_size) {
1023 mm_log((3, "tiff_get_tag_double_array() tag index out of range"));
1027 entry = tiff->ifd + index;
1028 if (array_index < 0 || array_index >= entry->count) {
1029 mm_log((3, "tiff_get_tag_double_array() array index out of range"));
1033 offset = entry->offset + array_index * entry->item_size;
1035 switch (entry->type) {
1037 *result = tiff_get16(tiff, offset);
1041 *result = tiff_get32(tiff, offset);
1045 *result = tiff_get_rat(tiff, offset);
1049 *result = tiff_get16s(tiff, offset);
1053 *result = tiff_get32s(tiff, offset);
1057 *result = tiff_get_rats(tiff, offset);
1061 *result = *(tiff->base + offset);
1069 =item tiff_get_tag_double
1072 if (tiff_get_tag(tiff, index, &value)) {
1076 Attempts to retrieve a double value from the given index in the
1079 The value must have a count of 1.
1085 tiff_get_tag_double(imtiff *tiff, int index, double *result) {
1087 if (index < 0 || index >= tiff->ifd_size) {
1088 mm_log((3, "tiff_get_tag_double() index out of range"));
1092 entry = tiff->ifd + index;
1093 if (entry->count != 1) {
1094 mm_log((3, "tiff_get_tag_double() called on tag with multiple values"));
1098 return tiff_get_tag_double_array(tiff, index, result, 0);
1102 =item tiff_get_tag_int_array
1105 if (tiff_get_tag_int_array(tiff, index, &value, array_index)) {
1109 Attempts to retrieve an integer value from the given index in the
1116 tiff_get_tag_int_array(imtiff *tiff, int index, int *result, int array_index) {
1118 unsigned long offset;
1119 if (index < 0 || index >= tiff->ifd_size) {
1120 mm_log((3, "tiff_get_tag_int_array() tag index out of range"));
1124 entry = tiff->ifd + index;
1125 if (array_index < 0 || array_index >= entry->count) {
1126 mm_log((3, "tiff_get_tag_int_array() array index out of range"));
1130 offset = entry->offset + array_index * entry->item_size;
1132 switch (entry->type) {
1134 *result = tiff_get16(tiff, offset);
1138 *result = tiff_get32(tiff, offset);
1142 *result = tiff_get16s(tiff, offset);
1146 *result = tiff_get32s(tiff, offset);
1150 *result = *(tiff->base + offset);
1158 =item tiff_get_tag_int
1161 if (tiff_get_tag_int(tiff, index, &value)) {
1165 Attempts to retrieve an integer value from the given index in the
1168 The value must have a count of 1.
1174 tiff_get_tag_int(imtiff *tiff, int index, int *result) {
1176 if (index < 0 || index >= tiff->ifd_size) {
1177 mm_log((3, "tiff_get_tag_int() index out of range"));
1181 entry = tiff->ifd + index;
1182 if (entry->count != 1) {
1183 mm_log((3, "tiff_get_tag_int() called on tag with multiple values"));
1187 return tiff_get_tag_int_array(tiff, index, result, 0);
1193 =head2 Table-based tag setters
1195 This set of functions checks for matches between the current IFD and
1196 tags supplied in an array, when there's a match it sets the
1197 appropriate tag in the image.
1203 Scans the IFD for integer tags and sets them in the image,
1209 copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1213 for (tag_index = 0, entry = tiff->ifd;
1214 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1215 for (i = 0; i < map_count; ++i) {
1217 if (map[i].tag == entry->tag
1218 && tiff_get_tag_int(tiff, tag_index, &value)) {
1219 i_tags_setn(&im->tags, map[i].name, value);
1229 Scans the IFD for rational tags and sets them in the image.
1235 copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1239 for (tag_index = 0, entry = tiff->ifd;
1240 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1241 for (i = 0; i < map_count; ++i) {
1243 if (map[i].tag == entry->tag
1244 && tiff_get_tag_double(tiff, tag_index, &value)) {
1245 i_tags_set_float2(&im->tags, map[i].name, 0, value, 6);
1253 =item copy_string_tags
1255 Scans the IFD for string tags and sets them in the image.
1261 copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1265 for (tag_index = 0, entry = tiff->ifd;
1266 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1267 for (i = 0; i < map_count; ++i) {
1268 if (map[i].tag == entry->tag) {
1269 int len = entry->type == ift_ascii ? entry->size - 1 : entry->size;
1270 i_tags_set(&im->tags, map[i].name,
1271 (char const *)(tiff->base + entry->offset), len);
1279 =item copy_num_array_tags
1281 Scans the IFD for arrays of numbers and sets them in the image.
1286 /* a more general solution would be better in some ways, but we don't need it */
1287 #define MAX_ARRAY_VALUES 10
1288 #define MAX_ARRAY_STRING (MAX_ARRAY_VALUES * 20)
1291 copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) {
1292 int i, j, tag_index;
1295 for (tag_index = 0, entry = tiff->ifd;
1296 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1297 for (i = 0; i < map_count; ++i) {
1298 if (map[i].tag == entry->tag && entry->count <= MAX_ARRAY_VALUES) {
1299 if (entry->type == ift_rational || entry->type == ift_srational) {
1301 char workstr[MAX_ARRAY_STRING];
1302 size_t len = 0, item_len;
1304 for (j = 0; j < entry->count; ++j) {
1305 if (!tiff_get_tag_double_array(tiff, tag_index, &value, j)) {
1306 mm_log((3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j));
1309 if (len >= sizeof(workstr) - 1) {
1310 mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag));
1314 strcat(workstr, " ");
1317 #ifdef IMAGER_SNPRINTF
1318 item_len = snprintf(workstr + len, sizeof(workstr)-len, "%.6g", value);
1320 item_len = sprintf(workstr + len, "%.6g", value);
1324 i_tags_set(&im->tags, map[i].name, workstr, -1);
1326 else if (entry->type == ift_short || entry->type == ift_long
1327 || entry->type == ift_sshort || entry->type == ift_slong
1328 || entry->type == ift_byte) {
1330 char workstr[MAX_ARRAY_STRING];
1331 size_t len = 0, item_len;
1333 for (j = 0; j < entry->count; ++j) {
1334 if (!tiff_get_tag_int_array(tiff, tag_index, &value, j)) {
1335 mm_log((3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j));
1338 if (len >= sizeof(workstr) - 1) {
1339 mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag));
1343 strcat(workstr, " ");
1346 #ifdef IMAGER_SNPRINTF
1347 item_len = snprintf(workstr + len, sizeof(workstr) - len, "%d", value);
1349 item_len = sprintf(workstr + len, "%d", value);
1353 i_tags_set(&im->tags, map[i].name, workstr, -1);
1362 =item copy_name_tags
1364 This function maps integer values to descriptions for those values.
1366 In general we handle the integer value through copy_int_tags() and
1367 then the same tage with a "_name" suffix here.
1373 copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count) {
1374 int i, j, tag_index;
1377 for (tag_index = 0, entry = tiff->ifd;
1378 tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1379 for (i = 0; i < map_count; ++i) {
1381 if (map[i].tag == entry->tag
1382 && tiff_get_tag_int(tiff, tag_index, &value)) {
1383 tag_map const *found = NULL;
1384 for (j = 0; j < map[i].map_count; ++j) {
1385 if (value == map[i].map[j].tag) {
1386 found = map[i].map + j;
1391 i_tags_set(&im->tags, map[i].name, found->name, -1);
1403 =head2 Low level data access functions
1405 These functions use the byte order in the tiff object to extract
1406 various types of data from the tiff data.
1408 These functions will abort if called with an out of range offset.
1410 The intent is that any offset checks should have been done by the caller.
1416 Retrieve a 16 bit unsigned integer from offset.
1422 tiff_get16(imtiff *tiff, unsigned long offset) {
1423 if (offset + 2 > tiff->size) {
1424 mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1425 (unsigned long)tiff->size));
1429 if (tiff->type == tt_intel)
1430 return tiff->base[offset] + 0x100 * tiff->base[offset+1];
1432 return tiff->base[offset+1] + 0x100 * tiff->base[offset];
1438 Retrieve a 32-bit unsigned integer from offset.
1444 tiff_get32(imtiff *tiff, unsigned long offset) {
1445 if (offset + 4 > tiff->size) {
1446 mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1447 (unsigned long)tiff->size));
1451 if (tiff->type == tt_intel)
1452 return tiff->base[offset] + 0x100 * tiff->base[offset+1]
1453 + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1455 return tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1456 + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1459 #if 0 /* currently unused, but that may change */
1462 =item tiff_get_bytes
1464 Retrieve a byte string from offset.
1466 This isn't used much, you can usually deal with the data in-situ.
1467 This is intended for use when you need to modify the data in some way.
1473 tiff_get_bytes(imtiff *tiff, unsigned char *data, size_t offset,
1475 if (offset + size > tiff->size)
1478 memcpy(data, tiff->base+offset, size);
1488 Retrieve a 16-bit signed integer from offset.
1494 tiff_get16s(imtiff *tiff, unsigned long offset) {
1497 if (offset + 2 > tiff->size) {
1498 mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1499 (unsigned long)tiff->size));
1503 if (tiff->type == tt_intel)
1504 result = tiff->base[offset] + 0x100 * tiff->base[offset+1];
1506 result = tiff->base[offset+1] + 0x100 * tiff->base[offset];
1508 if (result > 0x7FFF)
1517 Retrieve a 32-bit signed integer from offset.
1523 tiff_get32s(imtiff *tiff, unsigned long offset) {
1526 if (offset + 4 > tiff->size) {
1527 mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1528 (unsigned long)tiff->size));
1532 if (tiff->type == tt_intel)
1533 work = tiff->base[offset] + 0x100 * tiff->base[offset+1]
1534 + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1536 work = tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1537 + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1539 /* not really needed on 32-bit int machines */
1540 if (work > 0x7FFFFFFFUL)
1541 return work - 0x80000000UL;
1549 Retrieve an unsigned rational from offset.
1555 tiff_get_rat(imtiff *tiff, unsigned long offset) {
1556 unsigned long numer, denom;
1557 if (offset + 8 > tiff->size) {
1558 mm_log((3, "attempt to get_rat at %lu in %lu image", offset,
1559 (unsigned long)tiff->size));
1563 numer = tiff_get32(tiff, offset);
1564 denom = tiff_get32(tiff, offset+4);
1570 return (double)numer / denom;
1576 Retrieve an signed rational from offset.
1582 tiff_get_rats(imtiff *tiff, unsigned long offset) {
1584 if (offset + 8 > tiff->size) {
1585 mm_log((3, "attempt to get_rat at %lu in %lu image", offset,
1586 (unsigned long)tiff->size));
1590 numer = tiff_get32s(tiff, offset);
1591 denom = tiff_get32s(tiff, offset+4);
1597 return (double)numer / denom;
1607 http://www.exif.org/
1611 Tony Cook <tonyc@cpan.org>