exif 1.0.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 62ee375b5a2f547b733036b6d45e9f07f9157a7f
4
- data.tar.gz: 1777637e0b478a47d4008a0953addbbc1b24f73b
2
+ SHA256:
3
+ metadata.gz: 2c6e39047ca990d8de0501f004d20125f203f3dc709b8c82e63c41af05689169
4
+ data.tar.gz: 2f6328707424b868243624554e3909ac7957a1a1dd6fffdedef4dd98d3a20c77
5
5
  SHA512:
6
- metadata.gz: 47983ae0fb7a3ad48c5b01d973da975c0d74bd1e50abb1db4ff310a4296b29c9ee435286c80a5280f45f804524f82e2f118bce0e8b0219f5674913206e09741d
7
- data.tar.gz: f026ead2e3e8c67a13cec1093bba58c7c162d7c67e347c967362ee8c19fe992eba2a077ea91ccd3130004451a1b97d72742a05bc3dcc8a73861a762d91aec272
6
+ metadata.gz: 5f063d81c93f73a012450e09315aab85afe7c7ac2257d017fa91144f10fc7ea783e6bb3a74470f441b8a373841ac436e2a41ac7340c3bbc989f39f75b311cce0
7
+ data.tar.gz: 9632cc061012ed9234ce2f1193d72b71119d40b8a970f8e63004f1f0976de751de4bbf2d68c3752f5ba04eef27322c1a3bbe4de9809b2e8a0befbfbfa9d8a537
data/ext/exif/data.c CHANGED
@@ -1,591 +1,374 @@
1
+ #include "data.h"
2
+ #include "ruby.h"
3
+
1
4
  #include <libexif/exif-data.h>
5
+ #include <libexif/exif-loader.h>
6
+ #include <libexif/exif-log.h>
7
+ #include <stdint.h>
2
8
  #include <time.h>
3
- #include "data.h"
4
9
 
5
- extern VALUE rb_mExif;
6
- VALUE rb_cData;
7
- static VALUE IFD2SYM[5];
10
+ extern VALUE rb_mExif, rb_eNotReadable, rb_eIFDNotFound;
11
+ extern const char *exif_entry_to_ivar(ExifEntry *entry);
12
+
13
+ VALUE rb_cExifData;
14
+ static const char *ifd_name_mapping[] = {"ifd0", "ifd1", "exif", "gps",
15
+ "interoperability"};
16
+ static const char *attr_readers[] = {"ifds",
17
+ "aperture_value",
18
+ "artist",
19
+ "battery_level",
20
+ "bits_per_sample",
21
+ "brightness_value",
22
+ "cfa_pattern",
23
+ "cfa_repeat_pattern_dim",
24
+ "color_space",
25
+ "components_configuration",
26
+ "compressed_bits_per_pixel",
27
+ "compression",
28
+ "contrast",
29
+ "copyright",
30
+ "custom_rendered",
31
+ "date_time",
32
+ "date_time_digitized",
33
+ "date_time_original",
34
+ "device_setting_description",
35
+ "digital_zoom_ratio",
36
+ "document_name",
37
+ "exif_ifd_pointer",
38
+ "exif_version",
39
+ "exposure_bias_value",
40
+ "exposure_index",
41
+ "exposure_mode",
42
+ "exposure_program",
43
+ "exposure_time",
44
+ "file_source",
45
+ "fill_order",
46
+ "flash",
47
+ "flash_energy",
48
+ "flash_pix_version",
49
+ "fnumber",
50
+ "focal_length",
51
+ "focal_length_in_35mm_film",
52
+ "focal_plane_resolution_unit",
53
+ "focal_plane_x_resolution",
54
+ "focal_plane_y_resolution",
55
+ "gain_control",
56
+ "gamma",
57
+ "gps_altitude",
58
+ "gps_altitude_ref",
59
+ "gps_area_information",
60
+ "gps_date_stamp",
61
+ "gps_dest_bearing",
62
+ "gps_dest_bearing_ref",
63
+ "gps_dest_distance",
64
+ "gps_dest_distance_ref",
65
+ "gps_dest_latitude",
66
+ "gps_dest_latitude_ref",
67
+ "gps_dest_longitude",
68
+ "gps_dest_longitude_ref",
69
+ "gps_differential",
70
+ "gps_dop",
71
+ "gps_img_direction",
72
+ "gps_img_direction_ref",
73
+ "gps_info_ifd_pointer",
74
+ "gps_latitude",
75
+ "gps_latitude_ref",
76
+ "gps_longitude",
77
+ "gps_longitude_ref",
78
+ "gps_map_datum",
79
+ "gps_measure_mode",
80
+ "gps_processing_method",
81
+ "gps_satellites",
82
+ "gps_speed",
83
+ "gps_speed_ref",
84
+ "gps_status",
85
+ "gps_time_stamp",
86
+ "gps_track",
87
+ "gps_track_ref",
88
+ "gps_version_id",
89
+ "image_description",
90
+ "image_length",
91
+ "image_resources",
92
+ "image_unique_id",
93
+ "image_width",
94
+ "inter_color_profile",
95
+ "interoperability_ifd_pointer",
96
+ "interoperability_index",
97
+ "interoperability_version",
98
+ "iptc_naa",
99
+ "iso_speed_ratings",
100
+ "jpeg_interchange_format",
101
+ "jpeg_interchange_format_length",
102
+ "jpeg_proc",
103
+ "light_source",
104
+ "make",
105
+ "maker_note",
106
+ "max_aperture_value",
107
+ "metering_mode",
108
+ "model",
109
+ "new_cfa_pattern",
110
+ "new_subfile_type",
111
+ "oecf",
112
+ "orientation",
113
+ "padding",
114
+ "photometric_interpretation",
115
+ "pixel_x_dimension",
116
+ "pixel_y_dimension",
117
+ "planar_configuration",
118
+ "primary_chromaticities",
119
+ "print_image_matching",
120
+ "reference_black_white",
121
+ "related_image_file_format",
122
+ "related_image_length",
123
+ "related_image_width",
124
+ "related_sound_file",
125
+ "resolution_unit",
126
+ "rows_per_strip",
127
+ "samples_per_pixel",
128
+ "saturation",
129
+ "scene_capture_type",
130
+ "scene_type",
131
+ "sensing_method",
132
+ "sharpness",
133
+ "shutter_speed_value",
134
+ "software",
135
+ "spatial_frequency_response",
136
+ "spectral_sensitivity",
137
+ "strip_byte_counts",
138
+ "strip_offsets",
139
+ "sub_ifds",
140
+ "sub_sec_time",
141
+ "sub_sec_time_digitized",
142
+ "sub_sec_time_original",
143
+ "subject_area",
144
+ "subject_distance",
145
+ "subject_distance_range",
146
+ "subject_location",
147
+ "tiff_ep_standard_id",
148
+ "time_zone_offset",
149
+ "transfer_function",
150
+ "transfer_range",
151
+ "user_comment",
152
+ "white_balance",
153
+ "white_point",
154
+ "x_resolution",
155
+ "xml_packet",
156
+ "xp_author",
157
+ "xp_comment",
158
+ "xp_keywords",
159
+ "xp_subject",
160
+ "xp_title",
161
+ "y_resolution",
162
+ "ycbcr_coefficients",
163
+ "ycbcr_positioning",
164
+ "ycbcr_sub_sampling"};
165
+
166
+ static VALUE new (VALUE self, VALUE input);
167
+ static VALUE dump(VALUE self);
168
+ static VALUE brackets(VALUE self, VALUE ifd_symbol);
169
+ static void each_content(ExifContent *ec, void *user_data);
170
+ static void each_entry(ExifEntry *, void *user_data);
171
+ static VALUE exif_entry_to_rb_value(ExifEntry *);
172
+ static VALUE rational_to_num(ExifRational rational);
173
+ static VALUE srational_to_num(ExifSRational srational);
174
+
175
+ static void exif_corrupt_log_func(ExifLog *log, ExifLogCode code,
176
+ const char *domain, const char *format,
177
+ va_list args, void *data) {
178
+ if (code == EXIF_LOG_CODE_CORRUPT_DATA) {
179
+ unsigned int *corrupt = (unsigned int *)data;
180
+ *corrupt = 1;
181
+ }
182
+ }
183
+
184
+ void init_data() {
185
+ int length;
8
186
 
9
- void init_data(){
10
- rb_cData = rb_define_class_under(rb_mExif, "Data", rb_cObject);
11
- IFD2SYM[EXIF_IFD_0] = INT2NUM(0);
12
- IFD2SYM[EXIF_IFD_1] = INT2NUM(1);
13
- IFD2SYM[EXIF_IFD_EXIF] = ID2SYM(rb_intern("exif"));
14
- IFD2SYM[EXIF_IFD_GPS] = ID2SYM(rb_intern("gps"));
15
- IFD2SYM[EXIF_IFD_INTEROPERABILITY] = ID2SYM(rb_intern("interoperability"));
16
- int length = sizeof(attrs) / sizeof(char*);
17
- for(int i = 0; i < length; ++i) rb_define_attr(rb_cData, attrs[i], 1, 0);
18
- rb_define_attr(rb_cData, "contents", 1, 0);
19
- rb_define_alias(rb_cData, "to_h", "contents");
20
- rb_define_singleton_method(rb_cData, "new", rb_new, 1);
21
- rb_define_method(rb_cData, "dump", rb_dump, 0);
22
- rb_define_method(rb_cData, "[]", rb_value, 1);
187
+ rb_cExifData = rb_define_class_under(rb_mExif, "Data", rb_cObject);
188
+ length = sizeof(attr_readers) / sizeof(char *);
189
+ for (int i = 0; i < length; ++i)
190
+ rb_define_attr(rb_cExifData, attr_readers[i], 1, 0);
191
+ rb_define_alias(rb_cExifData, "to_h", "ifds");
192
+ rb_define_singleton_method(rb_cExifData, "new", new, 1);
193
+ rb_define_method(rb_cExifData, "dump", dump, 0);
194
+ rb_define_method(rb_cExifData, "[]", brackets, 1);
23
195
  }
24
196
 
25
- VALUE rb_new(VALUE self, VALUE file_path){
26
- Check_Type(file_path, T_STRING);
27
- ExifData *ed = exif_data_new_from_file(StringValueCStr(file_path));
28
- if(!ed) rb_raise(rb_eRuntimeError, "File not readable or no EXIF data in file.");
197
+ VALUE new (VALUE self, VALUE input) {
198
+ ExifData *ed;
199
+
200
+ if (TYPE(input) != T_STRING && !rb_respond_to(input, rb_intern("read")))
201
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected String or IO)",
202
+ rb_obj_classname(input));
203
+
204
+ if (TYPE(input) == T_STRING) {
205
+ unsigned int corrupt = 0;
206
+ ExifLog *log = exif_log_new();
207
+ exif_log_set_func(log, exif_corrupt_log_func, (void *)&corrupt);
208
+ ed = exif_data_new();
209
+ exif_data_log(ed, log);
210
+ exif_data_load_data(ed, (unsigned char *)RSTRING_PTR(input),
211
+ (uint32_t)RSTRING_LEN(input));
212
+ exif_log_unref(log);
213
+ if (corrupt) {
214
+ exif_data_free(ed);
215
+ ed = NULL;
216
+ }
217
+ } else {
218
+ ExifLoader *loader = exif_loader_new();
219
+ VALUE buffer;
220
+ while (1) {
221
+ buffer = rb_funcall(input, rb_intern("read"), 1, INT2FIX(1024));
222
+ if (TYPE(buffer) == T_NIL)
223
+ break;
224
+ if (!exif_loader_write(loader, (unsigned char *)RSTRING_PTR(buffer),
225
+ (uint32_t)RSTRING_LEN(buffer)))
226
+ break;
227
+ }
228
+ ed = exif_loader_get_data(loader);
229
+ exif_loader_unref(loader);
230
+ }
231
+ if (!ed)
232
+ rb_raise(rb_eNotReadable, "File not readable or no EXIF data in file.");
233
+
29
234
  VALUE rb_data = Data_Wrap_Struct(self, NULL, exif_data_free, ed);
30
- rb_iv_set(rb_data, "@contents", rb_hash_new());
235
+ rb_iv_set(rb_data, "@ifds", rb_hash_new());
31
236
  exif_data_foreach_content(ed, each_content, &rb_data);
32
237
  return rb_data;
33
238
  }
34
239
 
35
- VALUE rb_dump(VALUE self){
240
+ static VALUE dump(VALUE self) {
36
241
  ExifData *ed;
37
242
  Data_Get_Struct(self, ExifData, ed);
38
243
  exif_data_dump(ed);
39
244
  return Qnil;
40
245
  }
41
246
 
42
- VALUE rb_value(VALUE self, VALUE key){
43
- VALUE rb_contents = rb_iv_get(self, "@contents");
44
- return rb_hash_aref(rb_contents, key);
247
+ static VALUE brackets(VALUE self, VALUE ifd_symbol) {
248
+ return rb_hash_aref(rb_iv_get(self, "@ifds"), ifd_symbol);
45
249
  }
46
250
 
47
- void each_content(ExifContent *ec, void *self_ptr){
48
- VALUE *self = (VALUE*)self_ptr;
49
- VALUE rb_contents = rb_iv_get(*self, "@contents");
50
- Check_Type(rb_contents, T_HASH);
51
- ExifIfd ifd = exif_content_get_ifd(ec);
52
- VALUE ifd_name = IFD2SYM[ifd]; //rb_str_new_cstr(exif_ifd_get_name(ifd));
53
- if(ifd == EXIF_IFD_COUNT) rb_raise(rb_eRuntimeError, "Con't get IFD.");
54
- else rb_hash_aset(rb_contents, ifd_name, rb_hash_new());
55
- exif_content_foreach_entry(ec, each_entry, self);
251
+ static void each_content(ExifContent *ec, void *self_ptr) {
252
+ ExifIfd ifd;
253
+
254
+ ifd = exif_content_get_ifd(ec);
255
+ if (ifd == EXIF_IFD_COUNT)
256
+ rb_raise(rb_eIFDNotFound, "Con't get IFD.");
257
+ rb_hash_aset(rb_iv_get(*(VALUE *)self_ptr, "@ifds"),
258
+ ID2SYM(rb_intern(ifd_name_mapping[ifd])), rb_hash_new());
259
+ exif_content_foreach_entry(ec, each_entry, self_ptr);
56
260
  }
57
261
 
58
- void each_entry(ExifEntry *ee, void *self_ptr){
59
- VALUE *self = (VALUE*)self_ptr;
60
- VALUE rb_contents = rb_iv_get(*self, "@contents");
61
- ExifIfd ifd = exif_entry_get_ifd(ee);
62
- const char *attr_name = attr_string(ifd, ee->tag);
63
- VALUE tag_name = ID2SYM(rb_intern(attr_name + 1));
64
- char buf[500];
65
- exif_entry_get_value(ee, buf, sizeof(buf));
262
+ static void each_entry(ExifEntry *entry, void *self_ptr) {
66
263
  VALUE value;
67
- switch(ee->format){
68
- // case EXIF_FORMAT_BYTE:
69
- // break;
70
- // case EXIF_FORMAT_ASCII:
71
- // break;
72
- case EXIF_FORMAT_SHORT:
73
- value = INT2NUM(atoi(buf));
74
- break;
75
- case EXIF_FORMAT_LONG:
76
- value = INT2NUM(atol(buf));
77
- break;
78
- // case EXIF_FORMAT_RATIONAL:
79
- // break;
80
- // case EXIF_FORMAT_SBYTE:
81
- // break;
82
- // case EXIF_FORMAT_UNDEFINED:
83
- // break;
84
- // case EXIF_FORMAT_SSHORT:
85
- // break;
86
- // case EXIF_FORMAT_SLONG:
87
- // break;
88
- // case EXIF_FORMAT_SRATIONAL:
89
- // break;
90
- case EXIF_FORMAT_FLOAT:
91
- value = rb_float_new(atof(buf));
92
- break;
93
- case EXIF_FORMAT_DOUBLE:
94
- value = rb_float_new(atof(buf));
95
- break;
96
- default:
97
- value = process_value(self, ifd, ee->tag, buf);
98
- }
99
- rb_hash_aset(rb_hash_aref(rb_contents, IFD2SYM[ifd]), tag_name, value);
100
- rb_hash_aset(rb_contents, tag_name, value);
101
- rb_iv_set(*self, attr_name, value);
102
- }
264
+ const char *ivar_name;
103
265
 
104
- VALUE process_value(VALUE *self_ptr, ExifIfd ifd, ExifTag tag, char *buf){
105
- ExifData *ed;
106
- Data_Get_Struct(*self_ptr, ExifData, ed);
107
- switch((int)tag){
108
- case EXIF_TAG_DATE_TIME:
109
- case EXIF_TAG_DATE_TIME_ORIGINAL:
110
- case EXIF_TAG_DATE_TIME_DIGITIZED:
111
- {
112
- struct tm timer;
113
- // "2013:09:10 16:31:21"
114
- buf[4] = buf[7] = buf[10] = buf[13] = buf[16] = '\0';
115
- timer.tm_year = atoi(buf) - 1900;
116
- timer.tm_mon = atoi(buf + 5) - 1;
117
- timer.tm_mday = atoi(buf + 8);
118
- timer.tm_hour = atoi(buf + 11);
119
- timer.tm_min = atoi(buf + 14);
120
- timer.tm_sec = atoi(buf + 17);
121
- return rb_time_new(mktime(&timer), 0);
122
- break;
266
+ ivar_name = exif_entry_to_ivar(entry);
267
+ value = exif_entry_to_rb_value(entry);
268
+
269
+ if (ivar_name == 0x00) {
270
+ rb_warning("Unsupported tag %x", entry->tag);
271
+ return;
123
272
  }
124
- case EXIF_TAG_GPS_LATITUDE: // EXIF_TAG_INTEROPERABILITY_INDEX
125
- case EXIF_TAG_GPS_LONGITUDE: // EXIF_TAG_INTEROPERABILITY_VERSION
126
- {
127
- if(ifd != EXIF_IFD_GPS) break;
128
- char *l = buf, *r = buf + 1;
129
- double degrees, minutes, seconds;
130
- // "121, 30.7476, 0"
131
- while(*r != ',') r++;
132
- *r = '\0'; r++;
133
- degrees = atof(l); l = r;
134
- while(*r != ',') r++;
135
- *r = '\0';
136
- minutes = atof(l); l = r + 1;
137
- seconds = atof(l);
138
- ExifTag ref_tag = tag == EXIF_TAG_GPS_LATITUDE ? EXIF_TAG_GPS_LATITUDE_REF : EXIF_TAG_GPS_LONGITUDE_REF;
139
- ExifEntry *entry = exif_content_get_entry(ed->ifd[EXIF_IFD_GPS], ref_tag);
140
- char ref_value; exif_entry_get_value(entry, &ref_value, 1);
141
- double degree = (degrees * 3600 + minutes * 60 + seconds) / 3600;
142
- if(ref_value == 'S' || ref_value == 'W') degree *= -1;
143
- return rb_float_new(degree);
144
- }
273
+
274
+ rb_hash_aset(rb_hash_aref(rb_iv_get(*(VALUE *)self_ptr, "@ifds"),
275
+ ID2SYM(rb_intern(
276
+ ifd_name_mapping[exif_entry_get_ifd(entry)]))),
277
+ ID2SYM(rb_intern(ivar_name + 1)), value);
278
+ if (TYPE(rb_ivar_defined(*(VALUE *)self_ptr, rb_intern(ivar_name))) ==
279
+ T_FALSE) {
280
+ rb_iv_set(*(VALUE *)self_ptr, ivar_name, value);
145
281
  }
146
- return rb_str_new_cstr(buf);
147
282
  }
148
283
 
149
- const char* attr_string(ExifIfd ifd, ExifTag tag){
150
- switch((int)tag){
151
- case EXIF_TAG_INTEROPERABILITY_INDEX: /* EXIF_TAG_GPS_LATITUDE_REF */
152
- return ifd == EXIF_IFD_GPS ? "@gps_latitude_ref" : "@interoperability_index";
153
- break;
154
- case EXIF_TAG_INTEROPERABILITY_VERSION: /* EXIF_TAG_GPS_LATITUDE */
155
- return ifd == EXIF_IFD_GPS ? "@gps_latitude" : "@interoperability_version";
156
- break;
157
- case EXIF_TAG_NEW_SUBFILE_TYPE:
158
- return "@new_subfile_type";
159
- break;
160
- case EXIF_TAG_IMAGE_WIDTH:
161
- return "@image_width";
162
- break;
163
- case EXIF_TAG_IMAGE_LENGTH:
164
- return "@image_length";
165
- break;
166
- case EXIF_TAG_BITS_PER_SAMPLE:
167
- return "@bits_per_sample";
168
- break;
169
- case EXIF_TAG_COMPRESSION:
170
- return "@compression";
171
- break;
172
- case EXIF_TAG_PHOTOMETRIC_INTERPRETATION:
173
- return "@photometric_interpretation";
174
- break;
175
- case EXIF_TAG_FILL_ORDER:
176
- return "@fill_order";
177
- break;
178
- case EXIF_TAG_DOCUMENT_NAME:
179
- return "@document_name";
180
- break;
181
- case EXIF_TAG_IMAGE_DESCRIPTION:
182
- return "@image_description";
183
- break;
184
- case EXIF_TAG_MAKE:
185
- return "@make";
186
- break;
187
- case EXIF_TAG_MODEL:
188
- return "@model";
189
- break;
190
- case EXIF_TAG_STRIP_OFFSETS:
191
- return "@strip_offsets";
192
- break;
193
- case EXIF_TAG_ORIENTATION:
194
- return "@orientation";
195
- break;
196
- case EXIF_TAG_SAMPLES_PER_PIXEL:
197
- return "@samples_per_pixel";
198
- break;
199
- case EXIF_TAG_ROWS_PER_STRIP:
200
- return "@rows_per_strip";
201
- break;
202
- case EXIF_TAG_STRIP_BYTE_COUNTS:
203
- return "@strip_byte_counts";
204
- break;
205
- case EXIF_TAG_X_RESOLUTION:
206
- return "@x_resolution";
207
- break;
208
- case EXIF_TAG_Y_RESOLUTION:
209
- return "@y_resolution";
210
- break;
211
- case EXIF_TAG_PLANAR_CONFIGURATION:
212
- return "@planar_configuration";
213
- break;
214
- case EXIF_TAG_RESOLUTION_UNIT:
215
- return "@resolution_unit";
216
- break;
217
- case EXIF_TAG_TRANSFER_FUNCTION:
218
- return "@transfer_function";
219
- break;
220
- case EXIF_TAG_SOFTWARE:
221
- return "@software";
222
- break;
223
- case EXIF_TAG_DATE_TIME:
224
- return "@date_time";
225
- break;
226
- case EXIF_TAG_ARTIST:
227
- return "@artist";
228
- break;
229
- case EXIF_TAG_WHITE_POINT:
230
- return "@white_point";
231
- break;
232
- case EXIF_TAG_PRIMARY_CHROMATICITIES:
233
- return "@primary_chromaticities";
234
- break;
235
- case EXIF_TAG_SUB_IFDS:
236
- return "@sub_ifds";
237
- break;
238
- case EXIF_TAG_TRANSFER_RANGE:
239
- return "@transfer_range";
240
- break;
241
- case EXIF_TAG_JPEG_PROC:
242
- return "@jpeg_proc";
243
- break;
244
- case EXIF_TAG_JPEG_INTERCHANGE_FORMAT:
245
- return "@jpeg_interchange_format";
246
- break;
247
- case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
248
- return "@jpeg_interchange_format_length";
249
- break;
250
- case EXIF_TAG_YCBCR_COEFFICIENTS:
251
- return "@ycbcr_coefficients";
252
- break;
253
- case EXIF_TAG_YCBCR_SUB_SAMPLING:
254
- return "@ycbcr_sub_sampling";
255
- break;
256
- case EXIF_TAG_YCBCR_POSITIONING:
257
- return "@ycbcr_positioning";
258
- break;
259
- case EXIF_TAG_REFERENCE_BLACK_WHITE:
260
- return "@reference_black_white";
261
- break;
262
- case EXIF_TAG_XML_PACKET:
263
- return "@xml_packet";
264
- break;
265
- case EXIF_TAG_RELATED_IMAGE_FILE_FORMAT:
266
- return "@related_image_file_format";
267
- break;
268
- case EXIF_TAG_RELATED_IMAGE_WIDTH:
269
- return "@related_image_width";
270
- break;
271
- case EXIF_TAG_RELATED_IMAGE_LENGTH:
272
- return "@related_image_length";
273
- break;
274
- case EXIF_TAG_CFA_REPEAT_PATTERN_DIM:
275
- return "@cfa_repeat_pattern_dim";
276
- break;
277
- case EXIF_TAG_CFA_PATTERN:
278
- return "@cfa_pattern";
279
- break;
280
- case EXIF_TAG_BATTERY_LEVEL:
281
- return "@battery_level";
282
- break;
283
- case EXIF_TAG_COPYRIGHT:
284
- return "@copyright";
285
- break;
286
- case EXIF_TAG_EXPOSURE_TIME:
287
- return "@exposure_time";
288
- break;
289
- case EXIF_TAG_FNUMBER:
290
- return "@fnumber";
291
- break;
292
- case EXIF_TAG_IPTC_NAA:
293
- return "@iptc_naa";
294
- break;
295
- case EXIF_TAG_IMAGE_RESOURCES:
296
- return "@image_resources";
297
- break;
298
- case EXIF_TAG_EXIF_IFD_POINTER:
299
- return "@exif_ifd_pointer";
300
- break;
301
- case EXIF_TAG_INTER_COLOR_PROFILE:
302
- return "@inter_color_profile";
303
- break;
304
- case EXIF_TAG_EXPOSURE_PROGRAM:
305
- return "@exposure_program";
306
- break;
307
- case EXIF_TAG_SPECTRAL_SENSITIVITY:
308
- return "@spectral_sensitivity";
309
- break;
310
- case EXIF_TAG_GPS_INFO_IFD_POINTER:
311
- return "@gps_info_ifd_pointer";
312
- break;
313
- case EXIF_TAG_ISO_SPEED_RATINGS:
314
- return "@iso_speed_ratings";
315
- break;
316
- case EXIF_TAG_OECF:
317
- return "@oecf";
318
- break;
319
- case EXIF_TAG_TIME_ZONE_OFFSET:
320
- return "@time_zone_offset";
321
- break;
322
- case EXIF_TAG_EXIF_VERSION:
323
- return "@exif_version";
324
- break;
325
- case EXIF_TAG_DATE_TIME_ORIGINAL:
326
- return "@date_time_original";
327
- break;
328
- case EXIF_TAG_DATE_TIME_DIGITIZED:
329
- return "@date_time_digitized";
330
- break;
331
- case EXIF_TAG_COMPONENTS_CONFIGURATION:
332
- return "@components_configuration";
333
- break;
334
- case EXIF_TAG_COMPRESSED_BITS_PER_PIXEL:
335
- return "@compressed_bits_per_pixel";
336
- break;
337
- case EXIF_TAG_SHUTTER_SPEED_VALUE:
338
- return "@shutter_speed_value";
339
- break;
340
- case EXIF_TAG_APERTURE_VALUE:
341
- return "@aperture_value";
342
- break;
343
- case EXIF_TAG_BRIGHTNESS_VALUE:
344
- return "@brightness_value";
345
- break;
346
- case EXIF_TAG_EXPOSURE_BIAS_VALUE:
347
- return "@exposure_bias_value";
348
- break;
349
- case EXIF_TAG_MAX_APERTURE_VALUE:
350
- return "@max_aperture_value";
351
- break;
352
- case EXIF_TAG_SUBJECT_DISTANCE:
353
- return "@subject_distance";
354
- break;
355
- case EXIF_TAG_METERING_MODE:
356
- return "@metering_mode";
357
- break;
358
- case EXIF_TAG_LIGHT_SOURCE:
359
- return "@light_source";
360
- break;
361
- case EXIF_TAG_FLASH:
362
- return "@flash";
363
- break;
364
- case EXIF_TAG_FOCAL_LENGTH:
365
- return "@focal_length";
366
- break;
367
- case EXIF_TAG_SUBJECT_AREA:
368
- return "@subject_area";
369
- break;
370
- case EXIF_TAG_TIFF_EP_STANDARD_ID:
371
- return "@tiff_ep_standard_id";
372
- break;
373
- case EXIF_TAG_MAKER_NOTE:
374
- return "@maker_note";
375
- break;
376
- case EXIF_TAG_USER_COMMENT:
377
- return "@user_comment";
378
- break;
379
- case EXIF_TAG_SUB_SEC_TIME:
380
- return "@sub_sec_time";
381
- break;
382
- case EXIF_TAG_SUB_SEC_TIME_ORIGINAL:
383
- return "@sub_sec_time_original";
384
- break;
385
- case EXIF_TAG_SUB_SEC_TIME_DIGITIZED:
386
- return "@sub_sec_time_digitized";
387
- break;
388
- case EXIF_TAG_XP_TITLE:
389
- return "@xp_title";
390
- break;
391
- case EXIF_TAG_XP_COMMENT:
392
- return "@xp_comment";
393
- break;
394
- case EXIF_TAG_XP_AUTHOR:
395
- return "@xp_author";
396
- break;
397
- case EXIF_TAG_XP_KEYWORDS:
398
- return "@xp_keywords";
399
- break;
400
- case EXIF_TAG_XP_SUBJECT:
401
- return "@xp_subject";
402
- break;
403
- case EXIF_TAG_FLASH_PIX_VERSION:
404
- return "@flash_pix_version";
405
- break;
406
- case EXIF_TAG_COLOR_SPACE:
407
- return "@color_space";
408
- break;
409
- case EXIF_TAG_PIXEL_X_DIMENSION:
410
- return "@pixel_x_dimension";
411
- break;
412
- case EXIF_TAG_PIXEL_Y_DIMENSION:
413
- return "@pixel_y_dimension";
414
- break;
415
- case EXIF_TAG_RELATED_SOUND_FILE:
416
- return "@related_sound_file";
417
- break;
418
- case EXIF_TAG_INTEROPERABILITY_IFD_POINTER:
419
- return "@interoperability_ifd_pointer";
420
- break;
421
- case EXIF_TAG_FLASH_ENERGY:
422
- return "@flash_energy";
423
- break;
424
- case EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE:
425
- return "@spatial_frequency_response";
426
- break;
427
- case EXIF_TAG_FOCAL_PLANE_X_RESOLUTION:
428
- return "@focal_plane_x_resolution";
429
- break;
430
- case EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION:
431
- return "@focal_plane_y_resolution";
432
- break;
433
- case EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT:
434
- return "@focal_plane_resolution_unit";
435
- break;
436
- case EXIF_TAG_SUBJECT_LOCATION:
437
- return "@subject_location";
438
- break;
439
- case EXIF_TAG_EXPOSURE_INDEX:
440
- return "@exposure_index";
441
- break;
442
- case EXIF_TAG_SENSING_METHOD:
443
- return "@sensing_method";
444
- break;
445
- case EXIF_TAG_FILE_SOURCE:
446
- return "@file_source";
447
- break;
448
- case EXIF_TAG_SCENE_TYPE:
449
- return "@scene_type";
450
- break;
451
- case EXIF_TAG_NEW_CFA_PATTERN:
452
- return "@new_cfa_pattern";
453
- break;
454
- case EXIF_TAG_CUSTOM_RENDERED:
455
- return "@custom_rendered";
456
- break;
457
- case EXIF_TAG_EXPOSURE_MODE:
458
- return "@exposure_mode";
459
- break;
460
- case EXIF_TAG_WHITE_BALANCE:
461
- return "@white_balance";
462
- break;
463
- case EXIF_TAG_DIGITAL_ZOOM_RATIO:
464
- return "@digital_zoom_ratio";
465
- break;
466
- case EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM:
467
- return "@focal_length_in_35mm_film";
468
- break;
469
- case EXIF_TAG_SCENE_CAPTURE_TYPE:
470
- return "@scene_capture_type";
471
- break;
472
- case EXIF_TAG_GAIN_CONTROL:
473
- return "@gain_control";
474
- break;
475
- case EXIF_TAG_CONTRAST:
476
- return "@contrast";
477
- break;
478
- case EXIF_TAG_SATURATION:
479
- return "@saturation";
480
- break;
481
- case EXIF_TAG_SHARPNESS:
482
- return "@sharpness";
483
- break;
484
- case EXIF_TAG_DEVICE_SETTING_DESCRIPTION:
485
- return "@device_setting_description";
486
- break;
487
- case EXIF_TAG_SUBJECT_DISTANCE_RANGE:
488
- return "@subject_distance_range";
489
- break;
490
- case EXIF_TAG_IMAGE_UNIQUE_ID:
491
- return "@image_unique_id";
492
- break;
493
- case EXIF_TAG_GAMMA:
494
- return "@gamma";
495
- break;
496
- case EXIF_TAG_PRINT_IMAGE_MATCHING:
497
- return "@print_image_matching";
498
- break;
499
- case EXIF_TAG_PADDING:
500
- return "@padding";
501
- break;
502
- case EXIF_TAG_GPS_VERSION_ID:
503
- return "@gps_version_id";
504
- break;
505
- case EXIF_TAG_GPS_LONGITUDE_REF:
506
- return "@gps_longitude_ref";
507
- break;
508
- case EXIF_TAG_GPS_LONGITUDE:
509
- return "@gps_longitude";
510
- break;
511
- case EXIF_TAG_GPS_ALTITUDE_REF:
512
- return "@gps_altitude_ref";
513
- break;
514
- case EXIF_TAG_GPS_ALTITUDE:
515
- return "@gps_altitude";
516
- break;
517
- case EXIF_TAG_GPS_TIME_STAMP:
518
- return "@gps_time_stamp";
519
- break;
520
- case EXIF_TAG_GPS_SATELLITES:
521
- return "@gps_satellites";
522
- break;
523
- case EXIF_TAG_GPS_STATUS:
524
- return "@gps_status";
525
- break;
526
- case EXIF_TAG_GPS_MEASURE_MODE:
527
- return "@gps_measure_mode";
528
- break;
529
- case EXIF_TAG_GPS_DOP:
530
- return "@gps_dop";
531
- break;
532
- case EXIF_TAG_GPS_SPEED_REF:
533
- return "@gps_speed_ref";
534
- break;
535
- case EXIF_TAG_GPS_SPEED:
536
- return "@gps_speed";
537
- break;
538
- case EXIF_TAG_GPS_TRACK_REF:
539
- return "@gps_track_ref";
540
- break;
541
- case EXIF_TAG_GPS_TRACK:
542
- return "@gps_track";
543
- break;
544
- case EXIF_TAG_GPS_IMG_DIRECTION_REF:
545
- return "@gps_img_direction_ref";
546
- break;
547
- case EXIF_TAG_GPS_IMG_DIRECTION:
548
- return "@gps_img_direction";
549
- break;
550
- case EXIF_TAG_GPS_MAP_DATUM:
551
- return "@gps_map_datum";
552
- break;
553
- case EXIF_TAG_GPS_DEST_LATITUDE_REF:
554
- return "@gps_dest_latitude_ref";
555
- break;
556
- case EXIF_TAG_GPS_DEST_LATITUDE:
557
- return "@gps_dest_latitude";
558
- break;
559
- case EXIF_TAG_GPS_DEST_LONGITUDE_REF:
560
- return "@gps_dest_longitude_ref";
284
+ #define TYPECAST(value1, value2) \
285
+ do { \
286
+ if (entry->components > 1) { \
287
+ ret = rb_ary_new2(entry->components); \
288
+ for (i = 0; i < entry->components; i++) \
289
+ rb_ary_push(ret, value1); \
290
+ } else \
291
+ ret = value2; \
292
+ } while (0)
293
+
294
+ #define TYPECAST_BYTE(c_to_rb, type) \
295
+ TYPECAST(c_to_rb((type)entry->data[i]), c_to_rb((type)entry->data[0]))
296
+
297
+ #define TYPECAST_EXIF(c_to_rb, exif_get) \
298
+ TYPECAST(c_to_rb(exif_get_##exif_get(entry->data + i * size, order)), \
299
+ c_to_rb(exif_get_##exif_get(entry->data, order)))
300
+
301
+ static VALUE exif_entry_to_rb_value(ExifEntry *entry) {
302
+ ExifData *data;
303
+ ExifByteOrder order;
304
+ VALUE ret;
305
+ size_t i;
306
+ unsigned char size;
307
+
308
+ data = entry->parent->parent;
309
+ order = exif_data_get_byte_order(data);
310
+ ret = Qnil;
311
+ size = exif_format_get_size(entry->format);
312
+
313
+ switch (entry->format) {
314
+ case EXIF_FORMAT_UNDEFINED:
315
+ ret = rb_str_new((const char *)entry->data, entry->size);
561
316
  break;
562
- case EXIF_TAG_GPS_DEST_LONGITUDE:
563
- return "@gps_dest_longitude";
317
+ case EXIF_FORMAT_BYTE:
318
+ TYPECAST_BYTE(INT2FIX, uint8_t);
319
+ case EXIF_FORMAT_SBYTE:
320
+ TYPECAST_BYTE(INT2FIX, int8_t);
564
321
  break;
565
- case EXIF_TAG_GPS_DEST_BEARING_REF:
566
- return "@gps_dest_bearing_ref";
322
+ case EXIF_FORMAT_SHORT:
323
+ TYPECAST_EXIF(INT2FIX, short);
567
324
  break;
568
- case EXIF_TAG_GPS_DEST_BEARING:
569
- return "@gps_dest_bearing";
325
+ case EXIF_FORMAT_SSHORT:
326
+ TYPECAST_EXIF(INT2FIX, sshort);
570
327
  break;
571
- case EXIF_TAG_GPS_DEST_DISTANCE_REF:
572
- return "@gps_dest_distance_ref";
328
+ case EXIF_FORMAT_LONG:
329
+ TYPECAST_EXIF(ULONG2NUM, long);
573
330
  break;
574
- case EXIF_TAG_GPS_DEST_DISTANCE:
575
- return "@gps_dest_distance";
331
+ case EXIF_FORMAT_SLONG:
332
+ TYPECAST_EXIF(LONG2NUM, slong);
576
333
  break;
577
- case EXIF_TAG_GPS_PROCESSING_METHOD:
578
- return "@gps_processing_method";
334
+ case EXIF_FORMAT_ASCII:
335
+ ret = rb_str_new2((const char *)entry->data);
579
336
  break;
580
- case EXIF_TAG_GPS_AREA_INFORMATION:
581
- return "@gps_area_information";
337
+ case EXIF_FORMAT_RATIONAL:
338
+ TYPECAST_EXIF(rational_to_num, rational);
582
339
  break;
583
- case EXIF_TAG_GPS_DATE_STAMP:
584
- return "@gps_date_stamp";
340
+ case EXIF_FORMAT_SRATIONAL:
341
+ TYPECAST_EXIF(srational_to_num, srational);
585
342
  break;
586
- case EXIF_TAG_GPS_DIFFERENTIAL:
587
- return "@gps_differential";
343
+ case EXIF_FORMAT_DOUBLE:
344
+ case EXIF_FORMAT_FLOAT:
345
+ ret = rb_float_new(*(double *)entry->data);
588
346
  break;
589
347
  }
590
- return NULL;
591
- }
348
+
349
+ return ret;
350
+ }
351
+
352
+ #undef TYPECAST
353
+ #undef TYPECAST_BYTE
354
+ #undef TYPECAST_EXIF
355
+
356
+ VALUE rational_to_num(ExifRational rational) {
357
+ if (rational.numerator == 0 && rational.denominator == 0)
358
+ return DBL2NUM(NAN);
359
+ else if (rational.denominator == 0)
360
+ return DBL2NUM(INFINITY);
361
+ else
362
+ return rb_rational_new(ULONG2NUM(rational.numerator),
363
+ ULONG2NUM(rational.denominator));
364
+ }
365
+
366
+ VALUE srational_to_num(ExifSRational srational) {
367
+ if (srational.numerator == 0 && srational.denominator == 0)
368
+ return DBL2NUM(NAN);
369
+ else if (srational.denominator == 0)
370
+ return DBL2NUM(srational.numerator > 0 ? INFINITY : -INFINITY);
371
+ else
372
+ return rb_rational_new(LONG2NUM(srational.numerator),
373
+ LONG2NUM(srational.denominator));
374
+ }