mini_exiftool 1.0.2 → 1.1.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.
- data/Changelog +5 -1
- data/lib/mini_exiftool.rb +4 -3
- data/test/data/test 36/"Bench.jpg +0 -0
- data/test/test_class_methods.rb +0 -8
- data/test/test_dumping.rb +0 -10
- data/test/test_escape_filename.rb +25 -0
- data/test/test_read.rb +1 -1
- data/test/test_read_numerical.rb +1 -1
- data/test/test_save.rb +1 -1
- metadata +6 -5
- data/lib/mini_exiftool.new.rb +0 -445
- data/x.rb +0 -3
data/Changelog
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
Version 1.1.0
|
2
|
+
- Escaping filenames in shell commands
|
3
|
+
Thanks to Michael Hoy for the hint and implementing a patch which was
|
4
|
+
the base for this fix.
|
1
5
|
Version 1.0.2
|
2
6
|
- Fixing warings
|
3
|
-
|
7
|
+
Thanks to Peter-Hinrich Krogmann for the hint.
|
4
8
|
Version 1.0.1
|
5
9
|
- Fixing bug [#22726]
|
6
10
|
Making MiniExiftool::Error public.
|
data/lib/mini_exiftool.rb
CHANGED
@@ -16,6 +16,7 @@ require 'fileutils'
|
|
16
16
|
require 'tempfile'
|
17
17
|
require 'pstore'
|
18
18
|
require 'set'
|
19
|
+
require 'shellwords'
|
19
20
|
|
20
21
|
# Simple OO access to the Exiftool command-line application.
|
21
22
|
class MiniExiftool
|
@@ -29,7 +30,7 @@ class MiniExiftool
|
|
29
30
|
attr_reader :filename
|
30
31
|
attr_accessor :numerical, :composite, :convert_encoding, :errors, :timestamps
|
31
32
|
|
32
|
-
VERSION = '1.0
|
33
|
+
VERSION = '1.1.0'
|
33
34
|
|
34
35
|
# +opts+ support at the moment
|
35
36
|
# * <code>:numerical</code> for numerical values, default is +false+
|
@@ -80,7 +81,7 @@ class MiniExiftool
|
|
80
81
|
opt_params << (@numerical ? '-n ' : '')
|
81
82
|
opt_params << (@composite ? '' : '-e ')
|
82
83
|
opt_params << (@convert_encoding ? '-L ' : '')
|
83
|
-
cmd = %Q(#@@cmd -q -q -s -t #{opt_params} #{@@sep_op}
|
84
|
+
cmd = %Q(#@@cmd -q -q -s -t #{opt_params} #{@@sep_op} #{Shellwords.escape(filename)})
|
84
85
|
if run(cmd)
|
85
86
|
parse_output
|
86
87
|
else
|
@@ -156,7 +157,7 @@ class MiniExiftool
|
|
156
157
|
opt_params = ''
|
157
158
|
opt_params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '')
|
158
159
|
opt_params << (@convert_encoding ? '-L ' : '')
|
159
|
-
cmd = %Q(#@@cmd -q -P -overwrite_original #{opt_params} #{tag_params}
|
160
|
+
cmd = %Q(#@@cmd -q -P -overwrite_original #{opt_params} #{tag_params} #{temp_filename})
|
160
161
|
result = run(cmd)
|
161
162
|
unless result
|
162
163
|
all_ok = false
|
Binary file
|
data/test/test_class_methods.rb
CHANGED
@@ -27,14 +27,6 @@ class TestClassMethods < TestCase
|
|
27
27
|
rescue MiniExiftool::Error => e
|
28
28
|
assert_match /File 'not_existing_file' does not exist/, e.message
|
29
29
|
end
|
30
|
-
assert_raises MiniExiftool::Error do
|
31
|
-
MiniExiftool.new __FILE__ # file type wich Exiftool can not handle
|
32
|
-
end
|
33
|
-
begin
|
34
|
-
MiniExiftool.new __FILE__ # file type wich Exiftool can not handle
|
35
|
-
rescue MiniExiftool::Error => e
|
36
|
-
assert_match /Error: Unknown (?:image|file) type/, e.message
|
37
|
-
end
|
38
30
|
end
|
39
31
|
|
40
32
|
def test_command
|
data/test/test_dumping.rb
CHANGED
@@ -76,14 +76,4 @@ class TestDumping < TestCase
|
|
76
76
|
assert_equal true, MiniExiftool.from_yaml(numerical.to_yaml).numerical
|
77
77
|
end
|
78
78
|
|
79
|
-
def test_heuristics_for_restoring_timestamps
|
80
|
-
standard = @mini_exiftool.to_hash
|
81
|
-
timestamps = MiniExiftool.new(@filename_test, :timestamps => DateTime).to_hash
|
82
|
-
assert_equal Time, MiniExiftool.from_hash(standard).timestamps
|
83
|
-
assert_equal DateTime, MiniExiftool.from_hash(timestamps).timestamps
|
84
|
-
# Doesn't work yet.
|
85
|
-
# assert_equal Time, MiniExiftool.from_yaml(standard.to_yaml).timestamps
|
86
|
-
# assert_equal DateTime, MiniExiftool.from_yaml(timestamps.to_yaml).timestamps
|
87
|
-
end
|
88
|
-
|
89
79
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'helpers_for_test'
|
2
|
+
|
3
|
+
class TestEscapeFilename < TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@temp_file = Tempfile.new('test')
|
7
|
+
@temp_file.close
|
8
|
+
@temp_filename = @temp_file.path
|
9
|
+
@org_filename = File.dirname(__FILE__) + '/data/test 36"Bench.jpg'
|
10
|
+
FileUtils.cp(@org_filename, @temp_filename)
|
11
|
+
@mini_exiftool = MiniExiftool.new @temp_filename
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_access
|
15
|
+
assert_equal '36" Bench', @mini_exiftool['description']
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_save
|
19
|
+
desc = 'another bench'
|
20
|
+
@mini_exiftool.description = desc
|
21
|
+
assert @mini_exiftool.save
|
22
|
+
assert_equal desc, @mini_exiftool.description
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/test/test_read.rb
CHANGED
@@ -25,7 +25,7 @@ class TestRead < TestCase
|
|
25
25
|
assert_kind_of Float, @mini_exiftool['MaxApertureValue']
|
26
26
|
assert_kind_of String, @mini_exiftool.flash
|
27
27
|
assert_kind_of Fixnum, @mini_exiftool['ExposureCompensation']
|
28
|
-
assert_kind_of String, @mini_exiftool['SubjectLocation']
|
28
|
+
assert_kind_of String, (@mini_exiftool['SubjectLocation'] || @mini_exiftool['SubjectArea'])
|
29
29
|
assert_kind_of Array, @mini_exiftool['Keywords']
|
30
30
|
assert_kind_of String, @mini_exiftool['SupplementalCategories']
|
31
31
|
assert_kind_of Array, @mini_exiftool['SupplementalCategories'].to_a
|
data/test/test_read_numerical.rb
CHANGED
@@ -22,7 +22,7 @@ class TestReadNumerical < TestCase
|
|
22
22
|
assert_kind_of Fixnum, @mini_exiftool_num.flash
|
23
23
|
assert_kind_of String, @mini_exiftool_num.exif_version
|
24
24
|
assert_kind_of Fixnum, @mini_exiftool_num['ExposureCompensation']
|
25
|
-
assert_kind_of String, @mini_exiftool_num['SubjectLocation']
|
25
|
+
assert_kind_of String, (@mini_exiftool_num['SubjectLocation'] || @mini_exiftool_num['SubjectArea'])
|
26
26
|
assert_kind_of Array, @mini_exiftool_num['Keywords']
|
27
27
|
assert_kind_of String, @mini_exiftool_num['SupplementalCategories']
|
28
28
|
assert_kind_of Array, @mini_exiftool_num['SupplementalCategories'].to_a
|
data/test/test_save.rb
CHANGED
@@ -32,7 +32,7 @@ class TestSave < TestCase
|
|
32
32
|
result = @mini_exiftool.save
|
33
33
|
assert_equal false, result
|
34
34
|
assert_equal 1, @mini_exiftool.errors.size
|
35
|
-
|
35
|
+
assert_match(/Can't convert IFD0:Orientation \(not in PrintConv\)/,
|
36
36
|
@mini_exiftool.errors['Orientation'])
|
37
37
|
assert @mini_exiftool.changed?
|
38
38
|
assert @mini_exiftool.changed_tags.include?('Orientation')
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.2
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jan Friedrich
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-02-10 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -32,25 +32,25 @@ files:
|
|
32
32
|
- examples/external_photo.rb
|
33
33
|
- examples/print_portraits.rb
|
34
34
|
- examples/shift_time.rb
|
35
|
-
- lib/mini_exiftool.new.rb
|
36
35
|
- lib/mini_exiftool.rb
|
37
36
|
- setup.rb
|
38
37
|
- test/helpers_for_test.rb
|
39
38
|
- test/test_class_methods.rb
|
40
39
|
- test/test_composite.rb
|
41
40
|
- test/test_dumping.rb
|
41
|
+
- test/test_escape_filename.rb
|
42
42
|
- test/test_read.rb
|
43
43
|
- test/test_read_numerical.rb
|
44
44
|
- test/test_save.rb
|
45
45
|
- test/test_special.rb
|
46
46
|
- test/test_special_dates.rb
|
47
47
|
- test/test_write.rb
|
48
|
-
- x.rb
|
49
48
|
- Rakefile
|
50
49
|
- COPYING
|
51
50
|
- Changelog
|
52
51
|
- test/data/Canon.jpg
|
53
52
|
- test/data/INFORMATION
|
53
|
+
- test/data/test 36"Bench.jpg
|
54
54
|
- test/data/test.jpg
|
55
55
|
- test/data/test_special_dates.jpg
|
56
56
|
- README
|
@@ -96,6 +96,7 @@ test_files:
|
|
96
96
|
- test/test_class_methods.rb
|
97
97
|
- test/test_composite.rb
|
98
98
|
- test/test_dumping.rb
|
99
|
+
- test/test_escape_filename.rb
|
99
100
|
- test/test_read.rb
|
100
101
|
- test/test_read_numerical.rb
|
101
102
|
- test/test_save.rb
|
data/lib/mini_exiftool.new.rb
DELETED
@@ -1,445 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# MiniExiftool
|
3
|
-
#
|
4
|
-
# This library is wrapper for the Exiftool command-line
|
5
|
-
# application (http://www.sno.phy.queensu.ca/~phil/exiftool/)
|
6
|
-
# written by Phil Harvey.
|
7
|
-
# Read and write access is done in a clean OO manner.
|
8
|
-
#
|
9
|
-
# Author: Jan Friedrich
|
10
|
-
# Copyright (c) 2007, 2008 by Jan Friedrich
|
11
|
-
# Licensed under the GNU LESSER GENERAL PUBLIC LICENSE,
|
12
|
-
# Version 2.1, February 1999
|
13
|
-
#
|
14
|
-
|
15
|
-
require 'fileutils'
|
16
|
-
require 'tempfile'
|
17
|
-
require 'pstore'
|
18
|
-
require 'set'
|
19
|
-
|
20
|
-
# Simple OO access to the Exiftool command-line application.
|
21
|
-
class MiniExiftool
|
22
|
-
|
23
|
-
# Name of the Exiftool command-line application
|
24
|
-
@@cmd = 'exiftool'
|
25
|
-
|
26
|
-
# Hash of the standard options used when call MiniExiftool.new
|
27
|
-
@@opts = { :numerical => false, :composite => true, :convert_encoding => false, :timestamps => Time }
|
28
|
-
|
29
|
-
attr_reader :filename
|
30
|
-
attr_accessor :numerical, :composite, :convert_encoding, :errors, :timestamps
|
31
|
-
|
32
|
-
VERSION = '1.0.1'
|
33
|
-
|
34
|
-
# +opts+ support at the moment
|
35
|
-
# * <code>:numerical</code> for numerical values, default is +false+
|
36
|
-
# * <code>:composite</code> for including composite tags while loading,
|
37
|
-
# default is +true+
|
38
|
-
# * <code>:convert_encoding</code> convert encoding (See -L-option of
|
39
|
-
# the exiftool command-line application, default is +false+
|
40
|
-
# * <code>:timestamps</code> generating DateTime objects instead of
|
41
|
-
# Time objects if set to <code>DateTime</code>, default is +Time+
|
42
|
-
#
|
43
|
-
# <b>ATTENTION:</b> Time objects are created using <code>Time.local</code>
|
44
|
-
# therefore they use <em>your local timezone</em>, DateTime objects instead
|
45
|
-
# are created <em>without timezone</em>!
|
46
|
-
def initialize filename=nil, opts={}
|
47
|
-
opts = @@opts.merge opts
|
48
|
-
@numerical = opts[:numerical]
|
49
|
-
@composite = opts[:composite]
|
50
|
-
@convert_encoding = opts[:convert_encoding]
|
51
|
-
@timestamps = opts[:timestamps]
|
52
|
-
@values = TagHash.new
|
53
|
-
@tag_names = TagHash.new
|
54
|
-
@changed_values = TagHash.new
|
55
|
-
@errors = TagHash.new
|
56
|
-
load filename unless filename.nil?
|
57
|
-
end
|
58
|
-
|
59
|
-
def initialize_from_hash hash # :nodoc:
|
60
|
-
hash.each_pair do |tag,value|
|
61
|
-
set_value tag, value
|
62
|
-
end
|
63
|
-
set_attributes_by_heuristic
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
|
-
# Load the tags of filename.
|
68
|
-
def load filename
|
69
|
-
unless filename && File.exist?(filename)
|
70
|
-
raise MiniExiftool::Error.new("File '#{filename}' does not exist.")
|
71
|
-
end
|
72
|
-
if File.directory?(filename)
|
73
|
-
raise MiniExiftool::Error.new("'#{filename}' is a directory.")
|
74
|
-
end
|
75
|
-
@filename = filename
|
76
|
-
@values.clear
|
77
|
-
@tag_names.clear
|
78
|
-
@changed_values.clear
|
79
|
-
opt_params = ''
|
80
|
-
opt_params << (@numerical ? '-n ' : '')
|
81
|
-
opt_params << (@composite ? '' : '-e ')
|
82
|
-
opt_params << (@convert_encoding ? '-L ' : '')
|
83
|
-
cmd = %Q(#@@cmd -q -q -s -t #{opt_params} #{@@sep_op} "#{filename}")
|
84
|
-
if run(cmd)
|
85
|
-
parse_output
|
86
|
-
else
|
87
|
-
raise MiniExiftool::Error.new(@error_text)
|
88
|
-
end
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
# Reload the tags of an already readed file.
|
93
|
-
def reload
|
94
|
-
load @filename
|
95
|
-
end
|
96
|
-
|
97
|
-
# Returns the value of a tag.
|
98
|
-
def [] tag
|
99
|
-
@changed_values[tag] || @values[tag]
|
100
|
-
end
|
101
|
-
|
102
|
-
# Set the value of a tag.
|
103
|
-
def []=(tag, val)
|
104
|
-
@changed_values[tag] = val
|
105
|
-
end
|
106
|
-
|
107
|
-
# Returns true if any tag value is changed or if the value of a
|
108
|
-
# given tag is changed.
|
109
|
-
def changed? tag=false
|
110
|
-
if tag
|
111
|
-
@changed_values.include? tag
|
112
|
-
else
|
113
|
-
!@changed_values.empty?
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# Revert all changes or the change of a given tag.
|
118
|
-
def revert tag=nil
|
119
|
-
if tag
|
120
|
-
val = @changed_values.delete(tag)
|
121
|
-
res = val != nil
|
122
|
-
else
|
123
|
-
res = @changed_values.size > 0
|
124
|
-
@changed_values.clear
|
125
|
-
end
|
126
|
-
res
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns an array of the tags (original tag names) of the readed file.
|
130
|
-
def tags
|
131
|
-
@values.keys.map { |key| @tag_names[key] }
|
132
|
-
end
|
133
|
-
|
134
|
-
# Returns an array of all changed tags.
|
135
|
-
def changed_tags
|
136
|
-
@changed_values.keys.map { |key| MiniExiftool.original_tag(key) }
|
137
|
-
end
|
138
|
-
|
139
|
-
# Save the changes to the file.
|
140
|
-
def save
|
141
|
-
return false if @changed_values.empty?
|
142
|
-
@errors.clear
|
143
|
-
temp_file = Tempfile.new('mini_exiftool')
|
144
|
-
temp_file.close
|
145
|
-
temp_filename = temp_file.path
|
146
|
-
FileUtils.cp filename, temp_filename
|
147
|
-
all_ok = true
|
148
|
-
@changed_values.each do |tag, val|
|
149
|
-
original_tag = MiniExiftool.original_tag(tag)
|
150
|
-
arr_val = val.kind_of?(Array) ? val : [val]
|
151
|
-
arr_val.map! {|e| convert e}
|
152
|
-
tag_params = ''
|
153
|
-
arr_val.each do |v|
|
154
|
-
tag_params << %Q(-#{original_tag}="#{v}" )
|
155
|
-
end
|
156
|
-
opt_params = ''
|
157
|
-
opt_params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '')
|
158
|
-
opt_params << (@convert_encoding ? '-L ' : '')
|
159
|
-
cmd = %Q(#@@cmd -q -P -overwrite_original #{opt_params} #{tag_params} "#{temp_filename}")
|
160
|
-
result = run(cmd)
|
161
|
-
unless result
|
162
|
-
all_ok = false
|
163
|
-
@errors[tag] = @error_text.gsub(/Nothing to do.\n\z/, '').chomp
|
164
|
-
end
|
165
|
-
end
|
166
|
-
if all_ok
|
167
|
-
FileUtils.cp temp_filename, filename
|
168
|
-
reload
|
169
|
-
end
|
170
|
-
temp_file.delete
|
171
|
-
all_ok
|
172
|
-
end
|
173
|
-
|
174
|
-
# Returns a hash of the original loaded values of the MiniExiftool
|
175
|
-
# instance.
|
176
|
-
def to_hash
|
177
|
-
result = {}
|
178
|
-
@values.each do |k,v|
|
179
|
-
result[@tag_names[k]] = v
|
180
|
-
end
|
181
|
-
result
|
182
|
-
end
|
183
|
-
|
184
|
-
# Returns a YAML representation of the original loaded values of the
|
185
|
-
# MiniExiftool instance.
|
186
|
-
def to_yaml
|
187
|
-
to_hash.to_yaml
|
188
|
-
end
|
189
|
-
|
190
|
-
# Create a MiniExiftool instance from a hash
|
191
|
-
def self.from_hash hash
|
192
|
-
instance = MiniExiftool.new
|
193
|
-
instance.initialize_from_hash hash
|
194
|
-
instance
|
195
|
-
end
|
196
|
-
|
197
|
-
# Create a MiniExiftool instance from YAML data created with
|
198
|
-
# MiniExiftool#to_yaml
|
199
|
-
def self.from_yaml yaml
|
200
|
-
MiniExiftool.from_hash YAML.load(yaml)
|
201
|
-
end
|
202
|
-
|
203
|
-
# Returns the command name of the called Exiftool application.
|
204
|
-
def self.command
|
205
|
-
@@cmd
|
206
|
-
end
|
207
|
-
|
208
|
-
# Setting the command name of the called Exiftool application.
|
209
|
-
def self.command= cmd
|
210
|
-
@@cmd = cmd
|
211
|
-
end
|
212
|
-
|
213
|
-
# Returns the options hash.
|
214
|
-
def self.opts
|
215
|
-
@@opts
|
216
|
-
end
|
217
|
-
|
218
|
-
# Returns a set of all known tags of Exiftool.
|
219
|
-
def self.all_tags
|
220
|
-
unless defined? @@all_tags
|
221
|
-
@@all_tags = pstore_get :all_tags
|
222
|
-
end
|
223
|
-
@@all_tags
|
224
|
-
end
|
225
|
-
|
226
|
-
# Returns a set of all possible writable tags of Exiftool.
|
227
|
-
def self.writable_tags
|
228
|
-
unless defined? @@writable_tags
|
229
|
-
@@writable_tags = pstore_get :writable_tags
|
230
|
-
end
|
231
|
-
@@writable_tags
|
232
|
-
end
|
233
|
-
|
234
|
-
# Returns the original Exiftool name of the given tag
|
235
|
-
def self.original_tag tag
|
236
|
-
unless defined? @@all_tags_map
|
237
|
-
@@all_tags_map = pstore_get :all_tags_map
|
238
|
-
end
|
239
|
-
@@all_tags_map[tag]
|
240
|
-
end
|
241
|
-
|
242
|
-
# Returns the version of the Exiftool command-line application.
|
243
|
-
def self.exiftool_version
|
244
|
-
output = `#{MiniExiftool.command} -ver 2>&1`
|
245
|
-
unless $?.exitstatus == 0
|
246
|
-
raise MiniExiftool::Error.new("Command '#{MiniExiftool.command}' not found")
|
247
|
-
end
|
248
|
-
output.chomp!
|
249
|
-
end
|
250
|
-
|
251
|
-
def self.unify tag
|
252
|
-
tag.gsub(/[-_]/,'').downcase
|
253
|
-
end
|
254
|
-
|
255
|
-
# Exception class
|
256
|
-
class MiniExiftool::Error < StandardError; end
|
257
|
-
|
258
|
-
############################################################################
|
259
|
-
private
|
260
|
-
############################################################################
|
261
|
-
|
262
|
-
@@error_file = Tempfile.new 'errors'
|
263
|
-
@@error_file.close
|
264
|
-
|
265
|
-
if Float(exiftool_version) < 7.41
|
266
|
-
@@separator = ', '
|
267
|
-
@@sep_op = ''
|
268
|
-
else
|
269
|
-
@@separator = '@@'
|
270
|
-
@@sep_op = '-sep @@'
|
271
|
-
end
|
272
|
-
|
273
|
-
def run cmd
|
274
|
-
if $DEBUG
|
275
|
-
$stderr.puts cmd
|
276
|
-
end
|
277
|
-
@output = `#{cmd} 2>#{@@error_file.path}`
|
278
|
-
@status = $?
|
279
|
-
unless @status.exitstatus == 0
|
280
|
-
@error_text = File.readlines(@@error_file.path).join
|
281
|
-
return false
|
282
|
-
else
|
283
|
-
@error_text = ''
|
284
|
-
return true
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
def convert val
|
289
|
-
case val
|
290
|
-
when Time
|
291
|
-
val = val.strftime('%Y:%m:%d %H:%M:%S')
|
292
|
-
end
|
293
|
-
val
|
294
|
-
end
|
295
|
-
|
296
|
-
def method_missing symbol, *args
|
297
|
-
tag_name = symbol.id2name
|
298
|
-
if tag_name.sub!(/=$/, '')
|
299
|
-
self[tag_name] = args.first
|
300
|
-
else
|
301
|
-
self[tag_name]
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
def parse_output
|
306
|
-
@output.each_line do |line|
|
307
|
-
tag, value = parse_line line
|
308
|
-
set_value tag, value
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
def parse_line line
|
313
|
-
if line =~ /^([^\t]+)\t(.*)$/
|
314
|
-
tag, value = $1, $2
|
315
|
-
case value
|
316
|
-
when /^\d{4}:\d\d:\d\d \d\d:\d\d:\d\d$/
|
317
|
-
arr = value.split(/[: ]/) #Fixed by kro44 - add parentheses
|
318
|
-
arr.map! {|elem| elem.to_i}
|
319
|
-
begin
|
320
|
-
if @timestamps == Time
|
321
|
-
value = Time.local(*arr) #Fixed by kro44 - add parentheses
|
322
|
-
elsif @timestamps == DateTime
|
323
|
-
value = DateTime.strptime(value,'%Y:%m:%d %H:%M:%S')
|
324
|
-
else
|
325
|
-
raise MiniExiftool::Error.new("Value #@timestamps not allowed for option timestamps.")
|
326
|
-
end
|
327
|
-
rescue ArgumentError
|
328
|
-
value = false
|
329
|
-
end
|
330
|
-
when /^\d+\.\d+$/
|
331
|
-
value = value.to_f
|
332
|
-
when /^0+[1-9]+$/
|
333
|
-
# nothing => String
|
334
|
-
when /^-?\d+$/
|
335
|
-
value = value.to_i
|
336
|
-
when /^[\d ]+$/
|
337
|
-
# nothing => String
|
338
|
-
when /#{@@separator}/
|
339
|
-
value = value.split @@separator
|
340
|
-
end
|
341
|
-
else
|
342
|
-
raise MiniExiftool::Error.new("Malformed line #{line.inspect} of exiftool output.")
|
343
|
-
end
|
344
|
-
unless value.respond_to?('to_a')
|
345
|
-
class << value
|
346
|
-
def to_a
|
347
|
-
[self]
|
348
|
-
end
|
349
|
-
end
|
350
|
-
end
|
351
|
-
return [tag, value]
|
352
|
-
end
|
353
|
-
|
354
|
-
def set_value tag, value
|
355
|
-
@tag_names[tag] = tag
|
356
|
-
@values[tag] = value
|
357
|
-
end
|
358
|
-
|
359
|
-
def set_attributes_by_heuristic
|
360
|
-
self.composite = tags.include?('ImageSize') ? true : false
|
361
|
-
self.numerical = self.file_size.kind_of?(Integer) ? true : false
|
362
|
-
# TODO: Is there a heuristic to determine @convert_encoding?
|
363
|
-
self.timestamps = self.FileModifyDate.kind_of?(DateTime) ? DateTime : Time
|
364
|
-
end
|
365
|
-
|
366
|
-
def temp_filename
|
367
|
-
unless @temp_filename
|
368
|
-
temp_file = Tempfile.new('mini-exiftool')
|
369
|
-
temp_file.close
|
370
|
-
FileUtils.cp(@filename, temp_file.path)
|
371
|
-
@temp_filename = temp_file.path
|
372
|
-
end
|
373
|
-
@temp_filename
|
374
|
-
end
|
375
|
-
|
376
|
-
def self.pstore_get attribute
|
377
|
-
load_or_create_pstore unless defined? @@pstore
|
378
|
-
result = nil
|
379
|
-
@@pstore.transaction(true) do |ps|
|
380
|
-
result = ps[attribute]
|
381
|
-
end
|
382
|
-
result
|
383
|
-
end
|
384
|
-
|
385
|
-
def self.load_or_create_pstore
|
386
|
-
# This will hopefully work on *NIX and Windows systems
|
387
|
-
home = ENV['HOME'] || ENV['HOMEDRIVE'] + ENV['HOMEPATH'] || ENV['USERPROFILE']
|
388
|
-
subdir = RUBY_PLATFORM =~ /win/i ? '_mini_exiftool' : '.mini_exiftool'
|
389
|
-
FileUtils.mkdir_p(File.join(home, subdir))
|
390
|
-
filename = File.join(home, subdir, 'exiftool_tags_' << exiftool_version.gsub('.', '_') << '.pstore')
|
391
|
-
@@pstore = PStore.new filename
|
392
|
-
if !File.exist?(filename) || File.size(filename) == 0
|
393
|
-
@@pstore.transaction do |ps|
|
394
|
-
ps[:all_tags] = all_tags = determine_tags('list')
|
395
|
-
ps[:writable_tags] = determine_tags('listw')
|
396
|
-
map = {}
|
397
|
-
all_tags.each { |k| map[unify(k)] = k }
|
398
|
-
ps[:all_tags_map] = map
|
399
|
-
end
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
|
-
def self.determine_tags arg
|
404
|
-
output = `#{@@cmd} -#{arg}`
|
405
|
-
lines = output.split(/\n/) #Fixed by kro44 - add parentheses
|
406
|
-
tags = Set.new
|
407
|
-
lines.each do |line|
|
408
|
-
next unless line =~ /^\s/
|
409
|
-
tags |= line.chomp.split
|
410
|
-
end
|
411
|
-
tags
|
412
|
-
end
|
413
|
-
|
414
|
-
|
415
|
-
# Hash with indifferent access:
|
416
|
-
# DateTimeOriginal == datetimeoriginal == date_time_original
|
417
|
-
class TagHash < Hash # :nodoc:
|
418
|
-
def[] k
|
419
|
-
super(unify(k))
|
420
|
-
end
|
421
|
-
def []= k, v
|
422
|
-
super(unify(k), v)
|
423
|
-
end
|
424
|
-
def delete k
|
425
|
-
super(unify(k))
|
426
|
-
end
|
427
|
-
|
428
|
-
def unify tag
|
429
|
-
MiniExiftool.unify tag
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
end
|
434
|
-
|
435
|
-
# Add to_a to Numerical if it's not yet defined
|
436
|
-
unless Numeric.instance_methods.include? 'to_a'
|
437
|
-
class Numeric
|
438
|
-
def to_a
|
439
|
-
[self]
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|
443
|
-
|
444
|
-
# Test if we can run the Exiftool command
|
445
|
-
MiniExiftool.exiftool_version
|