exif_utility 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/exif_utility +4 -0
- data/lib/exif_utility.rb +20 -0
- data/lib/exif_utility/data.rb +26 -0
- data/lib/exif_utility/interpreter.rb +918 -0
- data/lib/exif_utility/parser.rb +176 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a170d2a17362fee9fc97611b715544a2fc282f9f
|
4
|
+
data.tar.gz: 7f80ff385be3436068dcc9f08ac08fd2b85124e8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 45b1ac562b6cc886d87e831c23f561590467880052abd5739d9de5fc0d744338e124fd9ae2e245a40aa6100a1e915777413ca7ccc15e74ffc289e0bff53c46b3
|
7
|
+
data.tar.gz: 6931c287d71a66811b64d351f2410f07602bca2bfd02902584de0d7025cf25b8f1c2b02337eb7088039cd83cbef011f46836b3622c129e55343b563e364a14f4
|
data/bin/exif_utility
ADDED
data/lib/exif_utility.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module ExifUtility
|
2
|
+
class ExifUtility
|
3
|
+
|
4
|
+
# Exif data is stored in the Data class
|
5
|
+
attr_accessor :data
|
6
|
+
|
7
|
+
def initialize(filename)
|
8
|
+
@data = Data.new
|
9
|
+
Parser.new(filename, data)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'date'
|
17
|
+
|
18
|
+
require 'exif_utility/data'
|
19
|
+
require 'exif_utility/parser'
|
20
|
+
require 'exif_utility/interpreter'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ExifUtility
|
2
|
+
# Contains the values for each tag, populated by the parser
|
3
|
+
class Data
|
4
|
+
|
5
|
+
# TODO: Save data read in for each tag
|
6
|
+
|
7
|
+
|
8
|
+
# These are the tags, in order. Blank lines means tags were skipped.
|
9
|
+
attr_accessor :make # 0x010f
|
10
|
+
attr_accessor :model # 0x0110
|
11
|
+
|
12
|
+
attr_accessor :software # 0x0131
|
13
|
+
attr_accessor :modify_date # 0x0132
|
14
|
+
|
15
|
+
attr_accessor :exif_offset # 0x876
|
16
|
+
|
17
|
+
attr_accessor :date_time_original # 0x9003
|
18
|
+
attr_accessor :create_date # 0x9004
|
19
|
+
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
# nothing needed to be done currently
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,918 @@
|
|
1
|
+
module ExifUtility
|
2
|
+
class Interpreter
|
3
|
+
|
4
|
+
def initialize(data)
|
5
|
+
@data = data
|
6
|
+
|
7
|
+
# data_format =>
|
8
|
+
@data_format_and_size = {
|
9
|
+
"0001" => 1, # unsigned byte
|
10
|
+
"0002" => 1, # ascii character
|
11
|
+
"0003" => 2, # unsigned short
|
12
|
+
"0004" => 4, # unsigned long
|
13
|
+
"0005" => 8, # unsigned rational: a fractional value containing 2 signed/unsigned long integer values: the first is the numerator, the second is the denominator
|
14
|
+
"0006" => 1, # signed byte
|
15
|
+
"0007" => 1, # undefined
|
16
|
+
"0008" => 2, # signed short
|
17
|
+
"0009" => 4, # signed long
|
18
|
+
"000A" => 8, # signed rational
|
19
|
+
"000B" => 4, # single float
|
20
|
+
"000C" => 8 # double float
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def size_from_data_format(data_format)
|
25
|
+
@data_format_and_size[data_format]
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
def interpret_as_string(data)
|
32
|
+
# Also removes the null character at the end.
|
33
|
+
data.scan(/../).map(&:hex).map(&:chr).join[0..-2]
|
34
|
+
end
|
35
|
+
|
36
|
+
def interpret_as_number(data)
|
37
|
+
data.to_i(16)
|
38
|
+
end
|
39
|
+
|
40
|
+
def interpret_as_date_time(data)
|
41
|
+
data = interpret_as_string(data)
|
42
|
+
DateTime.strptime(data, '%Y:%m:%d %H:%M:%S')
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
# http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
|
48
|
+
def interpret(tag, data)
|
49
|
+
case tag
|
50
|
+
|
51
|
+
|
52
|
+
# when "0001"
|
53
|
+
# @data.interop_index = data
|
54
|
+
# when "0002"
|
55
|
+
# @data.interop_version = data
|
56
|
+
# when "000B"
|
57
|
+
# @data.processing_software = data
|
58
|
+
# when "00FE"
|
59
|
+
# @data.subfile_type = data
|
60
|
+
# when "00FF"
|
61
|
+
# @data.old_subfile_type = data
|
62
|
+
# when "0100"
|
63
|
+
# @data.image_width = data
|
64
|
+
# when "0101"
|
65
|
+
# @data.image_height = data
|
66
|
+
# when "0102"
|
67
|
+
# @data.bits_per_sample = data
|
68
|
+
# when "0103"
|
69
|
+
# @data.compression = data
|
70
|
+
# when "0106"
|
71
|
+
# @data.photometric_interpretation = data
|
72
|
+
# when "0107"
|
73
|
+
# @data.thresholding = data
|
74
|
+
# when "0108"
|
75
|
+
# @data.cell_width = data
|
76
|
+
# when "0109"
|
77
|
+
# @data.cell_length = data
|
78
|
+
# when "010A"
|
79
|
+
# @data.fill_order = data
|
80
|
+
# when "010D"
|
81
|
+
# @data.document_name = data
|
82
|
+
# when "010E"
|
83
|
+
# @data.image_description = data
|
84
|
+
when "010F"
|
85
|
+
@data.make = interpret_as_string(data)
|
86
|
+
when "0110"
|
87
|
+
@data.model = interpret_as_string(data)
|
88
|
+
# when "0111"
|
89
|
+
# @data.strip_offsets = data
|
90
|
+
# when "0112"
|
91
|
+
# @data.orientation = data
|
92
|
+
# when "0115"
|
93
|
+
# @data.samples_per_pixel = data
|
94
|
+
# when "0116"
|
95
|
+
# @data.rows_per_strip = data
|
96
|
+
# when "0117"
|
97
|
+
# @data.strip_byte_counts = data
|
98
|
+
# when "0118"
|
99
|
+
# @data.min_sample_value = data
|
100
|
+
# when "0119"
|
101
|
+
# @data.max_sample_value = data
|
102
|
+
# when "011A"
|
103
|
+
# @data.x_resolution = data
|
104
|
+
# when "011B"
|
105
|
+
# @data.y_resolution = data
|
106
|
+
# when "011C"
|
107
|
+
# @data.planar_configuration = data
|
108
|
+
# when "011D"
|
109
|
+
# @data.page_name = data
|
110
|
+
# when "011E"
|
111
|
+
# @data.x_position = data
|
112
|
+
# when "011F"
|
113
|
+
# @data.y_position = data
|
114
|
+
# when "0120"
|
115
|
+
# @data.free_offsets = data
|
116
|
+
# when "0121"
|
117
|
+
# @data.free_byte_counts = data
|
118
|
+
# when "0122"
|
119
|
+
# @data.gray_response_unit = data
|
120
|
+
# when "0123"
|
121
|
+
# @data.gray_response_curve = data
|
122
|
+
# when "0124"
|
123
|
+
# @data.t4_options = data
|
124
|
+
# when "0125"
|
125
|
+
# @data.t6_options = data
|
126
|
+
# when "0128"
|
127
|
+
# @data.resolution_unit = data
|
128
|
+
# when "0129"
|
129
|
+
# @data.page_number = data
|
130
|
+
# when "012C"
|
131
|
+
# @data.color_response_unit = data
|
132
|
+
# when "012D"
|
133
|
+
# @data.transfer_function = data
|
134
|
+
when "0131"
|
135
|
+
@data.software = interpret_as_string(data)
|
136
|
+
when "0132"
|
137
|
+
@data.modify_date = interpret_as_date_time(data)
|
138
|
+
# when "013B"
|
139
|
+
# @data.artist = data
|
140
|
+
# when "013C"
|
141
|
+
# @data.host_computer = data
|
142
|
+
# when "013D"
|
143
|
+
# @data.predictor = data
|
144
|
+
# when "013E"
|
145
|
+
# @data.white_point = data
|
146
|
+
# when "013F"
|
147
|
+
# @data.primary_chromaticities = data
|
148
|
+
# when "0140"
|
149
|
+
# @data.color_map = data
|
150
|
+
# when "0141"
|
151
|
+
# @data.halftone_hints = data
|
152
|
+
# when "0142"
|
153
|
+
# @data.tile_width = data
|
154
|
+
# when "0143"
|
155
|
+
# @data.tile_length = data
|
156
|
+
# when "0144"
|
157
|
+
# @data.tile_offsets = data
|
158
|
+
# when "0145"
|
159
|
+
# @data.tile_byte_counts = data
|
160
|
+
# when "0146"
|
161
|
+
# @data.bad_fax_lines = data
|
162
|
+
# when "0147"
|
163
|
+
# @data.clean_fax_data = data
|
164
|
+
# when "0148"
|
165
|
+
# @data.consecutive_bad_fax_lines = data
|
166
|
+
# when "014A"
|
167
|
+
# @data.sub_ifd = data
|
168
|
+
# when "014C"
|
169
|
+
# @data.ink_set = data
|
170
|
+
# when "014D"
|
171
|
+
# @data.ink_names = data
|
172
|
+
# when "014E"
|
173
|
+
# @data.number_of_inks = data
|
174
|
+
# when "0150"
|
175
|
+
# @data.dot_range = data
|
176
|
+
# when "0151"
|
177
|
+
# @data.target_printer = data
|
178
|
+
# when "0152"
|
179
|
+
# @data.extra_samples = data
|
180
|
+
# when "0153"
|
181
|
+
# @data.sample_format = data
|
182
|
+
# when "0154"
|
183
|
+
# @data.s_min_sample_value = data
|
184
|
+
# when "0155"
|
185
|
+
# @data.s_max_sample_value = data
|
186
|
+
# when "0156"
|
187
|
+
# @data.transfer_range = data
|
188
|
+
# when "0157"
|
189
|
+
# @data.clip_path = data
|
190
|
+
# when "0158"
|
191
|
+
# @data.x_clip_path_units = data
|
192
|
+
# when "0159"
|
193
|
+
# @data.y_clip_path_units = data
|
194
|
+
# when "015A"
|
195
|
+
# @data.indexed = data
|
196
|
+
# when "015B"
|
197
|
+
# @data.jpeg_tables = data
|
198
|
+
# when "015F"
|
199
|
+
# @data.opi_proxy = data
|
200
|
+
# when "0190"
|
201
|
+
# @data.global_parameters_ifd = data
|
202
|
+
# when "0191"
|
203
|
+
# @data.profile_type = data
|
204
|
+
# when "0192"
|
205
|
+
# @data.fax_profile = data
|
206
|
+
# when "0193"
|
207
|
+
# @data.coding_methods = data
|
208
|
+
# when "0194"
|
209
|
+
# @data.version_year = data
|
210
|
+
# when "0195"
|
211
|
+
# @data.mode_number = data
|
212
|
+
# when "01B1"
|
213
|
+
# @data.decode = data
|
214
|
+
# when "01B2"
|
215
|
+
# @data.default_image_color = data
|
216
|
+
# when "01B3"
|
217
|
+
# @data.t82_options = data
|
218
|
+
# when "01B5"
|
219
|
+
# @data.jpeg_tables = data
|
220
|
+
# when "0200"
|
221
|
+
# @data.jpeg_proc = data
|
222
|
+
# when "0201"
|
223
|
+
# @data.thumbnail_offset = data
|
224
|
+
# when "0202"
|
225
|
+
# @data.thumbnail_length = data
|
226
|
+
# when "0203"
|
227
|
+
# @data.jpeg_restart_interval = data
|
228
|
+
# when "0205"
|
229
|
+
# @data.jpeg_lossless_predictors = data
|
230
|
+
# when "0206"
|
231
|
+
# @data.jpeg_point_transforms = data
|
232
|
+
# when "0207"
|
233
|
+
# @data.jpeg_q_tables = data
|
234
|
+
# when "0208"
|
235
|
+
# @data.jpeg_dc_tables = data
|
236
|
+
# when "0209"
|
237
|
+
# @data.jpeg_ac_tables = data
|
238
|
+
# when "0211"
|
239
|
+
# @data.y_cb_cr_coefficients = data
|
240
|
+
# when "0212"
|
241
|
+
# @data.y_cb_cr_subsampling = data
|
242
|
+
# when "0213"
|
243
|
+
# @data.y_cb_cr_positioning = data
|
244
|
+
# when "0214"
|
245
|
+
# @data.reference_black_white = data
|
246
|
+
# when "022F"
|
247
|
+
# @data.strip_row_counts = data
|
248
|
+
# when "02BC"
|
249
|
+
# @data.application_notes = data
|
250
|
+
# when "03E7"
|
251
|
+
# @data.uspt_omiscellaneous = data
|
252
|
+
# when "1000"
|
253
|
+
# @data.related_image_file_format = data
|
254
|
+
# when "1001"
|
255
|
+
# @data.related_image_width = data
|
256
|
+
# when "1002"
|
257
|
+
# @data.related_image_height = data
|
258
|
+
# when "4746"
|
259
|
+
# @data.rating = data
|
260
|
+
# when "4747"
|
261
|
+
# @data.xp_dip_xml = data
|
262
|
+
# when "4748"
|
263
|
+
# @data.stitch_info = data
|
264
|
+
# when "4749"
|
265
|
+
# @data.rating_percent = data
|
266
|
+
# when "800D"
|
267
|
+
# @data.image_id = data
|
268
|
+
# when "80A3"
|
269
|
+
# @data.wang_tag_1 = data
|
270
|
+
# when "80A4"
|
271
|
+
# @data.wang_annotation = data
|
272
|
+
# when "80A5"
|
273
|
+
# @data.wang_tag_3 = data
|
274
|
+
# when "80A6"
|
275
|
+
# @data.wang_tag_4 = data
|
276
|
+
# when "80E3"
|
277
|
+
# @data.matteing = data
|
278
|
+
# when "80E4"
|
279
|
+
# @data.data_type = data
|
280
|
+
# when "80E5"
|
281
|
+
# @data.image_depth = data
|
282
|
+
# when "80E6"
|
283
|
+
# @data.tile_depth = data
|
284
|
+
# when "827D"
|
285
|
+
# @data.mode_l2 = data
|
286
|
+
# when "828D"
|
287
|
+
# @data.cfa_repeat_pattern_dim = data
|
288
|
+
# when "828E"
|
289
|
+
# @data.cfa_pattern_2 = data
|
290
|
+
# when "828F"
|
291
|
+
# @data.battery_level = data
|
292
|
+
# when "8290"
|
293
|
+
# @data.kodak_ifd = data
|
294
|
+
# when "8298"
|
295
|
+
# @data.copyright = data
|
296
|
+
# when "829A"
|
297
|
+
# @data.exposure_time = data
|
298
|
+
# when "829D"
|
299
|
+
# @data.f_number = data
|
300
|
+
# when "82A5"
|
301
|
+
# @data.md_file_tag = data
|
302
|
+
# when "82A6"
|
303
|
+
# @data.md_scale_pixel = data
|
304
|
+
# when "82A7"
|
305
|
+
# @data.md_color_table = data
|
306
|
+
# when "82A8"
|
307
|
+
# @data.md_lab_name = data
|
308
|
+
# when "82A9"
|
309
|
+
# @data.md_sample_info = data
|
310
|
+
# when "82AA"
|
311
|
+
# @data.md_prep_date = data
|
312
|
+
# when "82AB"
|
313
|
+
# @data.md_prep_time = data
|
314
|
+
# when "82AC"
|
315
|
+
# @data.mdfileunits = data
|
316
|
+
# when "830E"
|
317
|
+
# @data.pixel_scale = data
|
318
|
+
# when "8335"
|
319
|
+
# @data.advent_scale = data
|
320
|
+
# when "8336"
|
321
|
+
# @data.advent_revision = data
|
322
|
+
# when "835C"
|
323
|
+
# @data.uic_1_tag = data
|
324
|
+
# when "835D"
|
325
|
+
# @data.uic_2_tag = data
|
326
|
+
# when "835E"
|
327
|
+
# @data.uic_3_tag = data
|
328
|
+
# when "835F"
|
329
|
+
# @data.uic_4_tag = data
|
330
|
+
# when "83BB"
|
331
|
+
# @data.iptc_naa = data
|
332
|
+
# when "847E"
|
333
|
+
# @data.intergraph_packet_data = data
|
334
|
+
# when "847F"
|
335
|
+
# @data.intergraph_flag_registers = data
|
336
|
+
# when "8480"
|
337
|
+
# @data.intergraph_matrix = data
|
338
|
+
# when "8481"
|
339
|
+
# @data.ingr_reserved = data
|
340
|
+
# when "8482"
|
341
|
+
# @data.model_tie_point = data
|
342
|
+
# when "84E0"
|
343
|
+
# @data.site = data
|
344
|
+
# when "84E1"
|
345
|
+
# @data.color_sequence = data
|
346
|
+
# when "84E2"
|
347
|
+
# @data.it8_header = data
|
348
|
+
# when "84E3"
|
349
|
+
# @data.raster_padding = data
|
350
|
+
# when "84E4"
|
351
|
+
# @data.bits_per_run_length = data
|
352
|
+
# when "84E5"
|
353
|
+
# @data.bits_per_extended_run_length = data
|
354
|
+
# when "84E6"
|
355
|
+
# @data.color_table = data
|
356
|
+
# when "84E7"
|
357
|
+
# @data.image_color_indicator = data
|
358
|
+
# when "84E8"
|
359
|
+
# @data.background_color_indicator = data
|
360
|
+
# when "84E9"
|
361
|
+
# @data.image_color_value = data
|
362
|
+
# when "84EA"
|
363
|
+
# @data.background_color_value = data
|
364
|
+
# when "84EB"
|
365
|
+
# @data.pixel_intensity_range = data
|
366
|
+
# when "84EC"
|
367
|
+
# @data.transparency_indicator = data
|
368
|
+
# when "84ED"
|
369
|
+
# @data.color_characterization = data
|
370
|
+
# when "84EE"
|
371
|
+
# @data.hc_usage = data
|
372
|
+
# when "84EF"
|
373
|
+
# @data.trap_indicator = data
|
374
|
+
# when "84F0"
|
375
|
+
# @data.cmyk_equivalent = data
|
376
|
+
# when "8546"
|
377
|
+
# @data.sem_info = data
|
378
|
+
# when "8568"
|
379
|
+
# @data.afcp_iptc = data
|
380
|
+
# when "85B8"
|
381
|
+
# @data.pixel_magic_jbig_options = data
|
382
|
+
# when "85D8"
|
383
|
+
# @data.model_transform = data
|
384
|
+
# when "8602"
|
385
|
+
# @data.wb_grgb_levels = data
|
386
|
+
# when "8606"
|
387
|
+
# @data.leaf_data = data
|
388
|
+
# when "8649"
|
389
|
+
# @data.photoshop_settings = data
|
390
|
+
when "8769"
|
391
|
+
@data.exif_offset = interpret_as_number(data)
|
392
|
+
# when "8773"
|
393
|
+
# @data.icc_profile = data
|
394
|
+
# when "877F"
|
395
|
+
# @data.tiff_fxextensions = data
|
396
|
+
# when "8780"
|
397
|
+
# @data.multi_profiles = data
|
398
|
+
# when "8781"
|
399
|
+
# @data.shared_data = data
|
400
|
+
# when "8782"
|
401
|
+
# @data.t88_options = data
|
402
|
+
# when "87AC"
|
403
|
+
# @data.image_layer = data
|
404
|
+
# when "87AF"
|
405
|
+
# @data.geo_tiff_directory = data
|
406
|
+
# when "87B0"
|
407
|
+
# @data.geo_tiff_double_params = data
|
408
|
+
# when "87B1"
|
409
|
+
# @data.geo_tiff_ascii_params = data
|
410
|
+
# when "8822"
|
411
|
+
# @data.exposure_program = data
|
412
|
+
# when "8824"
|
413
|
+
# @data.spectral_sensitivity = data
|
414
|
+
# when "8825"
|
415
|
+
# @data.gps_info = data
|
416
|
+
# when "8827"
|
417
|
+
# @data.iso = data
|
418
|
+
# when "8828"
|
419
|
+
# @data.opto_electric_conv_factor = data
|
420
|
+
# when "8829"
|
421
|
+
# @data.interlace = data
|
422
|
+
# when "882A"
|
423
|
+
# @data.time_zone_offset = data
|
424
|
+
# when "882B"
|
425
|
+
# @data.self_timer_mode = data
|
426
|
+
# when "8830"
|
427
|
+
# @data.sensitivity_type = data
|
428
|
+
# when "8831"
|
429
|
+
# @data.standard_output_sensitivity = data
|
430
|
+
# when "8832"
|
431
|
+
# @data.recommended_exposure_index = data
|
432
|
+
# when "8833"
|
433
|
+
# @data.iso_speed = data
|
434
|
+
# when "8834"
|
435
|
+
# @data.iso_speed_latitude_yyy = data
|
436
|
+
# when "8835"
|
437
|
+
# @data.iso_speed_latitude_zzz = data
|
438
|
+
# when "885C"
|
439
|
+
# @data.fax_recv_params = data
|
440
|
+
# when "885D"
|
441
|
+
# @data.fax_sub_address = data
|
442
|
+
# when "885E"
|
443
|
+
# @data.fax_recv_time = data
|
444
|
+
# when "888A"
|
445
|
+
# @data.leaf_subifd = data
|
446
|
+
# when "9000"
|
447
|
+
# @data.exif_version = data
|
448
|
+
when "9003"
|
449
|
+
@data.date_time_original = interpret_as_date_time(data)
|
450
|
+
when "9004"
|
451
|
+
@data.create_date = interpret_as_date_time(data)
|
452
|
+
# when "9101"
|
453
|
+
# @data.components_configuration = data
|
454
|
+
# when "9102"
|
455
|
+
# @data.compressed_bits_per_pixel = data
|
456
|
+
# when "9201"
|
457
|
+
# @data.shutter_speed_value = data
|
458
|
+
# when "9202"
|
459
|
+
# @data.aperture_value = data
|
460
|
+
# when "9203"
|
461
|
+
# @data.brightness_value = data
|
462
|
+
# when "9204"
|
463
|
+
# @data.exposure_compensation = data
|
464
|
+
# when "9205"
|
465
|
+
# @data.max_aperture_value = data
|
466
|
+
# when "9206"
|
467
|
+
# @data.subject_distance = data
|
468
|
+
# when "9207"
|
469
|
+
# @data.metering_mode = data
|
470
|
+
# when "9208"
|
471
|
+
# @data.light_source = data
|
472
|
+
# when "9209"
|
473
|
+
# @data.flash = data
|
474
|
+
# when "920A"
|
475
|
+
# @data.focal_length = data
|
476
|
+
# when "920B"
|
477
|
+
# @data.flash_energy = data
|
478
|
+
# when "920C"
|
479
|
+
# @data.spatial_frequencyresponse = data
|
480
|
+
# when "920D"
|
481
|
+
# @data.noise = data
|
482
|
+
# when "920E"
|
483
|
+
# @data.focal_plane_x_resolution = data
|
484
|
+
# when "920F"
|
485
|
+
# @data.focal_plane_y_resolution = data
|
486
|
+
# when "9210"
|
487
|
+
# @data.focal_plane_resolution_unit = data
|
488
|
+
# when "9211"
|
489
|
+
# @data.image_number = data
|
490
|
+
# when "9212"
|
491
|
+
# @data.security_classification = data
|
492
|
+
# when "9213"
|
493
|
+
# @data.image_history = data
|
494
|
+
# when "9214"
|
495
|
+
# @data.subject_area = data
|
496
|
+
# when "9215"
|
497
|
+
# @data.exposure_index = data
|
498
|
+
# when "9216"
|
499
|
+
# @data.tiff_ep_standard_id = data
|
500
|
+
# when "9217"
|
501
|
+
# @data.sensing_method = data
|
502
|
+
# when "923A"
|
503
|
+
# @data.cip3_data_file = data
|
504
|
+
# when "923B"
|
505
|
+
# @data.cip3_sheet = data
|
506
|
+
# when "923C"
|
507
|
+
# @data.cip3_side = data
|
508
|
+
# when "923F"
|
509
|
+
# @data.sto_nits = data
|
510
|
+
# when "927C"
|
511
|
+
# @data.maker_note_vendor = data # VENDOR can be Apple, Nikon, Canon, etc
|
512
|
+
# when "9286"
|
513
|
+
# @data.user_comment = data
|
514
|
+
# when "9290"
|
515
|
+
# @data.sub_sec_time = data
|
516
|
+
# when "9291"
|
517
|
+
# @data.sub_sec_time_original = data
|
518
|
+
# when "9292"
|
519
|
+
# @data.sub_sec_time_digitized = data
|
520
|
+
# when "932F"
|
521
|
+
# @data.ms_document_text = data
|
522
|
+
# when "9330"
|
523
|
+
# @data.ms_property_set_storage = data
|
524
|
+
# when "9331"
|
525
|
+
# @data.ms_document_text_position = data
|
526
|
+
# when "935C"
|
527
|
+
# @data.image_source_data = data
|
528
|
+
# when "9C9B"
|
529
|
+
# @data.xp_title = data
|
530
|
+
# when "9C9C"
|
531
|
+
# @data.xp_comment = data
|
532
|
+
# when "9C9D"
|
533
|
+
# @data.xp_author = data
|
534
|
+
# when "9C9E"
|
535
|
+
# @data.xp_keywords = data
|
536
|
+
# when "9C9F"
|
537
|
+
# @data.xp_subject = data
|
538
|
+
# when "A000"
|
539
|
+
# @data.flashpix_version = data
|
540
|
+
# when "A001"
|
541
|
+
# @data.color_space = data
|
542
|
+
# when "A002"
|
543
|
+
# @data.exif_image_width = data
|
544
|
+
# when "A003"
|
545
|
+
# @data.exif_image_height = data
|
546
|
+
# when "A004"
|
547
|
+
# @data.related_sound_file = data
|
548
|
+
# when "A005"
|
549
|
+
# @data.interop_offset = data
|
550
|
+
# when "A20B"
|
551
|
+
# @data.flash_energy = data
|
552
|
+
# when "A20C"
|
553
|
+
# @data.spatial_frequency_response = data
|
554
|
+
# when "A20D"
|
555
|
+
# @data.noise = data
|
556
|
+
# when "A20E"
|
557
|
+
# @data.focal_plane_x_resolution = data
|
558
|
+
# when "A20F"
|
559
|
+
# @data.focal_plane_y_resolution = data
|
560
|
+
# when "A210"
|
561
|
+
# @data.focal_plane_resolution_unit = data
|
562
|
+
# when "A211"
|
563
|
+
# @data.image_number = data
|
564
|
+
# when "A212"
|
565
|
+
# @data.security_classification = data
|
566
|
+
# when "A213"
|
567
|
+
# @data.image_history = data
|
568
|
+
# when "A214"
|
569
|
+
# @data.subject_location = data
|
570
|
+
# when "A215"
|
571
|
+
# @data.exposure_index = data
|
572
|
+
# when "A216"
|
573
|
+
# @data.tiff_ep_standard_id = data
|
574
|
+
# when "A217"
|
575
|
+
# @data.sensing_method = data
|
576
|
+
# when "A300"
|
577
|
+
# @data.file_source = data
|
578
|
+
# when "A301"
|
579
|
+
# @data.scene_type = data
|
580
|
+
# when "A302"
|
581
|
+
# @data.cfa_pattern = data
|
582
|
+
# when "A401"
|
583
|
+
# @data.custom_rendered = data
|
584
|
+
# when "A402"
|
585
|
+
# @data.exposure_mode = data
|
586
|
+
# when "A403"
|
587
|
+
# @data.white_balance = data
|
588
|
+
# when "A404"
|
589
|
+
# @data.digital_zoom_ratio = data
|
590
|
+
# when "A405"
|
591
|
+
# @data.focal_length_in_35mm_format = data
|
592
|
+
# when "A406"
|
593
|
+
# @data.scene_capture_type = data
|
594
|
+
# when "A407"
|
595
|
+
# @data.gain_control = data
|
596
|
+
# when "A408"
|
597
|
+
# @data.contrast = data
|
598
|
+
# when "A409"
|
599
|
+
# @data.saturation = data
|
600
|
+
# when "A40A"
|
601
|
+
# @data.sharpness = data
|
602
|
+
# when "A40B"
|
603
|
+
# @data.device_setting_description = data
|
604
|
+
# when "A40C"
|
605
|
+
# @data.subject_distance_range = data
|
606
|
+
# when "A420"
|
607
|
+
# @data.image_unique_id = data
|
608
|
+
# when "A430"
|
609
|
+
# @data.owner_name = data
|
610
|
+
# when "A431"
|
611
|
+
# @data.serial_number = data
|
612
|
+
# when "A432"
|
613
|
+
# @data.lens_info = data
|
614
|
+
# when "A433"
|
615
|
+
# @data.lens_make = data
|
616
|
+
# when "A434"
|
617
|
+
# @data.lens_model = data
|
618
|
+
# when "A435"
|
619
|
+
# @data.lens_serial_number = data
|
620
|
+
# when "A480"
|
621
|
+
# @data.gdal_metadata = data
|
622
|
+
# when "A481"
|
623
|
+
# @data.gdal_no_data = data
|
624
|
+
# when "A500"
|
625
|
+
# @data.gamma = data
|
626
|
+
# when "AFC0"
|
627
|
+
# @data.expand_software = data
|
628
|
+
# when "AFC1"
|
629
|
+
# @data.expand_lens = data
|
630
|
+
# when "AFC2"
|
631
|
+
# @data.expand_film = data
|
632
|
+
# when "AFC3"
|
633
|
+
# @data.expand_filter_lens = data
|
634
|
+
# when "AFC4"
|
635
|
+
# @data.expand_scanner = data
|
636
|
+
# when "AFC5"
|
637
|
+
# @data.expand_flash_lamp = data
|
638
|
+
# when "BC01"
|
639
|
+
# @data.pixel_format = data
|
640
|
+
# when "BC02"
|
641
|
+
# @data.transformation = data
|
642
|
+
# when "BC03"
|
643
|
+
# @data.uncompressed = data
|
644
|
+
# when "BC04"
|
645
|
+
# @data.image_type = data
|
646
|
+
# when "BC80"
|
647
|
+
# @data.image_width = data
|
648
|
+
# when "BC81"
|
649
|
+
# @data.image_height = data
|
650
|
+
# when "BC82"
|
651
|
+
# @data.width_resolution = data
|
652
|
+
# when "BC83"
|
653
|
+
# @data.height_resolution = data
|
654
|
+
# when "BCC0"
|
655
|
+
# @data.image_offset = data
|
656
|
+
# when "BCC1"
|
657
|
+
# @data.image_byte_count = data
|
658
|
+
# when "BCC2"
|
659
|
+
# @data.alpha_offset = data
|
660
|
+
# when "BCC3"
|
661
|
+
# @data.alpha_byte_count = data
|
662
|
+
# when "BCC4"
|
663
|
+
# @data.image_data_discard = data
|
664
|
+
# when "BCC5"
|
665
|
+
# @data.alpha_data_discard = data
|
666
|
+
# when "C427"
|
667
|
+
# @data.oce_scanjob_desc = data
|
668
|
+
# when "C428"
|
669
|
+
# @data.oce_application_selector = data
|
670
|
+
# when "C429"
|
671
|
+
# @data.oce_id_number = data
|
672
|
+
# when "C42A"
|
673
|
+
# @data.oce_image_logic = data
|
674
|
+
# when "C44F"
|
675
|
+
# @data.annotations = data
|
676
|
+
# when "C4A5"
|
677
|
+
# @data.print_im = data
|
678
|
+
# when "C573"
|
679
|
+
# @data.original_filename = data
|
680
|
+
# when "C580"
|
681
|
+
# @data.uspto_original_content_type = data
|
682
|
+
# when "C612"
|
683
|
+
# @data.dng_version = data
|
684
|
+
# when "C613"
|
685
|
+
# @data.dng_backward_version = data
|
686
|
+
# when "C614"
|
687
|
+
# @data.unique_camera_model = data
|
688
|
+
# when "C615"
|
689
|
+
# @data.localized_camera_model = data
|
690
|
+
# when "C616"
|
691
|
+
# @data.cfa_plane_color = data
|
692
|
+
# when "C617"
|
693
|
+
# @data.cfa_layout = data
|
694
|
+
# when "C618"
|
695
|
+
# @data.linearization_table = data
|
696
|
+
# when "C619"
|
697
|
+
# @data.black_level_repeat_dim = data
|
698
|
+
# when "C61A"
|
699
|
+
# @data.black_level = data
|
700
|
+
# when "C61B"
|
701
|
+
# @data.black_level_delta_h = data
|
702
|
+
# when "C61C"
|
703
|
+
# @data.black_level_delta_v = data
|
704
|
+
# when "C61D"
|
705
|
+
# @data.white_level = data
|
706
|
+
# when "C61E"
|
707
|
+
# @data.default_scale = data
|
708
|
+
# when "C61F"
|
709
|
+
# @data.default_crop_origin = data
|
710
|
+
# when "C620"
|
711
|
+
# @data.default_crop_size = data
|
712
|
+
# when "C621"
|
713
|
+
# @data.color_matrix_1 = data
|
714
|
+
# when "C622"
|
715
|
+
# @data.color_matrix_2 = data
|
716
|
+
# when "C623"
|
717
|
+
# @data.camera_calibration_1 = data
|
718
|
+
# when "C624"
|
719
|
+
# @data.camera_calibration_2 = data
|
720
|
+
# when "C625"
|
721
|
+
# @data.reduction_matrix_1 = data
|
722
|
+
# when "C626"
|
723
|
+
# @data.reduction_matrix_2 = data
|
724
|
+
# when "C627"
|
725
|
+
# @data.analog_balance = data
|
726
|
+
# when "C628"
|
727
|
+
# @data.asshot_neutral = data
|
728
|
+
# when "C629"
|
729
|
+
# @data.asshot_white_xy = data
|
730
|
+
# when "C62A"
|
731
|
+
# @data.baseline_exposure = data
|
732
|
+
# when "C62B"
|
733
|
+
# @data.baseline_noise = data
|
734
|
+
# when "C62C"
|
735
|
+
# @data.baseline_sharpness = data
|
736
|
+
# when "C62D"
|
737
|
+
# @data.bayer_green_split = data
|
738
|
+
# when "C62E"
|
739
|
+
# @data.linear_response_limit = data
|
740
|
+
# when "C62F"
|
741
|
+
# @data.camera_serial_number = data
|
742
|
+
# when "C630"
|
743
|
+
# @data.dng_lens_info = data
|
744
|
+
# when "C631"
|
745
|
+
# @data.chroma_blur_radius = data
|
746
|
+
# when "C632"
|
747
|
+
# @data.anti_alias_strength = data
|
748
|
+
# when "C633"
|
749
|
+
# @data.shadow_scale = data
|
750
|
+
# when "C634"
|
751
|
+
# @data.sr2_private = data
|
752
|
+
# when "C635"
|
753
|
+
# @data.maker_note_safety = data
|
754
|
+
# when "C640"
|
755
|
+
# @data.raw_image_segmentation = data
|
756
|
+
# when "C65A"
|
757
|
+
# @data.calibration_illuminant_1 = data
|
758
|
+
# when "C65B"
|
759
|
+
# @data.calibration_illuminant_2 = data
|
760
|
+
# when "C65C"
|
761
|
+
# @data.best_quality_scale = data
|
762
|
+
# when "C65D"
|
763
|
+
# @data.raw_data_unique_id = data
|
764
|
+
# when "C660"
|
765
|
+
# @data.alias_layer_metadata = data
|
766
|
+
# when "C68B"
|
767
|
+
# @data.original_raw_file_name = data
|
768
|
+
# when "C68C"
|
769
|
+
# @data.original_raw_file_data = data
|
770
|
+
# when "C68D"
|
771
|
+
# @data.active_area = data
|
772
|
+
# when "C68E"
|
773
|
+
# @data.masked_areas = data
|
774
|
+
# when "C68F"
|
775
|
+
# @data.asshot_icc_profile = data
|
776
|
+
# when "C690"
|
777
|
+
# @data.asshot_pre_profile_matrix = data
|
778
|
+
# when "C691"
|
779
|
+
# @data.current_icc_profile = data
|
780
|
+
# when "C692"
|
781
|
+
# @data.current_pre_profile_matrix = data
|
782
|
+
# when "C6BF"
|
783
|
+
# @data.colorimetric_reference = data
|
784
|
+
# when "C6D2"
|
785
|
+
# @data.panasonic_title = data
|
786
|
+
# when "C6D3"
|
787
|
+
# @data.panasonic_title_2 = data
|
788
|
+
# when "C6F3"
|
789
|
+
# @data.camera_calibration_sig = data
|
790
|
+
# when "C6F4"
|
791
|
+
# @data.profile_calibration_sig = data
|
792
|
+
# when "C6F5"
|
793
|
+
# @data.profile_ifd = data
|
794
|
+
# when "C6F6"
|
795
|
+
# @data.asshot_profile_name = data
|
796
|
+
# when "C6F7"
|
797
|
+
# @data.noise_reduction_applied = data
|
798
|
+
# when "C6F8"
|
799
|
+
# @data.profile_name = data
|
800
|
+
# when "C6F9"
|
801
|
+
# @data.profile_hue_sat_mapdims = data
|
802
|
+
# when "C6FA"
|
803
|
+
# @data.profile_hue_sat_map_data_1 = data
|
804
|
+
# when "C6FB"
|
805
|
+
# @data.profile_hue_sat_map_data_2 = data
|
806
|
+
# when "C6FC"
|
807
|
+
# @data.profile_tone_curve = data
|
808
|
+
# when "C6FD"
|
809
|
+
# @data.profile_embed_policy = data
|
810
|
+
# when "C6FE"
|
811
|
+
# @data.profile_copyright = data
|
812
|
+
# when "C714"
|
813
|
+
# @data.forward_matrix_1 = data
|
814
|
+
# when "C715"
|
815
|
+
# @data.forward_matrix_2 = data
|
816
|
+
# when "C716"
|
817
|
+
# @data.preview_application_name = data
|
818
|
+
# when "C717"
|
819
|
+
# @data.preview_application_version = data
|
820
|
+
# when "C718"
|
821
|
+
# @data.preview_settings_name = data
|
822
|
+
# when "C719"
|
823
|
+
# @data.preview_settings_digest = data
|
824
|
+
# when "C71A"
|
825
|
+
# @data.preview_color_space = data
|
826
|
+
# when "C71B"
|
827
|
+
# @data.preview_date_time = data
|
828
|
+
# when "C71C"
|
829
|
+
# @data.raw_image_digest = data
|
830
|
+
# when "C71D"
|
831
|
+
# @data.original_raw_file_digest = data
|
832
|
+
# when "C71E"
|
833
|
+
# @data.sub_tile_block_size = data
|
834
|
+
# when "C71F"
|
835
|
+
# @data.row_interleave_factor = data
|
836
|
+
# when "C725"
|
837
|
+
# @data.profile_look_table_dims = data
|
838
|
+
# when "C726"
|
839
|
+
# @data.profile_look_table_data = data
|
840
|
+
# when "C740"
|
841
|
+
# @data.opcode_list_1 = data
|
842
|
+
# when "C741"
|
843
|
+
# @data.opcode_list_2 = data
|
844
|
+
# when "C74E"
|
845
|
+
# @data.opcode_list_3 = data
|
846
|
+
# when "C761"
|
847
|
+
# @data.noise_profile = data
|
848
|
+
# when "C763"
|
849
|
+
# @data.time_codes = data
|
850
|
+
# when "C764"
|
851
|
+
# @data.frame_rate = data
|
852
|
+
# when "C772"
|
853
|
+
# @data.t_stop = data
|
854
|
+
# when "C789"
|
855
|
+
# @data.reel_name = data
|
856
|
+
# when "C791"
|
857
|
+
# @data.original_default_final_size = data
|
858
|
+
# when "C792"
|
859
|
+
# @data.original_best_quality_size = data
|
860
|
+
# when "C793"
|
861
|
+
# @data.original_default_crop_size = data
|
862
|
+
# when "C7A1"
|
863
|
+
# @data.camera_label = data
|
864
|
+
# when "C7A3"
|
865
|
+
# @data.profile_hue_sat_map_encoding = data
|
866
|
+
# when "C7A4"
|
867
|
+
# @data.profile_look_table_encoding = data
|
868
|
+
# when "C7A5"
|
869
|
+
# @data.baseline_exposure_offset = data
|
870
|
+
# when "C7A6"
|
871
|
+
# @data.default_black_render = data
|
872
|
+
# when "C7A7"
|
873
|
+
# @data.new_raw_image_digest = data
|
874
|
+
# when "C7A8"
|
875
|
+
# @data.raw_to_preview_gain = data
|
876
|
+
# when "C7B5"
|
877
|
+
# @data.default_user_crop = data
|
878
|
+
# when "EA1C"
|
879
|
+
# @data.padding = data
|
880
|
+
# when "EA1D"
|
881
|
+
# @data.offset_schema = data
|
882
|
+
# when "FDE8"
|
883
|
+
# @data.owner_name = data
|
884
|
+
# when "FDE9"
|
885
|
+
# @data.serial_number = data
|
886
|
+
# when "FDEA"
|
887
|
+
# @data.lens = data
|
888
|
+
# when "FE00"
|
889
|
+
# @data.kdc_ifd = data
|
890
|
+
# when "FE4C"
|
891
|
+
# @data.raw_file = data
|
892
|
+
# when "FE4D"
|
893
|
+
# @data.converter = data
|
894
|
+
# when "FE4E"
|
895
|
+
# @data.white_balance = data
|
896
|
+
# when "FE51"
|
897
|
+
# @data.exposure = data
|
898
|
+
# when "FE52"
|
899
|
+
# @data.shadows = data
|
900
|
+
# when "FE53"
|
901
|
+
# @data.brightness = data
|
902
|
+
# when "FE54"
|
903
|
+
# @data.contrast = data
|
904
|
+
# when "FE55"
|
905
|
+
# @data.saturation = data
|
906
|
+
# when "FE56"
|
907
|
+
# @data.sharpness = data
|
908
|
+
# when "FE57"
|
909
|
+
# @data.smoothness = data
|
910
|
+
# when "FE58"
|
911
|
+
# @data.moire_filter = data
|
912
|
+
end
|
913
|
+
|
914
|
+
end
|
915
|
+
|
916
|
+
end
|
917
|
+
|
918
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module ExifUtility
|
2
|
+
class Parser
|
3
|
+
|
4
|
+
def initialize(filename, data)
|
5
|
+
@data = data
|
6
|
+
@interpreter = Interpreter.new(@data)
|
7
|
+
|
8
|
+
file = File.open(filename, 'rb')
|
9
|
+
|
10
|
+
# Check to make sure it's an image.
|
11
|
+
# Every JPEG starts with 0xFFD8 the marker for a JPEG SOI (Start of image)
|
12
|
+
unless file.read(2).unpack('H*')[0].upcase == "FFD8"
|
13
|
+
raise "#{filename} is not a JPEG"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Exif data starts with the AAP1 Marker: 0xFFE1
|
17
|
+
# Sometimes there are other markers (0xFFE0) before, read past them until you get to 0xFFE1
|
18
|
+
first = file.read(1).unpack('H*')[0].upcase
|
19
|
+
while true
|
20
|
+
second = file.read(1).unpack('H*')[0].upcase
|
21
|
+
|
22
|
+
if first == "FF" and second == "E1"
|
23
|
+
break
|
24
|
+
end
|
25
|
+
first = second
|
26
|
+
end
|
27
|
+
|
28
|
+
# unless file.read(2).unpack('H*')[0].upcase == "FFE1"
|
29
|
+
# raise "#{filename} does not have Exif data"
|
30
|
+
# end
|
31
|
+
|
32
|
+
# The size of the APP1 data area (Exif data area)
|
33
|
+
exif_data_size = file.read(2).unpack('H*')[0].upcase.to_i(16) - 2 # note that this size includes the size of descriptor (2 bytes)
|
34
|
+
|
35
|
+
# Read in the Exif Header
|
36
|
+
# The Exif Header always starts with 0x457869660000
|
37
|
+
unless file.read(6).unpack('H*')[0].upcase == "457869660000"
|
38
|
+
raise "#{filename} does not have an Exif header"
|
39
|
+
end
|
40
|
+
|
41
|
+
exif_data_size -= 6 # subtract the size of the Exif Header (6 bytes)
|
42
|
+
|
43
|
+
# Read in all of APP1 Data
|
44
|
+
# @exif_data now starts at offset 0x0000
|
45
|
+
@exif_data = file.read(exif_data_size).unpack('H*')[0].upcase
|
46
|
+
@offset = 0
|
47
|
+
@alignment = :motorola
|
48
|
+
|
49
|
+
|
50
|
+
# Read in the TIFF Header (8 bytes)
|
51
|
+
# The first 2 bytes define the byte align of the TIFF data
|
52
|
+
# 0x4949 == "II". This is the Intel alignment (little-endian).
|
53
|
+
# 0x4d4d == "MM". This is the Motorola alignment (big-endian).
|
54
|
+
# Note that this alignment is only for the Exif data, not the JPEG data
|
55
|
+
# How the alignments differ:
|
56
|
+
# 0x12345678 is stored as 0x12 0x34 0x56 0x78 using Motorola align
|
57
|
+
# 0x12345678 is stored as 0x78 0x56 0x34 0x12 using Intel align
|
58
|
+
# But you can't just
|
59
|
+
case read(2)
|
60
|
+
when "4949"
|
61
|
+
@alignment = :intel
|
62
|
+
when "4D4D"
|
63
|
+
@alignment = :motorola
|
64
|
+
else
|
65
|
+
raise 'The TIFF Header does not have a byte alignment'
|
66
|
+
end
|
67
|
+
|
68
|
+
# The next 2 bytes are always 0x002A
|
69
|
+
unless read(2) == "002A"
|
70
|
+
raise 'Parsing error: not 0x002A'
|
71
|
+
end
|
72
|
+
|
73
|
+
# The last 4 bytes of the TIFF header are an offset to the first IFD (Image File Directory).
|
74
|
+
# Offset is counted from the beginning of the TIFF header and is usually 0x00000008.
|
75
|
+
# The Tiff header, including these 4 bytes, is 8 bytes total, so 0x00000008 is immediately after to the TIFF header
|
76
|
+
# Get us to the beginning of IFD0
|
77
|
+
@offset = read(4).to_i(16)
|
78
|
+
|
79
|
+
# The first IFD, IFD0, is the IFD of the main image.
|
80
|
+
# IFD1 is the IFD of the thumbnail image.
|
81
|
+
# IFDs contain image information data but IFD0 and IFD1 don't contain any digicam info such as shutter speed, focal length, etc.
|
82
|
+
# IFD0 always contains a special Tag Exif Offset (0x8769) which shows an offset to Exif SufIFD which is IFD formatted data that contains digicam info.
|
83
|
+
|
84
|
+
# Parse the first IFD
|
85
|
+
parse_IFD
|
86
|
+
|
87
|
+
# After an IFD there are 4 bytes representing the offset to the next IFD.
|
88
|
+
# Note that the next IFD is different from Exif SubIFD
|
89
|
+
# If they are 0x00000000 then there are no more IFDs
|
90
|
+
offset_to_next_IFD = read(4).to_i(16)
|
91
|
+
|
92
|
+
# Then jump to the offset for Exif SubIFD
|
93
|
+
set_offset(@data.exif_offset)
|
94
|
+
# Then parse the Exif SubIFD which contains digicam information
|
95
|
+
parse_IFD
|
96
|
+
|
97
|
+
|
98
|
+
## TODO: Parse the IFD linked to by IFD0
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
def parse_IFD
|
105
|
+
# The first 2 bytes are the number of directory entries contained in this IFD
|
106
|
+
@entries = read(2).to_i(16)
|
107
|
+
|
108
|
+
# Next are the directory entires, 12 bytes per entry, from entry (0) to (@entries - 1)
|
109
|
+
@entries.times do
|
110
|
+
parse_entry
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse_entry
|
117
|
+
tag = read(2)
|
118
|
+
data_format = read(2)
|
119
|
+
number_of_components = read(4).to_i(16)
|
120
|
+
data_value = read(4)
|
121
|
+
|
122
|
+
bytes_of_data = @interpreter.size_from_data_format(data_format) * number_of_components
|
123
|
+
if bytes_of_data > 4
|
124
|
+
# interpret the datavalue as an offset
|
125
|
+
result = @interpreter.interpret(tag, read_at_offset(bytes_of_data, data_value.to_i(16))) # in this scenario data_value is the offset to the data
|
126
|
+
else
|
127
|
+
# interpret the datavalue as the data
|
128
|
+
result = @interpreter.interpret(tag, data_value)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Data is saved in the interpreter
|
132
|
+
# @data.add_data(tag, result)
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
# Section for methods that work with reading in bytes
|
140
|
+
# Reads in data from @exif_data
|
141
|
+
|
142
|
+
def set_offset(new_offset)
|
143
|
+
@offset = new_offset
|
144
|
+
end
|
145
|
+
|
146
|
+
# have to chck if the data should be read as little or big endian
|
147
|
+
def read(num_bytes)
|
148
|
+
# convert to offsets in the array
|
149
|
+
start_offset = (@offset * 2)
|
150
|
+
end_offset = start_offset + (num_bytes * 2) - 1
|
151
|
+
|
152
|
+
# Check the alignment and convert if it's Intel align
|
153
|
+
if @alignment == :intel
|
154
|
+
# Convert little to big endian with an atomic element size of 1 byte
|
155
|
+
bytes = @exif_data[start_offset..end_offset].scan(/(..)/).reverse.join
|
156
|
+
else
|
157
|
+
# Assume by default that it's Motorola type align
|
158
|
+
bytes = @exif_data[start_offset..end_offset]
|
159
|
+
end
|
160
|
+
|
161
|
+
@offset += num_bytes
|
162
|
+
bytes
|
163
|
+
end
|
164
|
+
|
165
|
+
# always read big endian
|
166
|
+
def read_at_offset(num_bytes, offset)
|
167
|
+
# convert to offsets in the array
|
168
|
+
start_offset = (offset * 2)
|
169
|
+
end_offset = start_offset + (num_bytes * 2) - 1
|
170
|
+
|
171
|
+
@exif_data[start_offset..end_offset]
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: exif_utility
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jason Wang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Exif Utility is a module for reading Exif information from JPEGs
|
14
|
+
email: jasonbwangjbw@gmail.com
|
15
|
+
executables:
|
16
|
+
- exif_utility
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/exif_utility
|
21
|
+
- lib/exif_utility.rb
|
22
|
+
- lib/exif_utility/data.rb
|
23
|
+
- lib/exif_utility/interpreter.rb
|
24
|
+
- lib/exif_utility/parser.rb
|
25
|
+
homepage: https://github.com/jasonbw/exif_utility
|
26
|
+
licenses:
|
27
|
+
- MIT
|
28
|
+
metadata: {}
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 2.2.1
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: A module for reading Exif information from JPEGs
|
49
|
+
test_files: []
|