exifparser 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7616a451f2f84dd5f7e220b0199f67ca9a193fd3
4
+ data.tar.gz: 9ee05e177cec4badc1c71b6bad7f0e4708688f10
5
+ SHA512:
6
+ metadata.gz: d07432c7dde901cfc613824b40ce74c669d0f378f9c9dbf26848dc0264085d9e84c615d56f6c4279511bf73b6a1635b959711288ba2055f57338ca2e8d891366
7
+ data.tar.gz: d2c2e23601eb550b2d0adfffc9c35c5da88676d023a717ab3667a0bc3777f604125b02ddfb880b365bd195d969c063272d765d20392772127a0bb6ecdb1eccab
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in exifparser.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 kp
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ # Exifparser
2
+
3
+ Exif tag parser written in pure Ruby
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'exifparser'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install exifparser
18
+
19
+ ## Usage
20
+
21
+ see also lib/exifparser.rb
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
30
+
31
+ ## Original Author
32
+ Ryuichi Tamura <r-tam@fsinet.or.jp>
33
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'exifparser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "exifparser"
8
+ spec.version = ExifParser::VERSION
9
+ spec.authors = ["kp"]
10
+ spec.email = ["knomura.1394@gmail.com"]
11
+ spec.description = %q{Exif tag parser written in pure Ruby}
12
+ spec.summary = %q{Exif tag parser written in pure Ruby}
13
+ spec.homepage = ""
14
+ spec.license = "Ruby"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,265 @@
1
+ #
2
+ #
3
+ #= exifparser.rb - Exif tag parser written in pure ruby
4
+ #
5
+ #Author:: Ryuchi Tamura (r-tam@fsinet.or.jp)
6
+ #Copyright:: Copyright (C) 2002 Ryuichi Tamura.
7
+ #
8
+ # $Id: exifparser.rb,v 1.1.1.1 2002/12/16 07:59:00 tam Exp $
9
+ #
10
+ #== INTRODUCTION
11
+ #
12
+ #There are 2 classes you work with. ExifParser class is
13
+ #the Exif tag parser that parses all tags defined EXIF-2.2 standard,
14
+ #and many of extension tags uniquely defined by some digital equipment
15
+ #manufacturers. Currently, part of tags defined by FujiFilm, and
16
+ #Olympus is supported. After initialized with the path to image file
17
+ #of EXIF format, ExifParser will provides which tags are available in
18
+ #the image, and how you work with them.
19
+ #
20
+ #Tags availble from ExifParser is objects defined under Exif::Tag module,
21
+ #with its name being the class name. For example if you get "Make" tag
22
+ #from ExifParser, it is Exif::Tag::DateTime object. Inspecting it looks
23
+ #following:
24
+ #
25
+ # #<Exif::Tag::TIFF::Make ID=0x010f, IFD="IFD0" Name="Make", Format="Ascii" Value="FUJIFILM">
26
+ #
27
+ #here, ID is Tag ID defined in EXIF-2.2 standard, IFD is the name of
28
+ #Image File Directory, Name is String representation of tag ID, Format is
29
+ #string that shows how the data is formatted, and Value is the value of
30
+ #the tag. This is retrieved by Exif::Tag::Make#value.
31
+ #
32
+ #Another example. If you want to know whether flash was fired when the image
33
+ #was generated, ExifParser returns Exif::Tag::Flash object:
34
+ #
35
+ # tag = exif['Flash']
36
+ # p tag
37
+ # => #<Exif::Tag::Exif::Flash ID=0x9209, IFD="Exif" Name="Flash", Format="Unsigned short" Value="1">
38
+ # p tag.value
39
+ # => 1
40
+ #
41
+ #It may happen that diffrent IFDs have the same tag name. In this case,
42
+ #use Exif#tag(tagname, IFD)
43
+ #
44
+ #The value of the tag above, 1, is not clearly understood
45
+ #(supposed to be 'true', though). Exif::Tag::Flash#to_s will provides
46
+ #more human-readable form as String.
47
+ #
48
+ # tag.to_s #=> "Flash fired."
49
+ #
50
+ #many of these sentences are cited from Exif-2.2 standard.
51
+ #
52
+ #== USAGE
53
+ # require 'exifparser'
54
+ #
55
+ # exif = ExifParser.new("fujifilm.jpg")
56
+ #
57
+ # 1. get a tag value by its name('Make') or its ID (0x010f)
58
+ # exif['Make'] #=> 'FUJIFILM'
59
+ # exif[0x010f] #=> 'FUJIFILM'
60
+ #
61
+ # if the specified tag is not found, nil is returned.
62
+ #
63
+ # 2. to see the image has the value of specified tag
64
+ # exif.tag?('DateTime') #=> true
65
+ # exif.tag?('CameraID') #=> false
66
+ #
67
+ # 3. get all the tags contained in the image.
68
+ #
69
+ # exif.tags
70
+ #
71
+ # or, if you want to know all the tags defined in specific IFD,
72
+ #
73
+ # exif.tags(:IFD0) # get all the tags defined in IFD0
74
+ #
75
+ # you can traverse each tag and work on it.
76
+ #
77
+ # exif.each do |tag|
78
+ # p tag.to_s
79
+ # end
80
+ #
81
+ # # each tag in IFD0
82
+ # exif.each(:IFD0) do |ifd0_tag|
83
+ # p ifd0_tag.to_s
84
+ # end
85
+ #
86
+ # 4. extract thumbnail
87
+ #
88
+ # File.open("thumb.jpg") do |dest|
89
+ # exif.thumbnail dest
90
+ # end
91
+ #
92
+ # dest object must respond to '<<'.
93
+ #
94
+ require 'exifparser/scan'
95
+
96
+ module Exif
97
+
98
+ class Parser
99
+ #
100
+ # create a new object. fpath is String.
101
+ #
102
+ def initialize(fpath)
103
+ @fpath = fpath
104
+ @scanner = nil
105
+ File.open(fpath, "rb") do |f|
106
+ @scanner = Exif::Scanner.new(f)
107
+ @scanner.scan
108
+ end
109
+ @IFD0 = @scanner.result[:IFD0]
110
+ @IFD1 = @scanner.result[:IFD1]
111
+ @Exif = @scanner.result[:Exif]
112
+ @GPS = @scanner.result[:GPS]
113
+ @Interoperability = @scanner.result[:Interoperability]
114
+ @MakerNote = @scanner.result[:MakerNote]
115
+ @thumbnail = @scanner.result[:Thumbnail]
116
+ end
117
+
118
+ def inspect
119
+ sprintf("#<%s filename=\"%s\" entries: IFD0(%d) IFD1(%d) Exif(%d) GPS(%d) Interoperability(%d) MakerNote(%d)>", self.class, @fpath, @IFD0.length, @IFD1.length, @Exif.length, @GPS.length, @Interoperability.length, @MakerNote.length)
120
+ end
121
+
122
+ #
123
+ # return true if specified tagid is defined or has some value.
124
+ #
125
+ def tag?(tagid)
126
+ search_tag(tagid) ? true : false
127
+ end
128
+
129
+ #
130
+ # search tag on the specific IFD
131
+ #
132
+ def tag(tagname, ifd=nil)
133
+ search_tag(tagname, ifd)
134
+ end
135
+
136
+ #
137
+ # search the specified tag values. return value is object of
138
+ # classes defined under Exif::Tag module.
139
+ #
140
+ def [](tagname)
141
+ self.tag(tagname)
142
+ end
143
+
144
+ #
145
+ # set the specified tag to the specified value.
146
+ # XXX NOT IMPLEMETED XXX
147
+ #
148
+ def []=(tag, value)
149
+ # not implemented
150
+ end
151
+
152
+ #
153
+ # extract the thumbnail image to dest. dest should respond to
154
+ # '<<' method.
155
+ #
156
+ def thumbnail(dest)
157
+ dest << @thumbnail
158
+ end
159
+
160
+ #
161
+ # return the size of the thumbnail image
162
+ #
163
+ def thumbnail_size
164
+ @thumbnail.size
165
+ end
166
+
167
+ #
168
+ # return all the tags in the image.
169
+ #
170
+ # if argument ifd is specified, every tags defined in the
171
+ # specified IFD are passed to block.
172
+ #
173
+ # return value is object of classes defined under Exif::Tag module.
174
+ #
175
+ # allowable arguments are:
176
+ # * :IFD0
177
+ # * :IFD1
178
+ # * :Exif
179
+ # * :GPS
180
+ # * :Interoperability
181
+ # * :MakerNote (if exist)
182
+ def tags(ifd=nil)
183
+ if ifd
184
+ @scanner.result[ifd]
185
+ else
186
+ [
187
+ @IFD0,
188
+ @IFD1,
189
+ @Exif,
190
+ @GPS,
191
+ @Interoperability,
192
+ @MakerNote
193
+ ].flatten
194
+ end
195
+ end
196
+
197
+ #
198
+ # execute given block with block argument being every tags defined
199
+ # in all the IFDs contained in the image.
200
+ #
201
+ # if argument ifd is specified, every tags defined in the
202
+ # specified IFD are passed to block.
203
+ #
204
+ # return value is object of classes defined under Exif::Tag module.
205
+ #
206
+ # allowable arguments are:
207
+ # * :IFD0
208
+ # * :IFD1
209
+ # * :Exif
210
+ # * :GPS
211
+ # * :Interoperability
212
+ # * :MakerNote
213
+ def each(ifd=nil)
214
+ if ifd
215
+ @scanner.result[ifd].each{ |tag| yield tag }
216
+ else
217
+ [
218
+ @IFD0,
219
+ @IFD1,
220
+ @Exif,
221
+ @GPS,
222
+ @Interoperability,
223
+ @MakerNote
224
+ ].flatten.each do |tag|
225
+ yield tag
226
+ end
227
+ end
228
+ end
229
+
230
+ private
231
+
232
+ def search_tag(tagID, ifd=nil)
233
+ if ifd
234
+ @scanner.result(ifd).find do |tag|
235
+ case tagID
236
+ when Fixnum
237
+ tag.tagID.hex == tagID
238
+ when String
239
+ tag.name == tagID
240
+ end
241
+ end
242
+ else
243
+ [
244
+ @IFD0,
245
+ @IFD1,
246
+ @Exif,
247
+ @GPS,
248
+ @Interoperability,
249
+ @MakerNote
250
+ ].flatten.find do |tag|
251
+ case tagID
252
+ when Fixnum
253
+ tag.tagID.hex == tagID
254
+ when String
255
+ tag.name == tagID
256
+ end
257
+ end
258
+ end
259
+ end
260
+
261
+ end # module Parser
262
+
263
+ end # module Exif
264
+
265
+ ExifParser = Exif::Parser
@@ -0,0 +1,502 @@
1
+ #
2
+ # exifparser/makernote/nikon.rb -
3
+ #
4
+ # Copyright (C) 2002 Ryuichi Tamura (r-tam@fsinet.or.jp)
5
+ #
6
+ # $Revision: 1.1.1.1 $
7
+ # $Date: 2002/12/16 07:59:00 $
8
+ #
9
+ require 'exifparser/tag'
10
+ require 'exifparser/utils'
11
+
12
+ module Exif
13
+
14
+ module Tag
15
+
16
+ module MakerNote
17
+
18
+ #
19
+ # 0x0000 - Unknown
20
+ #
21
+
22
+ #
23
+ # 0x0001 - Tag0x0001
24
+ #
25
+ class Tag0x0001 < Base
26
+
27
+ def processData
28
+ @formatted = []
29
+ partition_data(@count) do |part|
30
+ @formatted.push _formatData(part)
31
+ end
32
+ end
33
+
34
+ def value
35
+ numTags = @formatted[0] / 2
36
+ ret = {}
37
+
38
+ return ret if numTags < 2
39
+ #
40
+ # offset 1 : Macro mode
41
+ #
42
+ ret["Macro mode"] =
43
+ case @formatted[1]
44
+ when 1
45
+ "Macro"
46
+ when 2
47
+ "Normal"
48
+ else
49
+ "Unknown"
50
+ end
51
+
52
+ return ret if numTags < 3
53
+ #
54
+ # offset 2 : if nonzero, length of self-timer in 10ths of a second.
55
+ #
56
+ selftimer_length = @formatted[2]
57
+
58
+ return ret if numTags < 5
59
+ #
60
+ # offset 4 : Flash mode
61
+ #
62
+ ret["Flash mode"] =
63
+ case @formatted[4]
64
+ when 0
65
+ "flash not fired"
66
+ when 1
67
+ "auto"
68
+ when 2
69
+ "on"
70
+ when 3
71
+ "red-eye reduction"
72
+ when 4
73
+ "slow synchro"
74
+ when 5
75
+ "auto + redeye reduction"
76
+ when 6
77
+ "on + redeye reduction"
78
+ when 16
79
+ "external flash"
80
+ else
81
+ "unknown"
82
+ end
83
+
84
+ return ret if numTags < 6
85
+ #
86
+ # offset 5: Contiuous drive mode
87
+ #
88
+ ret["Continuous drive mode"] =
89
+ case @formatted[5]
90
+ when 0
91
+ if selftimer_length != 0
92
+ "Timer = #{selftimer_length/10.0}sec."
93
+ else
94
+ "Single"
95
+ end
96
+ when 1
97
+ "Continuous"
98
+ end
99
+
100
+ return ret if numTags < 8
101
+ #
102
+ # offset 7: Focus Mode
103
+ #
104
+ ret["Focus Mode"] =
105
+ case @formatted[7]
106
+ when 0
107
+ "One-Shot"
108
+ when 1
109
+ "AI Servo"
110
+ when 2
111
+ "AI Focus"
112
+ when 3
113
+ "MF"
114
+ when 4
115
+ "Single"
116
+ when 5
117
+ "Continuous"
118
+ when 6
119
+ "MF"
120
+ else
121
+ "Unknown"
122
+ end
123
+
124
+ return ret if numTags < 11
125
+ #
126
+ # offset 10: Image size
127
+ #
128
+ ret["Image Size"] =
129
+ case @formatted[10]
130
+ when 0
131
+ "Large"
132
+ when 1
133
+ "Medium"
134
+ when
135
+ "Small"
136
+ else
137
+ "Unknown"
138
+ end
139
+
140
+ return ret if numTags < 12
141
+ #
142
+ # offset 11: "Easy shooting" mode
143
+ #
144
+ ret["Easy shooting mode"] =
145
+ case @formatted[11]
146
+ when 0
147
+ "Full auto"
148
+ when 1
149
+ "Manual"
150
+ when 2
151
+ "Landscape"
152
+ when 3
153
+ "Fast Shutter"
154
+ when 4
155
+ "Slow Shutter"
156
+ when 5
157
+ "Night"
158
+ when 6
159
+ "B&W"
160
+ when 7
161
+ "Sepia"
162
+ when 8
163
+ "Portrait"
164
+ when 9
165
+ "Sports"
166
+ when 10
167
+ "Macro / Close-Up"
168
+ when 11
169
+ "Pan Focus"
170
+ else
171
+ "Unknown"
172
+ end
173
+
174
+ return ret if numTags < 14
175
+ #
176
+ # offset 13: Contrast
177
+ #
178
+ ret["Contrast"] =
179
+ case @formatted[13]
180
+ when 0xffff
181
+ "Low"
182
+ when 0x0000
183
+ "Normal"
184
+ when 0x0001
185
+ "High"
186
+ else
187
+ "Unknown"
188
+ end
189
+
190
+ return ret if numTags < 15
191
+ #
192
+ # offset 14: Saturation
193
+ #
194
+ ret["Saturation"] =
195
+ case @formatted[14]
196
+ when 0xffff
197
+ "Low"
198
+ when 0x0000
199
+ "Normal"
200
+ when 0x0001
201
+ "High"
202
+ else
203
+ "Unknown"
204
+ end
205
+
206
+ return ret if numTags < 16
207
+ #
208
+ # offset 15: Contrast
209
+ #
210
+ ret["Sharpness"] =
211
+ case @formatted[15]
212
+ when 0xffff
213
+ "Low"
214
+ when 0x0000
215
+ "Normal"
216
+ when 0x0001
217
+ "High"
218
+ else
219
+ "Unknown"
220
+ end
221
+
222
+ return ret if numTags < 17
223
+ #
224
+ # offset 16: ISO
225
+ #
226
+ ret["ISO"] =
227
+ case @formatted[16]
228
+ when 0
229
+ "ISOSpeedRatings"
230
+ when 15
231
+ "Auto"
232
+ when 16
233
+ 50
234
+ when 17
235
+ 100
236
+ when 18
237
+ 200
238
+ when 19
239
+ 400
240
+ else
241
+ "Unknown"
242
+ end
243
+
244
+ return ret if numTags < 18
245
+ #
246
+ # offset 17: Metering mode
247
+ #
248
+ ret['Metering mode'] =
249
+ case @formatted[17]
250
+ when 3
251
+ "Evaluative"
252
+ when 4
253
+ "Partial"
254
+ when 5
255
+ "Center-weighted"
256
+ else
257
+ "Unknown"
258
+ end
259
+ ret
260
+ end
261
+
262
+ end
263
+
264
+ #
265
+ # 0x0003 - Tag0x0003
266
+ #
267
+ class Tag0x0003 < Base
268
+ end
269
+
270
+ #
271
+ # 0x0004 - Tag0x0004
272
+ #
273
+ class Tag0x0004 < Base
274
+
275
+ def processData
276
+ @formatted = []
277
+ partition_data(@count) do |part|
278
+ @formatted.push _formatData(part)
279
+ end
280
+ end
281
+
282
+ def value
283
+ numTags = @formatted[0] / 2
284
+ ret = {}
285
+
286
+ return hash if numTags < 8
287
+ # offset 7 : white balance
288
+ ret['White balance'] =
289
+ case @formatted[7]
290
+ when 0
291
+ "Auto"
292
+ when 1
293
+ "Sunny"
294
+ when 2
295
+ "Cloudy"
296
+ when 3
297
+ "Tungsten"
298
+ when 4
299
+ "Florescent"
300
+ when 5
301
+ "Flash"
302
+ when 6
303
+ "Custom"
304
+ else
305
+ "Unknown"
306
+ end
307
+
308
+ return ret if numTags < 10
309
+ # offset 9: Sequence number (if in a continuous burst)
310
+ ret['Sequence number'] = @formatted[9]
311
+
312
+ return ret if numTags < 15
313
+ # offset 14: Auto Focus point used
314
+ ret['Auto Focus point used'] = @formatted[14]
315
+
316
+ return ret if numTags < 16
317
+ ret['Flash bias'] =
318
+ case @formatted[15]
319
+ when 0xffc0
320
+ "-2 EV"
321
+ when 0xffcc
322
+ "-1.67 EV"
323
+ when 0xffd0
324
+ "-1.50 EV"
325
+ when 0xffd4
326
+ "-1.33 EV"
327
+ when 0xffe0
328
+ "-1 EV"
329
+ when 0xffec
330
+ "-0.67 EV"
331
+ when 0xfff0
332
+ "-0.50 EV"
333
+ when 0xfff4
334
+ "-0.33 EV"
335
+ when 0x0000
336
+ "0 EV"
337
+ when 0x000c
338
+ "0.33 EV"
339
+ when 0x0010
340
+ "0.50 EV"
341
+ when 0x0014
342
+ "0.67 EV"
343
+ when 0x0020
344
+ "1 EV"
345
+ when 0x002c
346
+ "1.33 EV"
347
+ when 0x0030
348
+ "1.50 EV"
349
+ when 0x0034
350
+ "1.67 EV"
351
+ when 0x0040
352
+ "2 EV"
353
+ else
354
+ "Unknown"
355
+ end
356
+
357
+ return ret if numTags < 20
358
+ ret['Subject Distance'] = @formatted[19]
359
+
360
+ ret
361
+ end
362
+
363
+ end
364
+
365
+ #
366
+ # 0x0006 - ImageType
367
+ #
368
+ class ImageType < Base
369
+ end
370
+
371
+ #
372
+ # 0x0007 - FirmwareVersion
373
+ #
374
+ class FirmwareVersion < Base
375
+ end
376
+
377
+ #
378
+ # 0x0008 - ImageNumber
379
+ #
380
+ class ImageNumber < Base
381
+ end
382
+
383
+ #
384
+ # 0x0009 - OwnerName
385
+ #
386
+ class OwnerName < Base
387
+ end
388
+
389
+ #
390
+ # 0x000a - Unknown
391
+ #
392
+
393
+ #
394
+ # 0x000c - CameraSerialNumber
395
+ #
396
+ class CameraSerialNumber < Base
397
+
398
+ def to_s
399
+ hi = @formatted / 0x10000
400
+ low = @formatted % 0x10000
401
+ "%04X%05d"%[hi, low]
402
+ end
403
+
404
+ end
405
+
406
+ #
407
+ # 0x000d - Unknown
408
+ #
409
+
410
+ #
411
+ # 0x000f - CustomFunctions
412
+ #
413
+ class CustomFunctions < Base
414
+
415
+ def processData
416
+ @formatted = []
417
+ partition_data(@count) do |part|
418
+ @formatted.push _formatData(part)
419
+ end
420
+ end
421
+
422
+ end
423
+
424
+ end
425
+
426
+ CanonIFDTable = {
427
+ 0x0000 => Unknown,
428
+ 0x0001 => MakerNote::Tag0x0001,
429
+ 0x0003 => MakerNote::Tag0x0003,
430
+ 0x0004 => MakerNote::Tag0x0004,
431
+ 0x0006 => MakerNote::ImageType,
432
+ 0x0007 => MakerNote::FirmwareVersion,
433
+ 0x0008 => MakerNote::ImageNumber,
434
+ 0x0009 => MakerNote::OwnerName,
435
+ 0x000a => Unknown,
436
+ 0x000c => MakerNote::CameraSerialNumber,
437
+ 0x000d => Unknown,
438
+ 0x000f => MakerNote::CustomFunctions
439
+ }
440
+
441
+ end
442
+
443
+ class Canon
444
+
445
+ def initialize(fin, tiff_origin, dataPos, byteOrder_module)
446
+ @fin = fin
447
+ @tiffHeader0 = tiff_origin
448
+ @dataPos = dataPos
449
+ @byteOrder_module = byteOrder_module
450
+ self.extend @byteOrder_module
451
+ end
452
+
453
+ def scan_IFD
454
+ #
455
+ # Canon MakerNote starts from 0
456
+ #
457
+ @fin.pos = @dataPos + 0
458
+ #
459
+ # get the number of tags
460
+ #
461
+ numDirs = decode_ushort(fin_read_n(2))
462
+ #
463
+ # now scan them
464
+ #
465
+ 1.upto(numDirs) {
466
+ curpos_tag = @fin.pos
467
+ tag = parseTagID(fin_read_n(2))
468
+ tagclass = Tag.find(tag.hex, Tag::CanonIFDTable)
469
+ unit, formatter = Tag::Format::Unit[decode_ushort(fin_read_n(2))]
470
+ count = decode_ulong(fin_read_n(4))
471
+ tagdata = fin_read_n(4)
472
+ obj = tagclass.new(tag, "MakerNote", count)
473
+ obj.extend formatter, @byteOrder_module
474
+ obj.pos = curpos_tag
475
+ if unit * count > 4
476
+ curpos = @fin.pos
477
+ begin
478
+ @fin.pos = @tiffHeader0 + decode_ulong(tagdata)
479
+ obj.dataPos = @fin.pos
480
+ obj.data = fin_read_n(unit*count)
481
+ ensure
482
+ @fin.pos = curpos
483
+ end
484
+ else
485
+ obj.dataPos = @fin.pos - 4
486
+ obj.data = tagdata
487
+ end
488
+ obj.processData
489
+ yield obj
490
+ }
491
+ end
492
+
493
+ private
494
+
495
+ def fin_read_n(n)
496
+ @fin.read(n)
497
+ end
498
+
499
+ end
500
+
501
+
502
+ end