leeh-mini_exiftool 1.6.0

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.
@@ -0,0 +1,159 @@
1
+ 1.6.0
2
+ - Type conversion in MiniExiftool.from_hash.
3
+ Thanks to Ethan Soutar-Rau for the merge request.
4
+ - Switching to rim. (No longer troubles with echoe.)
5
+ - Exiftool version detection delayed.
6
+ Thanks to Sebastian Skałacki for the merge request.
7
+ - New method MiniExiftool#save!
8
+ Cherry-picked commit from Wil Gieseler.
9
+
10
+ 1.5.1
11
+ - Make rational values work on Ruby 1.8.7.
12
+
13
+ 1.5.0
14
+ - Supporting exiftool command-line option -m.
15
+ rubyforge request [#29587]
16
+ Thanks to Michael Grove for reporting.
17
+ - Supporting rational values.
18
+
19
+ 1.4.4
20
+ - Fix escaping of values for older versions of Shellwords.
21
+
22
+ 1.4.3
23
+ - Fixing rubyforge bug [#29596] (Quotes in values)
24
+ Thanks to Michael Grove for reporting
25
+
26
+ 1.4.2
27
+ - Add .yardopts file to gem.
28
+
29
+ 1.4.1
30
+ - Update documentation for using yard.
31
+
32
+ 1.4.0
33
+ - Allow symbols for tag access with [].
34
+ - Refactoring tests.
35
+
36
+ 1.3.1
37
+ - Remove TestEscapeFilename test and releating test photo
38
+ because the latter produces errors on windows systems.
39
+ - Version check in prerelease task.
40
+
41
+ 1.3.0
42
+ - MiniExiftool is now ready for Ruby 1.9
43
+ All tests in the test suite pass. :)
44
+
45
+ 1.2.2
46
+ - Fixing ptore directory naming convention for darwin.
47
+ Thanks to Denis Barushev for the hint.
48
+
49
+ 1.2.1
50
+ - Switching to echoe.
51
+ - Update e-mail address.
52
+
53
+ 1.2.0
54
+ - Fixing time zone handling.
55
+ Thanks to ccoenen for the hint.
56
+
57
+ 1.1.0
58
+ - Escaping filenames in shell commands
59
+ Thanks to Michael Hoy for the hint and implementing a patch which was
60
+ the base for this fix.
61
+
62
+ 1.0.2
63
+ - Fixing warings
64
+ Thanks to Peter-Hinrich Krogmann for the hint.
65
+
66
+ 1.0.1
67
+ - Fixing bug [#22726]
68
+ Making MiniExiftool::Error public.
69
+ Thanks to Mathias Stjernstrom for sending a patch.
70
+
71
+ 1.0.0
72
+ - Be aware changing in the interface:
73
+ - List tags (e.g. Keywords, SupplementalCategories) are now handled as
74
+ arrays.
75
+ - Tag SubjectLocation is not longer an array value but a string value!
76
+
77
+ 0.7.0
78
+ - Changing composite behaviour: Composite tags are now included as standard!
79
+ - New method MiniExiftool.opts which returns a hash of the standard
80
+ options used for MiniExiftool.new
81
+ - New option :convert_encoding for MiniExiftool.new which uses the -L-option
82
+ of the exiftool command-line application (see online documentation for it)
83
+ Thanks to Henning Kulander for the causing of this change.
84
+
85
+ 0.6.0
86
+ - New methods for serialization:
87
+ - MiniExiftool.from_hash
88
+ - MiniExiftool.from_yaml
89
+ - MiniExiftool#to_hash
90
+ - MiniExiftool#to_yaml
91
+ Thanks to Andrew Bennett for the initial idea of YAML-serialization
92
+ - Refactoring of tests
93
+ - Small documetation update
94
+
95
+ 0.5.1
96
+ - Warning "parenthesize argument(s) for future version" removed
97
+ Thanks to Greg from knobby.ws
98
+
99
+ 0.5.0
100
+ - New option :timestamps to create DateTime objects instead of Time objects
101
+ for timestamps (Fixing bug #16328)
102
+ - Invalid values of timestamps (i.e. 0000:00:00 00:00:00) are now mapped
103
+ to false
104
+
105
+ 0.4.1
106
+ - Compatibility for Ruby 1.9
107
+
108
+ 0.4.0
109
+ - MiniExiftool::Error inherits now from StandardError
110
+ - Alternative installation via setup.rb
111
+ - Bugfix
112
+ Saving of non-read tags doesn't work with tags with hyphen
113
+ Thanks to Robin Romahn for reporting the bug
114
+ - New methods: MiniExiftool.all_tags and MiniExiftool.original_tag
115
+ - Interna: Original tag names (all and writable) are now saved via pstore in
116
+ a file for better performance
117
+
118
+ 0.3.1
119
+ - Typos fixed
120
+
121
+ 0.3.0
122
+ - Documentation completed and a Mini Tutorial added
123
+ - Interface changes:
124
+ - Test if a value for a tag can be saved is now done in
125
+ MiniExiftool#save
126
+ => There is no check at the moment you set a value:
127
+ the tag occurs in MiniExiftool#changed_values
128
+ => While calling MiniExiftool#save errors can occur (see next point)
129
+ - MiniExiftool#save is a transaction: if one or more error occurs the file is
130
+ not changed! In such a case the errors can be found in MiniExiftool#errors
131
+ - Parameter opts of MiniExiftool.initialize is now a Hash with two options:
132
+ - :numerical => read metadata as numerical values
133
+ - :composite => read also composite tags
134
+ - Tests added
135
+
136
+ 0.2.0
137
+ - Better error handling (i.e. error messages)
138
+ - Checking if the exiftool command can be executed at loading the lib
139
+ - New class method exiftool_version
140
+ - Added tests
141
+ - Documentation completed
142
+
143
+ 0.1.2
144
+ - Bugfix for Windows (Tempfile)
145
+ Thanks to Jérome Soika for testing
146
+ - Regexes optimized (a little bit)
147
+ - New class-method MiniExiftool.writable_tags
148
+
149
+ 0.1.1
150
+ - Fixing bug [#8073]
151
+ Handling the '-' in tag Self-timer
152
+ Thanks to Eric Young
153
+
154
+ 0.1.0
155
+ - New method "revert"
156
+ - More tests
157
+
158
+ 0.0.1
159
+ - Initial release
@@ -0,0 +1,50 @@
1
+ = MiniExiftool
2
+
3
+ This library is wrapper for the Exiftool command-line application
4
+ (http://www.sno.phy.queensu.ca/~phil/exiftool) written by Phil Harvey.
5
+ Read and write access is done in a clean OO manner.
6
+
7
+ == Requirements
8
+
9
+ An installation of the Exiftool command-line application.
10
+ Instructions for installation you can find under
11
+ http://www.sno.phy.queensu.ca/~phil/exiftool/install.html .
12
+
13
+ Alternatively Wil Gieseler has bundled a meta-gem that eliminates the
14
+ need for a seperate Exiftool installation. Have a look at
15
+ http://github.com/wilg/mini_exiftool_vendored or
16
+ http://rubygems.org/gems/mini_exiftool_vendored .
17
+
18
+ == Installation
19
+
20
+ First you need Exiftool (see under Requirements above). Then you can simply
21
+ install the gem with
22
+ gem install mini_exiftool
23
+ respectively (on *nix sytems)
24
+ sudo gem install mini_exiftool
25
+
26
+ Alternative you can download the tarball or zip file and run
27
+ ruby setup.rb config
28
+ ruby setup.rb setup
29
+ sudo ruby setup.rb install
30
+
31
+ == Contribution
32
+
33
+ The code is also hostet in a git repository on Gitorious at
34
+ http://gitorious.org/projects/mini_exiftool
35
+ feel free to contribute!
36
+
37
+ == Author
38
+ Jan Friedrich <janfri26 AT gmail DOT com>
39
+
40
+ == Copyright / License
41
+ Copyright (c) 2007-2011 by Jan Friedrich
42
+
43
+ Licensed under terms of the GNU LESSER GENERAL PUBLIC LICENSE, Version 2.1,
44
+ February 1999 (see file COPYING for more details)
45
+
46
+ == Usage
47
+
48
+ For further information about using MiniExiftool read the
49
+ Tutorial[link://file.Tutorial.html] and have a look at the examples in
50
+ directory examples.
@@ -0,0 +1,23 @@
1
+ require 'rim'
2
+ require 'rim/check_version'
3
+ require 'rim/gem'
4
+ require 'rim/test'
5
+
6
+ $:.unshift 'lib'
7
+ require 'mini_exiftool'
8
+
9
+ Rim.setup do |p|
10
+ p.name = 'leeh-mini_exiftool'
11
+ p.version = MiniExiftool::VERSION
12
+ p.authors = 'Jan Friedrich'
13
+ p.email = 'janfri26@gmail.com'
14
+ p.summary = 'This library is wrapper for the Exiftool command-line application (http://www.sno.phy.queensu.ca/~phil/exiftool).'
15
+ p.homepage = 'http://gitorious.org/mini_exiftool'
16
+ p.install_message = %q{
17
+ +-----------------------------------------------------------------------+
18
+ | Please ensure you have installed exiftool and it's found in your PATH |
19
+ | (Try "exiftool -ver" on your commandline). For more details see |
20
+ | http://www.sno.phy.queensu.ca/~phil/exiftool/install.html |
21
+ +-----------------------------------------------------------------------+
22
+ }
23
+ end
@@ -0,0 +1,464 @@
1
+ # -- encoding: utf-8 --
2
+ #
3
+ # MiniExiftool
4
+ #
5
+ # This library is wrapper for the Exiftool command-line
6
+ # application (http://www.sno.phy.queensu.ca/~phil/exiftool/)
7
+ # written by Phil Harvey.
8
+ # Read and write access is done in a clean OO manner.
9
+ #
10
+ # Author: Jan Friedrich
11
+ # Copyright (c) 2007-2012 by Jan Friedrich
12
+ # Licensed under the GNU LESSER GENERAL PUBLIC LICENSE,
13
+ # Version 2.1, February 1999
14
+ #
15
+
16
+ require 'fileutils'
17
+ require 'tempfile'
18
+ require 'pstore'
19
+ require 'rational'
20
+ require 'set'
21
+ require 'shellwords'
22
+ require 'time'
23
+
24
+ # Simple OO access to the Exiftool command-line application.
25
+ class MiniExiftool
26
+
27
+ # Name of the Exiftool command-line application
28
+ @@cmd = 'exiftool'
29
+
30
+ # Hash of the standard options used when call MiniExiftool.new
31
+ @@opts = { :numerical => false, :composite => true, :convert_encoding => false, :ignore_minor_errors => false, :timestamps => Time }
32
+
33
+ attr_reader :filename
34
+ attr_accessor :numerical, :composite, :convert_encoding, :ignore_minor_errors, :errors, :timestamps
35
+
36
+ VERSION = '1.6.0'
37
+
38
+ # +opts+ support at the moment
39
+ # * <code>:numerical</code> for numerical values, default is +false+
40
+ # * <code>:composite</code> for including composite tags while loading,
41
+ # default is +true+
42
+ # * <code>:convert_encoding</code> convert encoding (See -L-option of
43
+ # the exiftool command-line application, default is +false+)
44
+ # * <code>:ignore_minor_errors</code> ignore minor errors (See -m-option
45
+ # of the exiftool command-line application, default is +false+)
46
+ # * <code>:timestamps</code> generating DateTime objects instead of
47
+ # Time objects if set to <code>DateTime</code>, default is +Time+
48
+ #
49
+ # <b>ATTENTION:</b> Time objects are created using <code>Time.local</code>
50
+ # therefore they use <em>your local timezone</em>, DateTime objects instead
51
+ # are created <em>without timezone</em>!
52
+ def initialize filename=nil, opts={}
53
+ opts = @@opts.merge opts
54
+ @numerical = opts[:numerical]
55
+ @composite = opts[:composite]
56
+ @convert_encoding = opts[:convert_encoding]
57
+ @ignore_minor_errors = opts[:ignore_minor_errors]
58
+ @timestamps = opts[:timestamps]
59
+ @coord_format = opts[:coord_format]
60
+ @values = TagHash.new
61
+ @tag_names = TagHash.new
62
+ @changed_values = TagHash.new
63
+ @errors = TagHash.new
64
+ load filename unless filename.nil?
65
+ end
66
+
67
+ def initialize_from_hash hash # :nodoc:
68
+ hash.each_pair do |tag,value|
69
+ set_value tag, perform_conversions(value)
70
+ end
71
+ set_attributes_by_heuristic
72
+ self
73
+ end
74
+
75
+ # Load the tags of filename.
76
+ def load filename
77
+ MiniExiftool.setup
78
+ unless filename && File.exist?(filename)
79
+ raise MiniExiftool::Error.new("File '#{filename}' does not exist.")
80
+ end
81
+ if File.directory?(filename)
82
+ raise MiniExiftool::Error.new("'#{filename}' is a directory.")
83
+ end
84
+ @filename = filename
85
+ @values.clear
86
+ @tag_names.clear
87
+ @changed_values.clear
88
+ opt_params = ''
89
+ opt_params << (@numerical ? '-n ' : '')
90
+ opt_params << (@composite ? '' : '-e ')
91
+ opt_params << (@convert_encoding ? '-L ' : '')
92
+ opt_params << (@coord_format ? "-c \"#{@coord_format}\"" : '')
93
+ cmd = %Q(#@@cmd -q -q -s -t #{opt_params} #{@@sep_op} #{Shellwords.escape(filename)})
94
+ if run(cmd)
95
+ parse_output
96
+ else
97
+ raise MiniExiftool::Error.new(@error_text)
98
+ end
99
+ self
100
+ end
101
+
102
+ # Reload the tags of an already read file.
103
+ def reload
104
+ load @filename
105
+ end
106
+
107
+ # Returns the value of a tag.
108
+ def [] tag
109
+ @changed_values[tag] || @values[tag]
110
+ end
111
+
112
+ # Set the value of a tag.
113
+ def []=(tag, val)
114
+ @changed_values[tag] = val
115
+ end
116
+
117
+ # Returns true if any tag value is changed or if the value of a
118
+ # given tag is changed.
119
+ def changed? tag=false
120
+ if tag
121
+ @changed_values.include? tag
122
+ else
123
+ !@changed_values.empty?
124
+ end
125
+ end
126
+
127
+ # Revert all changes or the change of a given tag.
128
+ def revert tag=nil
129
+ if tag
130
+ val = @changed_values.delete(tag)
131
+ res = val != nil
132
+ else
133
+ res = @changed_values.size > 0
134
+ @changed_values.clear
135
+ end
136
+ res
137
+ end
138
+
139
+ # Returns an array of the tags (original tag names) of the read file.
140
+ def tags
141
+ @values.keys.map { |key| @tag_names[key] }
142
+ end
143
+
144
+ # Returns an array of all changed tags.
145
+ def changed_tags
146
+ @changed_values.keys.map { |key| MiniExiftool.original_tag(key) }
147
+ end
148
+
149
+ # Save the changes to the file.
150
+ def save
151
+ MiniExiftool.setup
152
+ return false if @changed_values.empty?
153
+ @errors.clear
154
+ temp_file = Tempfile.new('mini_exiftool')
155
+ temp_file.close
156
+ temp_filename = temp_file.path
157
+ FileUtils.cp filename, temp_filename
158
+ all_ok = true
159
+ @changed_values.each do |tag, val|
160
+ original_tag = MiniExiftool.original_tag(tag)
161
+ arr_val = val.kind_of?(Array) ? val : [val]
162
+ arr_val.map! {|e| convert e}
163
+ tag_params = ''
164
+ arr_val.each do |v|
165
+ tag_params << %Q(-#{original_tag}=#{Shellwords.escape(v.to_s)} )
166
+ end
167
+ opt_params = ''
168
+ opt_params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '')
169
+ opt_params << (@convert_encoding ? '-L ' : '')
170
+ opt_params << (@ignore_minor_errors ? '-m' : '')
171
+ cmd = %Q(#@@cmd -q -P -overwrite_original #{opt_params} #{tag_params} #{temp_filename})
172
+ if convert_encoding && cmd.respond_to?(:encode)
173
+ cmd.encode('ISO-8859-1')
174
+ end
175
+ result = run(cmd)
176
+ unless result
177
+ all_ok = false
178
+ @errors[tag] = @error_text.gsub(/Nothing to do.\n\z/, '').chomp
179
+ end
180
+ end
181
+ if all_ok
182
+ FileUtils.cp temp_filename, filename
183
+ reload
184
+ end
185
+ temp_file.delete
186
+ all_ok
187
+ end
188
+
189
+ def save!
190
+ unless save
191
+ err = []
192
+ self.errors.each do |key, value|
193
+ err << "(#{key}) #{value}"
194
+ end
195
+ raise MiniExiftool::Error.new("MiniExiftool couldn't save. The following errors occurred: #{err.empty? ? "None" : err.join(", ")}")
196
+ end
197
+ end
198
+
199
+ # Returns a hash of the original loaded values of the MiniExiftool
200
+ # instance.
201
+ def to_hash
202
+ result = {}
203
+ @values.each do |k,v|
204
+ result[@tag_names[k]] = v
205
+ end
206
+ result
207
+ end
208
+
209
+ # Returns a YAML representation of the original loaded values of the
210
+ # MiniExiftool instance.
211
+ def to_yaml
212
+ to_hash.to_yaml
213
+ end
214
+
215
+ # Create a MiniExiftool instance from a hash. Default value conversions will be applied if neccesary.
216
+ def self.from_hash hash
217
+ instance = MiniExiftool.new
218
+ instance.initialize_from_hash hash
219
+ instance
220
+ end
221
+
222
+ # Create a MiniExiftool instance from YAML data created with
223
+ # MiniExiftool#to_yaml
224
+ def self.from_yaml yaml
225
+ MiniExiftool.from_hash YAML.load(yaml)
226
+ end
227
+
228
+ # Returns the command name of the called Exiftool application.
229
+ def self.command
230
+ @@cmd
231
+ end
232
+
233
+ # Setting the command name of the called Exiftool application.
234
+ def self.command= cmd
235
+ @@cmd = cmd
236
+ end
237
+
238
+ # Returns the options hash.
239
+ def self.opts
240
+ @@opts
241
+ end
242
+
243
+ # Returns a set of all known tags of Exiftool.
244
+ def self.all_tags
245
+ unless defined? @@all_tags
246
+ @@all_tags = pstore_get :all_tags
247
+ end
248
+ @@all_tags
249
+ end
250
+
251
+ # Returns a set of all possible writable tags of Exiftool.
252
+ def self.writable_tags
253
+ unless defined? @@writable_tags
254
+ @@writable_tags = pstore_get :writable_tags
255
+ end
256
+ @@writable_tags
257
+ end
258
+
259
+ # Returns the original Exiftool name of the given tag
260
+ def self.original_tag tag
261
+ unless defined? @@all_tags_map
262
+ @@all_tags_map = pstore_get :all_tags_map
263
+ end
264
+ @@all_tags_map[tag]
265
+ end
266
+
267
+ # Returns the version of the Exiftool command-line application.
268
+ def self.exiftool_version
269
+ output = `#{MiniExiftool.command} -ver 2>&1`
270
+ unless $?.exitstatus == 0
271
+ raise MiniExiftool::Error.new("Command '#{MiniExiftool.command}' not found")
272
+ end
273
+ output.chomp!
274
+ end
275
+
276
+ def self.unify tag
277
+ tag.to_s.gsub(/[-_]/,'').downcase
278
+ end
279
+
280
+ # Exception class
281
+ class MiniExiftool::Error < StandardError; end
282
+
283
+ ############################################################################
284
+ private
285
+ ############################################################################
286
+
287
+ @@setup_done = false
288
+ def self.setup
289
+ return if @@setup_done
290
+ @@error_file = Tempfile.new 'errors'
291
+ @@error_file.close
292
+
293
+ if Float(exiftool_version) < 7.41
294
+ @@separator = ', '
295
+ @@sep_op = ''
296
+ else
297
+ @@separator = '@@'
298
+ @@sep_op = '-sep @@'
299
+ end
300
+ @@setup_done = true
301
+ end
302
+
303
+ def run cmd
304
+ if $DEBUG
305
+ $stderr.puts cmd
306
+ end
307
+ @output = `#{cmd} 2>#{@@error_file.path}`
308
+ if convert_encoding && @output.respond_to?(:force_encoding)
309
+ @output.force_encoding('ISO-8859-1')
310
+ end
311
+ @status = $?
312
+ unless @status.exitstatus == 0
313
+ @error_text = File.readlines(@@error_file.path).join
314
+ return false
315
+ else
316
+ @error_text = ''
317
+ return true
318
+ end
319
+ end
320
+
321
+ def convert val
322
+ case val
323
+ when Time
324
+ val = val.strftime('%Y:%m:%d %H:%M:%S')
325
+ end
326
+ val
327
+ end
328
+
329
+ def method_missing symbol, *args
330
+ tag_name = symbol.id2name
331
+ if tag_name.sub!(/=$/, '')
332
+ self[tag_name] = args.first
333
+ else
334
+ self[tag_name]
335
+ end
336
+ end
337
+
338
+ def parse_output
339
+ @output.each_line do |line|
340
+ tag, value = parse_line line
341
+ set_value tag, value
342
+ end
343
+ end
344
+
345
+ def parse_line line
346
+ if line =~ /^([^\t]+)\t(.*)$/
347
+ tag, value = $1, perform_conversions($2)
348
+ else
349
+ raise MiniExiftool::Error.new("Malformed line #{line.inspect} of exiftool output.")
350
+ end
351
+ return [tag, value]
352
+ end
353
+
354
+ def perform_conversions(value)
355
+ case value
356
+ when /^\d{4}:\d\d:\d\d \d\d:\d\d:\d\d/
357
+ s = value.sub(/^(\d+):(\d+):/, '\1-\2-')
358
+ begin
359
+ if @timestamps == Time
360
+ value = Time.parse(s)
361
+ elsif @timestamps == DateTime
362
+ value = DateTime.parse(s)
363
+ else
364
+ raise MiniExiftool::Error.new("Value #@timestamps not allowed for option timestamps.")
365
+ end
366
+ rescue ArgumentError
367
+ value = false
368
+ end
369
+ when /^\d+\.\d+$/
370
+ value = value.to_f
371
+ when /^0+[1-9]+$/
372
+ # nothing => String
373
+ when /^-?\d+$/
374
+ value = value.to_i
375
+ when %r(^(\d+)/(\d+)$)
376
+ value = Rational($1.to_i, $2.to_i)
377
+ when /^[\d ]+$/
378
+ # nothing => String
379
+ when /#{@@separator}/
380
+ value = value.split @@separator
381
+ end
382
+ value
383
+ end
384
+
385
+ def set_value tag, value
386
+ @tag_names[tag] = tag
387
+ @values[tag] = value
388
+ end
389
+
390
+ def set_attributes_by_heuristic
391
+ self.composite = tags.include?('ImageSize') ? true : false
392
+ self.numerical = self.file_size.kind_of?(Integer) ? true : false
393
+ # TODO: Is there a heuristic to determine @convert_encoding?
394
+ self.timestamps = self.FileModifyDate.kind_of?(DateTime) ? DateTime : Time
395
+ end
396
+
397
+ def temp_filename
398
+ unless @temp_filename
399
+ temp_file = Tempfile.new('mini-exiftool')
400
+ temp_file.close
401
+ FileUtils.cp(@filename, temp_file.path)
402
+ @temp_filename = temp_file.path
403
+ end
404
+ @temp_filename
405
+ end
406
+
407
+ def self.pstore_get attribute
408
+ load_or_create_pstore unless defined? @@pstore
409
+ result = nil
410
+ @@pstore.transaction(true) do |ps|
411
+ result = ps[attribute]
412
+ end
413
+ result
414
+ end
415
+
416
+ def self.load_or_create_pstore
417
+ # This will hopefully work on *NIX and Windows systems
418
+ home = ENV['HOME'] || ENV['HOMEDRIVE'] + ENV['HOMEPATH'] || ENV['USERPROFILE']
419
+ subdir = RUBY_PLATFORM =~ /\bmswin/i ? '_mini_exiftool' : '.mini_exiftool'
420
+ FileUtils.mkdir_p(File.join(home, subdir))
421
+ filename = File.join(home, subdir, 'exiftool_tags_' << exiftool_version.gsub('.', '_') << '.pstore')
422
+ @@pstore = PStore.new filename
423
+ if !File.exist?(filename) || File.size(filename) == 0
424
+ @@pstore.transaction do |ps|
425
+ ps[:all_tags] = all_tags = determine_tags('list')
426
+ ps[:writable_tags] = determine_tags('listw')
427
+ map = {}
428
+ all_tags.each { |k| map[unify(k)] = k }
429
+ ps[:all_tags_map] = map
430
+ end
431
+ end
432
+ end
433
+
434
+ def self.determine_tags arg
435
+ output = `#{@@cmd} -#{arg}`
436
+ lines = output.split(/\n/)
437
+ tags = Set.new
438
+ lines.each do |line|
439
+ next unless line =~ /^\s/
440
+ tags |= line.chomp.split
441
+ end
442
+ tags
443
+ end
444
+
445
+
446
+ # Hash with indifferent access:
447
+ # DateTimeOriginal == datetimeoriginal == date_time_original
448
+ class TagHash < Hash # :nodoc:
449
+ def[] k
450
+ super(unify(k))
451
+ end
452
+ def []= k, v
453
+ super(unify(k), v)
454
+ end
455
+ def delete k
456
+ super(unify(k))
457
+ end
458
+
459
+ def unify tag
460
+ MiniExiftool.unify tag
461
+ end
462
+ end
463
+
464
+ end