diff --git a/ext/exif/data.c b/ext/exif/data.c index 96f5683..8afc2a6 100644 --- a/ext/exif/data.c +++ b/ext/exif/data.c @@ -11,8 +11,8 @@ extern VALUE rb_mExif, rb_eNotReadble, rb_eIFDNotFound; extern const char* exif_entry_to_ivar(ExifEntry* entry); VALUE rb_cData; - -static const char* attrs[] = {"aperture_value", "artist", "battery_level", "bits_per_sample", "brightness_value", "cfa_pattern", "cfa_repeat_pattern_dim", "color_space", "components_configuration", "compressed_bits_per_pixel", "compression", "contrast", "copyright", "custom_rendered", "date_time", "date_time_digitized", "date_time_original", "device_setting_description", "digital_zoom_ratio", "document_name", "exif_ifd_pointer", "exif_version", "exposure_bias_value", "exposure_index", "exposure_mode", "exposure_program", "exposure_time", "file_source", "fill_order", "flash", "flash_energy", "flash_pix_version", "fnumber", "focal_length", "focal_length_in_35mm_film", "focal_plane_resolution_unit", "focal_plane_x_resolution", "focal_plane_y_resolution", "gain_control", "gamma", "gps_altitude", "gps_altitude_ref", "gps_area_information", "gps_date_stamp", "gps_dest_bearing", "gps_dest_bearing_ref", "gps_dest_distance", "gps_dest_distance_ref", "gps_dest_latitude", "gps_dest_latitude_ref", "gps_dest_longitude", "gps_dest_longitude_ref", "gps_differential", "gps_dop", "gps_img_direction", "gps_img_direction_ref", "gps_info_ifd_pointer", "gps_latitude", "gps_latitude_ref", "gps_longitude", "gps_longitude_ref", "gps_map_datum", "gps_measure_mode", "gps_processing_method", "gps_satellites", "gps_speed", "gps_speed_ref", "gps_status", "gps_time_stamp", "gps_track", "gps_track_ref", "gps_version_id", "image_description", "image_length", "image_resources", "image_unique_id", "image_width", "inter_color_profile", "interoperability_ifd_pointer", "interoperability_index", "interoperability_version", "iptc_naa", "iso_speed_ratings", "jpeg_interchange_format", "jpeg_interchange_format_length", "jpeg_proc", "light_source", "make", "maker_note", "max_aperture_value", "metering_mode", "model", "new_cfa_pattern", "new_subfile_type", "oecf", "orientation", "padding", "photometric_interpretation", "pixel_x_dimension", "pixel_y_dimension", "planar_configuration", "primary_chromaticities", "print_image_matching", "reference_black_white", "related_image_file_format", "related_image_length", "related_image_width", "related_sound_file", "resolution_unit", "rows_per_strip", "samples_per_pixel", "saturation", "scene_capture_type", "scene_type", "sensing_method", "sharpness", "shutter_speed_value", "software", "spatial_frequency_response", "spectral_sensitivity", "strip_byte_counts", "strip_offsets", "sub_ifds", "sub_sec_time", "sub_sec_time_digitized", "sub_sec_time_original", "subject_area", "subject_distance", "subject_distance_range", "subject_location", "tiff_ep_standard_id", "time_zone_offset", "transfer_function", "transfer_range", "user_comment", "white_balance", "white_point", "x_resolution", "xml_packet", "xp_author", "xp_comment", "xp_keywords", "xp_subject", "xp_title", "y_resolution", "ycbcr_coefficients", "ycbcr_positioning", "ycbcr_sub_sampling"}; +static const char* ifd_name_mapping[] = {"ifd0", "ifd1", "exif", "gps", "interoperability"}; +static const char* attr_readers[] = {"ifds", "aperture_value", "artist", "battery_level", "bits_per_sample", "brightness_value", "cfa_pattern", "cfa_repeat_pattern_dim", "color_space", "components_configuration", "compressed_bits_per_pixel", "compression", "contrast", "copyright", "custom_rendered", "date_time", "date_time_digitized", "date_time_original", "device_setting_description", "digital_zoom_ratio", "document_name", "exif_ifd_pointer", "exif_version", "exposure_bias_value", "exposure_index", "exposure_mode", "exposure_program", "exposure_time", "file_source", "fill_order", "flash", "flash_energy", "flash_pix_version", "fnumber", "focal_length", "focal_length_in_35mm_film", "focal_plane_resolution_unit", "focal_plane_x_resolution", "focal_plane_y_resolution", "gain_control", "gamma", "gps_altitude", "gps_altitude_ref", "gps_area_information", "gps_date_stamp", "gps_dest_bearing", "gps_dest_bearing_ref", "gps_dest_distance", "gps_dest_distance_ref", "gps_dest_latitude", "gps_dest_latitude_ref", "gps_dest_longitude", "gps_dest_longitude_ref", "gps_differential", "gps_dop", "gps_img_direction", "gps_img_direction_ref", "gps_info_ifd_pointer", "gps_latitude", "gps_latitude_ref", "gps_longitude", "gps_longitude_ref", "gps_map_datum", "gps_measure_mode", "gps_processing_method", "gps_satellites", "gps_speed", "gps_speed_ref", "gps_status", "gps_time_stamp", "gps_track", "gps_track_ref", "gps_version_id", "image_description", "image_length", "image_resources", "image_unique_id", "image_width", "inter_color_profile", "interoperability_ifd_pointer", "interoperability_index", "interoperability_version", "iptc_naa", "iso_speed_ratings", "jpeg_interchange_format", "jpeg_interchange_format_length", "jpeg_proc", "light_source", "make", "maker_note", "max_aperture_value", "metering_mode", "model", "new_cfa_pattern", "new_subfile_type", "oecf", "orientation", "padding", "photometric_interpretation", "pixel_x_dimension", "pixel_y_dimension", "planar_configuration", "primary_chromaticities", "print_image_matching", "reference_black_white", "related_image_file_format", "related_image_length", "related_image_width", "related_sound_file", "resolution_unit", "rows_per_strip", "samples_per_pixel", "saturation", "scene_capture_type", "scene_type", "sensing_method", "sharpness", "shutter_speed_value", "software", "spatial_frequency_response", "spectral_sensitivity", "strip_byte_counts", "strip_offsets", "sub_ifds", "sub_sec_time", "sub_sec_time_digitized", "sub_sec_time_original", "subject_area", "subject_distance", "subject_distance_range", "subject_location", "tiff_ep_standard_id", "time_zone_offset", "transfer_function", "transfer_range", "user_comment", "white_balance", "white_point", "x_resolution", "xml_packet", "xp_author", "xp_comment", "xp_keywords", "xp_subject", "xp_title", "y_resolution", "ycbcr_coefficients", "ycbcr_positioning", "ycbcr_sub_sampling"}; static VALUE new(VALUE self, VALUE input); static VALUE dump(VALUE self); @@ -24,9 +24,8 @@ void init_data(){ int length; rb_cData = rb_define_class_under(rb_mExif, "Data", rb_cObject); - length = sizeof(attrs) / sizeof(char*); - - for(int i = 0; i < length; ++i) rb_define_attr(rb_cData, attrs[i], 1, 0); + length = sizeof(attr_readers) / sizeof(char*); + for(int i = 0; i < length; ++i) rb_define_attr(rb_cData, attr_readers[i], 1, 0); rb_define_singleton_method(rb_cData, "new", new, 1); rb_define_method(rb_cData, "dump", dump, 0); } @@ -52,7 +51,9 @@ VALUE new(VALUE self, VALUE input){ exif_loader_unref (loader); if(!ed) rb_raise(rb_eNotReadble, "File not readable or no EXIF data in file."); + VALUE rb_data = Data_Wrap_Struct(self, NULL, exif_data_free, ed); + rb_iv_set(rb_data, "@ifds", rb_hash_new()); exif_data_foreach_content(ed, each_content, &rb_data); return rb_data; } @@ -70,7 +71,7 @@ static void each_content(ExifContent *ec, void *self_ptr){ ifd = exif_content_get_ifd(ec); if(ifd == EXIF_IFD_COUNT) rb_raise(rb_eIFDNotFound, "Con't get IFD."); - + rb_hash_aset(rb_iv_get(*(VALUE*)self_ptr, "@ifds"), ID2SYM(rb_intern(ifd_name_mapping[ifd])), rb_hash_new()); exif_content_foreach_entry(ec, each_entry, self_ptr); } @@ -80,7 +81,14 @@ static void each_entry(ExifEntry *entry, void *self_ptr){ ivar_name = exif_entry_to_ivar(entry); value = exif_entry_to_rb_value(entry); - + rb_hash_aset( + rb_hash_aref( + rb_iv_get(*(VALUE*)self_ptr, "@ifds"), + ID2SYM(rb_intern(ifd_name_mapping[exif_entry_get_ifd(entry)])) + ), + ID2SYM(rb_intern(ivar_name + 1)), + value + ); rb_iv_set(*(VALUE*)self_ptr, ivar_name, value); } diff --git a/test/test_exif.rb b/test/test_exif.rb index bcce23b..9a4df1a 100644 --- a/test/test_exif.rb +++ b/test/test_exif.rb @@ -5,6 +5,88 @@ class TestExif < Minitest::Test module Shared + def test_ifds + assert_equal({ + image_width: 4000, + image_length: 2670, + bits_per_sample: [8, 8, 8], + photometric_interpretation: 2, + make: 'NIKON CORPORATION', + model: 'NIKON D600', + orientation: 1, + samples_per_pixel: 3, + x_resolution: Rational(300, 1), + y_resolution: Rational(300, 1), + resolution_unit: 2, + software: 'Adobe Photoshop CS6 (Macintosh)', + date_time: '2013:12:08 21:14:11' + }, data.ifds[:ifd0]) + + assert_equal({ + compression: 6, + x_resolution: Rational(72, 1), + y_resolution: Rational(72, 1), + resolution_unit: 2 + }, data.ifds[:ifd1]) + + assert_equal({ + exposure_time: Rational(1, 125), + fnumber: Rational(8, 1), + exposure_program: 3, + iso_speed_ratings: 250, + exif_version: '0230', + date_time_original: '2013:09:10 16:31:21', + date_time_digitized: '2013:09:10 16:31:21', + shutter_speed_value: Rational(870723, 125000), + aperture_value: Rational(6, 1), + exposure_bias_value: Rational(-1, 3), + max_aperture_value: Rational(3, 1), + metering_mode: 2, + light_source: 9, + flash: 16, + focal_length: Rational(70, 1), + sub_sec_time_original: '90', + sub_sec_time_digitized: '90', + color_space: 1, + pixel_x_dimension: 4000, + pixel_y_dimension: 2670, + focal_plane_x_resolution: Rational(54886891, 32768), + focal_plane_y_resolution: Rational(54886891, 32768), + focal_plane_resolution_unit: 3, + sensing_method: 2, + file_source: "\x03", + scene_type: "\x01", + new_cfa_pattern: "\x02\x00\x02\x00\x00\x01\x01\x02", + custom_rendered: 0, + exposure_mode: 0, + white_balance: 1, + digital_zoom_ratio: Rational(1, 1), + focal_length_in_35mm_film: 70, + scene_capture_type: 0, + gain_control: 0, + contrast: 0, + saturation: 0, + sharpness: 0, + subject_distance_range: 0, + flash_pix_version: '0100' + }, data.ifds[:exif]) + + assert_equal({ + gps_version_id: [2, 2, 0, 0], + gps_latitude_ref: 'N', + gps_latitude: [Rational(24, 1), Rational(106817, 10000), Rational(0, 1)], + gps_longitude_ref: 'E', + gps_longitude: [Rational(121, 1), Rational(76869, 2500), Rational(0, 1)], + gps_altitude_ref: 0, + gps_altitude: Rational(332, 1), + gps_time_stamp: [Rational(8, 1), Rational(4, 1), Rational(25, 1)], + gps_map_datum: 'WGS-84', + gps_date_stamp: '2013:09:10' + }, data.ifds[:gps]) + + assert_equal({}, data.ifds[:interoperability]) + end + def test_undefined assert_equal '0230', data.exif_version assert_equal "\x03", data.file_source