exif_utility 0.0.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 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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'exif_utility'
4
+ puts ExifUtility.hi(ARGV[0])
@@ -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: []