mini_exiftool 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +15 -0
- data/README.rdoc +3 -3
- data/Rakefile +4 -0
- data/Tutorial.rdoc +151 -0
- data/lib/mini_exiftool.rb +72 -42
- data/test/data/invalid_byte_sequence_in_utf8.json +4 -0
- data/test/test_filename_access.rb +60 -0
- data/test/test_invalid_byte_sequence_in_utf8.rb +27 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2970f3d46bd1c8af75467b6914b3bc0f13723615
|
4
|
+
data.tar.gz: 2ac12585911106fe8b086b24f8d881f4f2b830aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b5379aefcce1ef0f88154f4026de05a1c227ed209b69eb35d0d4f1559531556ea8dab0ae78f4b518f77a6ad804b3ec756a8359211e266d1d0de4b597dff6a47
|
7
|
+
data.tar.gz: 8a85d9606d967cac3bde0041a8ce790cb5c4b34292204d4f662943b3ed49e6b81dc12aaee84e1081e33a82480361e05600e6924bfffeafbcf94d3c1280091486
|
data/Changelog
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
2.2.0
|
2
|
+
The Encoding Release
|
3
|
+
- New option :replace_invalid_chars to handle "bad data"
|
4
|
+
invalid byte sequences in UTF-8
|
5
|
+
Thanks to Chris Salzberg (aka shioyama) and
|
6
|
+
Robert May (aka robotmay) for precious hints
|
7
|
+
- Support of different encodings for commandline params
|
8
|
+
and filenames (neccessary to support Windows)
|
9
|
+
to allow filenames with special chars
|
10
|
+
Thanks to uwe58 and others for hints
|
11
|
+
- Doing different commandline escaping for windows and POSIX
|
12
|
+
systems
|
13
|
+
Thanks to Michael Dungan for the hint
|
14
|
+
- Update Tutorial
|
15
|
+
|
1
16
|
2.1.0
|
2
17
|
- insert require 'json'
|
3
18
|
- Drop option :convert_encoding (use Ruby String
|
data/README.rdoc
CHANGED
@@ -53,6 +53,6 @@ February 1999 (see file COPYING for more details)
|
|
53
53
|
|
54
54
|
== Usage
|
55
55
|
|
56
|
-
For further information about using MiniExiftool read the
|
57
|
-
|
58
|
-
|
56
|
+
For further information about using MiniExiftool read the Tutorial.rdoc
|
57
|
+
in the project root folder and have a look at the examples in directory
|
58
|
+
examples.
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rim'
|
2
2
|
require 'rim/check_version'
|
3
3
|
require 'rim/gem'
|
4
|
+
require 'rim/rdoc'
|
4
5
|
require 'rim/test'
|
5
6
|
|
6
7
|
$:.unshift 'lib'
|
@@ -13,6 +14,9 @@ Rim.setup do |p|
|
|
13
14
|
p.email = 'janfri26@gmail.com'
|
14
15
|
p.summary = 'This library is wrapper for the Exiftool command-line application (http://www.sno.phy.queensu.ca/~phil/exiftool).'
|
15
16
|
p.homepage = 'http://gitorious.org/mini_exiftool'
|
17
|
+
p.gem_files << 'Tutorial.rdoc'
|
18
|
+
puts p.rdoc_files
|
19
|
+
p.rdoc_files << 'Tutorial.rdoc'
|
16
20
|
p.install_message = %q{
|
17
21
|
+-----------------------------------------------------------------------+
|
18
22
|
| Please ensure you have installed exiftool at least version 7.65 |
|
data/Tutorial.rdoc
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
= Mini Tutorial
|
2
|
+
|
3
|
+
|
4
|
+
== Installation
|
5
|
+
|
6
|
+
* Installing the Exiftool command-line application from Phil Harvey
|
7
|
+
(see http://www.sno.phy.queensu.ca/~phil/exiftool/install.html)
|
8
|
+
* Installing the Ruby library (<code>gem install mini_exiftool</code>)
|
9
|
+
|
10
|
+
|
11
|
+
== Lesson 1: Reading Meta Data
|
12
|
+
|
13
|
+
=== A Simple Example
|
14
|
+
|
15
|
+
require 'rubygems'
|
16
|
+
require 'mini_exiftool'
|
17
|
+
|
18
|
+
photo = MiniExiftool.new 'photo.jpg'
|
19
|
+
puts photo['DateTimeOriginal']
|
20
|
+
|
21
|
+
|
22
|
+
=== Smart Tag Names
|
23
|
+
In the example above we use <code>photo['DateTimeOriginal']</code> to
|
24
|
+
get the value for the time the photo was taken. But tag names are not
|
25
|
+
case sensitive and additional underlines are also irrelevant. So
|
26
|
+
following expressions are equivalent:
|
27
|
+
photo['DateTimeOriginal']
|
28
|
+
photo['datetimeoriginal']
|
29
|
+
photo['date_time_original']
|
30
|
+
|
31
|
+
It is also possible to use symbols:
|
32
|
+
photo[:DateTimeOriginal]
|
33
|
+
photo[:datetimeoriginal]
|
34
|
+
photo[:date_time_original]
|
35
|
+
|
36
|
+
=== Nicer Access Via Dynamic Methods
|
37
|
+
|
38
|
+
Using the []-method is the safest way to access to values of tags
|
39
|
+
(e. g. Self-timer you can only access this way) but the smarter way is
|
40
|
+
using dynamic method access. You can write:
|
41
|
+
photo.datetimeoriginal
|
42
|
+
or also
|
43
|
+
photo.date_time_original
|
44
|
+
|
45
|
+
|
46
|
+
=== Value Types
|
47
|
+
|
48
|
+
Following types of values are at the moment supported:
|
49
|
+
* Array (e. g. Keywords => ['tree', 'gras'])
|
50
|
+
* Fixnum (e. g. ISO => 400)
|
51
|
+
* Float (e. g. FNumber => 9.5)
|
52
|
+
* String (e. g. Model => DYNAX 7D)
|
53
|
+
* Time (e. g. DateTimeOriginal => 2005:09:13 20:08:50)
|
54
|
+
|
55
|
+
Be aware, if there is only one value in a tag which can hold multiple
|
56
|
+
values the result is'nt an array! But you can get one with the Array
|
57
|
+
method:
|
58
|
+
# only _one_ keyword
|
59
|
+
p1 = MiniExiftool.new 'p1.jpg'
|
60
|
+
p1.keywords # => 'red'
|
61
|
+
# _more than one_ keywords
|
62
|
+
p3 = MiniExiftool.new 'p3.jpg'
|
63
|
+
p3.keywords # => ['red', 'yellow', 'green']
|
64
|
+
|
65
|
+
# if we want to get an array in both cases and don't know
|
66
|
+
# if there is one ore more values set let's take Array()
|
67
|
+
Array(p1.keywords) # => ['red']
|
68
|
+
Array(p3.keywords) # => ['red', 'yellow', 'green']
|
69
|
+
|
70
|
+
=== Using options
|
71
|
+
|
72
|
+
The Exiftool command-line application has an option (-n) to get values
|
73
|
+
as numbers if possible, in MiniExiftool you can do this with setting
|
74
|
+
the <code>:numerical</code> option to +true+ while generating a new
|
75
|
+
instance with new or using the <code>numerical=</code>-method
|
76
|
+
combining with calling <code>reload</code>.
|
77
|
+
|
78
|
+
Let's look at an example:
|
79
|
+
# standard: numerical is false
|
80
|
+
photo = MiniExiftool.new 'photo.jpg'
|
81
|
+
photo.exposure_time # => '1/60' (String)
|
82
|
+
# now with numerical is true
|
83
|
+
photo.numerical = true
|
84
|
+
photo.reload
|
85
|
+
photo.exposure_time # => 0.01666667 (Float)
|
86
|
+
This behaviour can be useful if you want to do calculations on the
|
87
|
+
value, if you only want to show the value the standard behaviour is
|
88
|
+
maybe better.
|
89
|
+
|
90
|
+
The Time class of Ruby cannot handle timestamps before 1st January 1970
|
91
|
+
on some platforms. If there are timestamps in files before this date it
|
92
|
+
will result in an error. In this case we can set the option
|
93
|
+
<code>:timestamps</code> to +DateTime+ to use DateTime objects instead
|
94
|
+
of Time objects.
|
95
|
+
|
96
|
+
There is another option <code>:composite</code>. If this is set to
|
97
|
+
+false+ the composite tags are not calculated by the exiftool
|
98
|
+
command-line application (option -e).
|
99
|
+
|
100
|
+
Further options are
|
101
|
+
* <code>:ignore_minor_errors</code> to ignore minor
|
102
|
+
errors (See -m-option of the exiftool command-line application,
|
103
|
+
default is +false+)
|
104
|
+
* <code>:coord_format</code> set format for GPS coordinates (See
|
105
|
+
-c-option of the exiftool command-line application, default is +nil+
|
106
|
+
that means exiftool standard)
|
107
|
+
* <code>:replace_invalid_chars</code> replace string for invalid
|
108
|
+
UTF-8 characters or +false+ if no replacing should be done,
|
109
|
+
default is +false+
|
110
|
+
|
111
|
+
=== Further Example
|
112
|
+
|
113
|
+
For understanding reading access to meta data also have a look at the
|
114
|
+
example file <code>print_portraits.rb</code> in the +examples+
|
115
|
+
directory.
|
116
|
+
|
117
|
+
== Lesson 2: Writing Meta Data
|
118
|
+
|
119
|
+
|
120
|
+
=== Also A Very Simple Example
|
121
|
+
|
122
|
+
require 'rubygems'
|
123
|
+
require 'mini_exiftool'
|
124
|
+
|
125
|
+
photo = MiniExiftool.new 'photo.jpg'
|
126
|
+
photo.comment = 'hello world'
|
127
|
+
photo.save
|
128
|
+
|
129
|
+
|
130
|
+
=== Save Is Atomar
|
131
|
+
|
132
|
+
If you have changed serval values and call the +save+-method either
|
133
|
+
all changes will be written to the file or nothing. The return value
|
134
|
+
of the +save+-method is +true+ if all values are written to the file
|
135
|
+
otherwise save returns +false+. In the last case you can use the
|
136
|
+
+errors+-method which returns a hash of the tags which values couldn't
|
137
|
+
be writed with an error message for each of them.
|
138
|
+
|
139
|
+
|
140
|
+
=== Interesting Methods
|
141
|
+
|
142
|
+
Have a look at the <code>changed?</code>-method for checking if the
|
143
|
+
value of a specific tag is changed or a changing in general is
|
144
|
+
done. In the same way the +revert+-method reverts the value of a
|
145
|
+
specific tag or in general all changes.
|
146
|
+
|
147
|
+
You should also look at the rdoc information of MiniExiftool.
|
148
|
+
|
149
|
+
=== Further Examples
|
150
|
+
|
151
|
+
Have a look in the examples folder of MiniExiftool.
|
data/lib/mini_exiftool.rb
CHANGED
@@ -17,6 +17,7 @@ require 'fileutils'
|
|
17
17
|
require 'json'
|
18
18
|
require 'pstore'
|
19
19
|
require 'rational'
|
20
|
+
require 'rbconfig'
|
20
21
|
require 'set'
|
21
22
|
require 'tempfile'
|
22
23
|
require 'time'
|
@@ -28,22 +29,30 @@ class MiniExiftool
|
|
28
29
|
@@cmd = 'exiftool'
|
29
30
|
|
30
31
|
# Hash of the standard options used when call MiniExiftool.new
|
31
|
-
@@opts = { :numerical => false, :composite => true, :ignore_minor_errors => false,
|
32
|
+
@@opts = { :numerical => false, :composite => true, :ignore_minor_errors => false,
|
33
|
+
:replace_invalid_chars => false, :timestamps => Time }
|
34
|
+
|
35
|
+
# Encoding of the filesystem (filenames in command line)
|
36
|
+
@@fs_enc = Encoding.find('filesystem')
|
32
37
|
|
33
38
|
attr_reader :filename
|
34
|
-
attr_accessor :numerical, :composite, :ignore_minor_errors, :errors,
|
39
|
+
attr_accessor :numerical, :composite, :ignore_minor_errors, :errors,
|
40
|
+
:replace_invalid_chars, :timestamps
|
35
41
|
|
36
|
-
VERSION = '2.
|
42
|
+
VERSION = '2.2.0'
|
37
43
|
|
38
44
|
# +opts+ support at the moment
|
39
45
|
# * <code>:numerical</code> for numerical values, default is +false+
|
40
46
|
# * <code>:composite</code> for including composite tags while loading,
|
41
47
|
# default is +true+
|
42
48
|
# * <code>:ignore_minor_errors</code> ignore minor errors (See -m-option
|
43
|
-
#
|
49
|
+
# of the exiftool command-line application, default is +false+)
|
44
50
|
# * <code>:coord_format</code> set format for GPS coordinates (See
|
45
51
|
# -c-option of the exiftool command-line application, default is +nil+
|
46
52
|
# that means exiftool standard)
|
53
|
+
# * <code>:replace_invalid_chars</code> replace string for invalid
|
54
|
+
# UTF-8 characters or +false+ if no replacing should be done,
|
55
|
+
# default is +false+
|
47
56
|
# * <code>:timestamps</code> generating DateTime objects instead of
|
48
57
|
# Time objects if set to <code>DateTime</code>, default is +Time+
|
49
58
|
#
|
@@ -61,6 +70,7 @@ class MiniExiftool
|
|
61
70
|
@ignore_minor_errors = opts[:ignore_minor_errors]
|
62
71
|
@timestamps = opts[:timestamps]
|
63
72
|
@coord_format = opts[:coord_format]
|
73
|
+
@replace_invalid_chars = opts[:replace_invalid_chars]
|
64
74
|
@values = TagHash.new
|
65
75
|
@tag_names = TagHash.new
|
66
76
|
@changed_values = TagHash.new
|
@@ -70,12 +80,19 @@ class MiniExiftool
|
|
70
80
|
|
71
81
|
def initialize_from_hash hash # :nodoc:
|
72
82
|
hash.each_pair do |tag,value|
|
73
|
-
set_value tag,
|
83
|
+
set_value tag, convert_after_load(value)
|
74
84
|
end
|
75
85
|
set_attributes_by_heuristic
|
76
86
|
self
|
77
87
|
end
|
78
88
|
|
89
|
+
def initialize_from_json json # :nodoc:
|
90
|
+
@output = json
|
91
|
+
@errors.clear
|
92
|
+
parse_output
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
79
96
|
# Load the tags of filename.
|
80
97
|
def load filename
|
81
98
|
MiniExiftool.setup
|
@@ -89,12 +106,11 @@ class MiniExiftool
|
|
89
106
|
@values.clear
|
90
107
|
@tag_names.clear
|
91
108
|
@changed_values.clear
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
if run(cmd)
|
109
|
+
params = '-j '
|
110
|
+
params << (@numerical ? '-n ' : '')
|
111
|
+
params << (@composite ? '' : '-e ')
|
112
|
+
params << (@coord_format ? "-c \"#{@coord_format}\"" : '')
|
113
|
+
if run(cmd_gen(params, @filename))
|
98
114
|
parse_output
|
99
115
|
else
|
100
116
|
raise MiniExiftool::Error.new(@error_text)
|
@@ -113,7 +129,7 @@ class MiniExiftool
|
|
113
129
|
end
|
114
130
|
|
115
131
|
# Set the value of a tag.
|
116
|
-
def []=
|
132
|
+
def []= tag, val
|
117
133
|
@changed_values[tag] = val
|
118
134
|
end
|
119
135
|
|
@@ -157,28 +173,26 @@ class MiniExiftool
|
|
157
173
|
temp_file = Tempfile.new('mini_exiftool')
|
158
174
|
temp_file.close
|
159
175
|
temp_filename = temp_file.path
|
160
|
-
FileUtils.cp filename, temp_filename
|
176
|
+
FileUtils.cp filename.encode(@@fs_enc), temp_filename
|
161
177
|
all_ok = true
|
162
178
|
@changed_values.each do |tag, val|
|
163
179
|
original_tag = MiniExiftool.original_tag(tag)
|
164
180
|
arr_val = val.kind_of?(Array) ? val : [val]
|
165
|
-
arr_val.map! {|e|
|
166
|
-
|
181
|
+
arr_val.map! {|e| convert_before_save(e)}
|
182
|
+
params = '-q -P -overwrite_original '
|
183
|
+
params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '')
|
184
|
+
params << (@ignore_minor_errors ? '-m ' : '')
|
167
185
|
arr_val.each do |v|
|
168
|
-
|
186
|
+
params << %Q(-#{original_tag}=#{escape(v)} )
|
169
187
|
end
|
170
|
-
|
171
|
-
opt_params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '')
|
172
|
-
opt_params << (@ignore_minor_errors ? '-m' : '')
|
173
|
-
cmd = %Q(#@@cmd -q -P -overwrite_original #{opt_params} #{tag_params} #{temp_filename})
|
174
|
-
result = run(cmd)
|
188
|
+
result = run(cmd_gen(params, temp_filename))
|
175
189
|
unless result
|
176
190
|
all_ok = false
|
177
191
|
@errors[tag] = @error_text.gsub(/Nothing to do.\n\z/, '').chomp
|
178
192
|
end
|
179
193
|
end
|
180
194
|
if all_ok
|
181
|
-
FileUtils.cp temp_filename, filename
|
195
|
+
FileUtils.cp temp_filename, filename.encode(@@fs_enc)
|
182
196
|
reload
|
183
197
|
end
|
184
198
|
temp_file.delete
|
@@ -211,13 +225,22 @@ class MiniExiftool
|
|
211
225
|
to_hash.to_yaml
|
212
226
|
end
|
213
227
|
|
214
|
-
# Create a MiniExiftool instance from a hash. Default value
|
228
|
+
# Create a MiniExiftool instance from a hash. Default value
|
229
|
+
# conversions will be applied if neccesary.
|
215
230
|
def self.from_hash hash
|
216
231
|
instance = MiniExiftool.new
|
217
232
|
instance.initialize_from_hash hash
|
218
233
|
instance
|
219
234
|
end
|
220
235
|
|
236
|
+
# Create a MiniExiftool instance from JSON data. Default value
|
237
|
+
# conversions will be applied if neccesary.
|
238
|
+
def self.from_json json, opts={}
|
239
|
+
instance = MiniExiftool.new nil, opts
|
240
|
+
instance.initialize_from_json json
|
241
|
+
instance
|
242
|
+
end
|
243
|
+
|
221
244
|
# Create a MiniExiftool instance from YAML data created with
|
222
245
|
# MiniExiftool#to_yaml
|
223
246
|
def self.from_yaml yaml
|
@@ -291,6 +314,10 @@ class MiniExiftool
|
|
291
314
|
@@setup_done = true
|
292
315
|
end
|
293
316
|
|
317
|
+
def cmd_gen arg_str='', filename
|
318
|
+
[@@cmd, arg_str.encode('UTF-8'), escape(filename.encode(@@fs_enc))].map {|s| s.force_encoding('UTF-8')}.join(' ')
|
319
|
+
end
|
320
|
+
|
294
321
|
def run cmd
|
295
322
|
if $DEBUG
|
296
323
|
$stderr.puts cmd
|
@@ -299,6 +326,7 @@ class MiniExiftool
|
|
299
326
|
@status = $?
|
300
327
|
unless @status.exitstatus == 0
|
301
328
|
@error_text = File.readlines(@@error_file.path).join
|
329
|
+
@error_text.force_encoding('UTF-8')
|
302
330
|
return false
|
303
331
|
else
|
304
332
|
@error_text = ''
|
@@ -306,7 +334,7 @@ class MiniExiftool
|
|
306
334
|
end
|
307
335
|
end
|
308
336
|
|
309
|
-
def
|
337
|
+
def convert_before_save val
|
310
338
|
case val
|
311
339
|
when Time
|
312
340
|
val = val.strftime('%Y:%m:%d %H:%M:%S')
|
@@ -324,13 +352,17 @@ class MiniExiftool
|
|
324
352
|
end
|
325
353
|
|
326
354
|
def parse_output
|
355
|
+
@output.force_encoding('UTF-8')
|
356
|
+
if @replace_invalid_chars && !@output.valid_encoding?
|
357
|
+
@output.encode!('UTF-16le', invalid: :replace, replace: @replace_invalid_chars).encode!('UTF-8')
|
358
|
+
end
|
327
359
|
JSON.parse(@output)[0].each do |tag,value|
|
328
|
-
value =
|
360
|
+
value = convert_after_load(value)
|
329
361
|
set_value tag, value
|
330
362
|
end
|
331
363
|
end
|
332
364
|
|
333
|
-
def
|
365
|
+
def convert_after_load value
|
334
366
|
return value unless value.kind_of?(String)
|
335
367
|
case value
|
336
368
|
when /^\d{4}:\d\d:\d\d \d\d:\d\d:\d\d/
|
@@ -371,16 +403,6 @@ class MiniExiftool
|
|
371
403
|
self.timestamps = self.FileModifyDate.kind_of?(DateTime) ? DateTime : Time
|
372
404
|
end
|
373
405
|
|
374
|
-
def temp_filename
|
375
|
-
unless @temp_filename
|
376
|
-
temp_file = Tempfile.new('mini-exiftool')
|
377
|
-
temp_file.close
|
378
|
-
FileUtils.cp(@filename, temp_file.path)
|
379
|
-
@temp_filename = temp_file.path
|
380
|
-
end
|
381
|
-
@temp_filename
|
382
|
-
end
|
383
|
-
|
384
406
|
def self.pstore_get attribute
|
385
407
|
load_or_create_pstore unless defined? @@pstore
|
386
408
|
result = nil
|
@@ -390,14 +412,16 @@ class MiniExiftool
|
|
390
412
|
result
|
391
413
|
end
|
392
414
|
|
415
|
+
@@running_on_windows = /mswin|mingw|cygwin/ === RbConfig::CONFIG['host_os']
|
416
|
+
|
393
417
|
def self.load_or_create_pstore
|
394
418
|
# This will hopefully work on *NIX and Windows systems
|
395
419
|
home = ENV['HOME'] || ENV['HOMEDRIVE'] + ENV['HOMEPATH'] || ENV['USERPROFILE']
|
396
|
-
subdir =
|
420
|
+
subdir = @@running_on_windows ? '_mini_exiftool' : '.mini_exiftool'
|
397
421
|
FileUtils.mkdir_p(File.join(home, subdir))
|
398
|
-
|
399
|
-
@@pstore = PStore.new
|
400
|
-
if !File.exist?(
|
422
|
+
pstore_filename = File.join(home, subdir, 'exiftool_tags_' << exiftool_version.gsub('.', '_') << '.pstore')
|
423
|
+
@@pstore = PStore.new pstore_filename
|
424
|
+
if !File.exist?(pstore_filename) || File.size(pstore_filename) == 0
|
401
425
|
@@pstore.transaction do |ps|
|
402
426
|
ps[:all_tags] = all_tags = determine_tags('list')
|
403
427
|
ps[:writable_tags] = determine_tags('listw')
|
@@ -419,8 +443,14 @@ class MiniExiftool
|
|
419
443
|
tags
|
420
444
|
end
|
421
445
|
|
422
|
-
|
423
|
-
|
446
|
+
if @@running_on_windows
|
447
|
+
def escape val
|
448
|
+
'"' << val.to_s.gsub(/([\\"])/, "\\\\\\1") << '"'
|
449
|
+
end
|
450
|
+
else
|
451
|
+
def escape val
|
452
|
+
'"' << val.to_s.gsub(/([\\"$])/, "\\\\\\1") << '"'
|
453
|
+
end
|
424
454
|
end
|
425
455
|
|
426
456
|
# Hash with indifferent access:
|
@@ -0,0 +1,4 @@
|
|
1
|
+
[{
|
2
|
+
"SourceFile": "dba713d8-cf64-11e2-9b31-7586d7f9220b.jpg",
|
3
|
+
"ColorBalanceUnknown": "0212\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000X'%�Tq��_8l�w\u001A��덈܈�D��1�\u0000�Cj����f�7&n\u000C\tx\u0008�{\"6�MX��P5���\u0010��K~��.d�����ڠ\u0008)���\u0017)@��+|���\u000C3\u0005��\u000Fˁ��\u0019���o�<(m\u000B\u0002V��X\u000C\u0019>Rǐ�1\u00053���dP�1'v\u001F\u001E8o~�[p��K\u001CI�R�wa�@5�*.�5@�aw��I\u001C�M+br���,�\u001F�v�0�QeҚ�3\u0004$���]?\u0019�X\u0011��\u0002�l(=�n�\u0006-\u0001z`k#�K�� �-\u0017*���\ni-JW=�L5�\u0012���tq�rzۇ�\u001B��f6^+�\u0000x��2#k\u000C\u0008]\t\u000F�&ɡ��\u000B��kCu��ͷP�y�܉�ꢲ\u001B��l9_�qT�%\u0013Z��E��Q\u0007\u0016|:Y̘�;\u0012B˭�|i�NF�AD�Ucʊ�\u0015�\u0004�W�\u000E�)��狈�{}،����G\u00114���:\u001AS��\u0014������\u001D��b+MȜ�O.f��$��\u0003��\u0003��$��f.Oɖ�G+b��\u001D�����\u0014��S\u001A:���4\u0005Gܾ����}{҂����#�\u0004�W�\u0004�\u0015���cU�DA�FN�i|��B\u0012/���M?j\u0016\u0007Q��E��Z\u0007%�T{��_9l��\u001B��덂܃�!�\u0000uCj����d�7&n\u000F\t\\\u0008\rk\"3�\\x���^7g��\u0011���{s�pt'�`�B�L\u0019=���K,h��.����2 9�J\u000B#�`�\u0001�\u0006�o�<)m\n\u0002S��X\r\u0019~>Wǐ�1\u00112���e���'�\u001F\u001Fx,9�Zx��H\u001DI�R�aHA5�*+�4@�av��H\u001CIͪ�s[�8-y\u001E\u001Ew'0�QeҚ�3\u00040���V?\u0018\u000CY��R\u0003\u000Bl(=�n�\u0007�\u0000�a�\"\nK�� ��\u0016��/��i-J�<\u0018Mپ����tq�rzۓ�\u0010��f6_߸�y]�2#k\u000C\u0008]\t\u000En'7�d����kCt\u0000�!��܉�ꢳ\u001B��m9^�pT�%\u0012Z��D��Q\u0006\u0016?X̙�:\u0012Cˬ�}i�NG�@D�Ubʋ�\u0014�\u0005�V�\u000F�(��튂�{|؍����G\u00104���:\u001BS��\u0015��������\u001D��c+Lȝ�N.g��$��\u0002��\u0003��%��f/OȜ�M*b�$\u0012G�\u0006�a�X���\u001A\\�5L�O;�H)�\u0000�sׂt-�t�W������uŜZ_K���APf��RĽ\u001DIJgæ0�\u0019�^\u000B���\u0005U�*o[��IѠ6��\"\u0014M�\u0014�w�v�\u0011�H.\u001B\u000F�L��<�k^8�a�\u0006�\u0007�d�=dR��FС9��+\u001FZ�%u�ʏ{.�i�@ֳ\u0017´mʹ\"��\u0016 1���;/*�\u0005ܚ���������'�\u0004�R��[\u00088}?wǑ�0\u00056���B��1&�\u001F/x,8�[r��H\u001CIϮ�wa�@5�**�5@�aw��I\u001CHͫ�r[�8,y\u001F\u001Ev'1�PfҚ��\u0004\u0000���V?~XO\u001E��P\u0002#m+<�or\u0007H\u0000�c�0\nH��\u001D��\u0017��\t��h-�=mD��&@\u0001ix.��:��%lZ�+\u000E�ɡ F\u0013��d�ݔ�������^�\n<\u0015����\u001B�HY\u0011pv#wr\u0014]M�\"\u0007�Ơ!I\u0018��o��\u0005\u000C�\u000F\u000B���"
|
4
|
+
}]
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# -- encoding: utf-8 --
|
2
|
+
require 'helpers_for_test'
|
3
|
+
require 'rbconfig'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
# Thanks to uwe58 and others for hints
|
7
|
+
|
8
|
+
class TestFilenameAccess < TestCase
|
9
|
+
|
10
|
+
@@running_on_windows = /mswin|mingw|cygwin/ === RbConfig::CONFIG['host_os']
|
11
|
+
|
12
|
+
@@fs_enc = Encoding.find('filesystem')
|
13
|
+
|
14
|
+
def create_testfile(basename_new)
|
15
|
+
tmpdir = Dir.tmpdir
|
16
|
+
filename_org = File.join(File.dirname(__FILE__), 'data/test.jpg')
|
17
|
+
filename_new = File.join(tmpdir, basename_new)
|
18
|
+
FileUtils.cp filename_org, filename_new.encode(@@fs_enc)
|
19
|
+
filename_new
|
20
|
+
end
|
21
|
+
|
22
|
+
def do_testing_with(basename)
|
23
|
+
filename_test = create_testfile(basename)
|
24
|
+
# read
|
25
|
+
m = MiniExiftool.new filename_test
|
26
|
+
assert_equal 400, m.iso
|
27
|
+
# save
|
28
|
+
m.iso = 200
|
29
|
+
m.save
|
30
|
+
assert_equal 200, m.iso
|
31
|
+
# Check original filename maybe with other encoding than filesystem
|
32
|
+
assert_equal basename, File.basename(m.filename)
|
33
|
+
rescue Exception => e
|
34
|
+
assert false, "File #{filename_test.inspect} not found!"
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_access_filename_with_spaces
|
38
|
+
do_testing_with 'filename with spaces.jpg'
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_access_filename_with_special_chars
|
42
|
+
do_testing_with 'filename_with_Ümläüts.jpg'
|
43
|
+
end
|
44
|
+
|
45
|
+
unless @@running_on_windows
|
46
|
+
def test_access_filename_with_doublequotes
|
47
|
+
do_testing_with 'filename_with_"doublequotes"_inside.jpg'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_access_filename_with_dollar_sign
|
52
|
+
# Thanks to Michael Dungan for the hint
|
53
|
+
do_testing_with 'filename_with_$_sign.jpg'
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_access_filename_with_ampersand
|
57
|
+
do_testing_with 'filename_with_&_sign.jpg'
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -- encoding: utf-8 --
|
2
|
+
require 'helpers_for_test'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
# Thanks to Chris Salzberg (aka shioyama) and
|
6
|
+
# Robert May (aka robotmay) for precious hints
|
7
|
+
|
8
|
+
class TestInvalidByteSequenceInUtf8 < TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@json = File.read(File.dirname(__FILE__) + '/data/invalid_byte_sequence_in_utf8.json')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_invalid_byte_sequence_in_utf8_cause_error
|
15
|
+
assert_raises ArgumentError do
|
16
|
+
MiniExiftool.from_json(@json)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_replace_invalid_chars
|
21
|
+
assert_nothing_raised do
|
22
|
+
mini_exiftool = MiniExiftool.from_json(@json, :replace_invalid_chars => '')
|
23
|
+
assert_equal 1036, mini_exiftool.color_balance_unknown.size
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_exiftool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Friedrich
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-06-
|
11
|
+
date: 2013-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rim
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- test/data/Bad_PreviewIFD.jpg
|
39
39
|
- test/data/Canon.jpg
|
40
40
|
- test/data/INFORMATION
|
41
|
+
- test/data/invalid_byte_sequence_in_utf8.json
|
41
42
|
- test/data/test.jpg
|
42
43
|
- test/data/test.jpg.json
|
43
44
|
- test/data/test_coordinates.jpg
|
@@ -47,7 +48,9 @@ files:
|
|
47
48
|
- test/test_class_methods.rb
|
48
49
|
- test/test_composite.rb
|
49
50
|
- test/test_dumping.rb
|
51
|
+
- test/test_filename_access.rb
|
50
52
|
- test/test_from_hash.rb
|
53
|
+
- test/test_invalid_byte_sequence_in_utf8.rb
|
51
54
|
- test/test_read.rb
|
52
55
|
- test/test_read_coordinates.rb
|
53
56
|
- test/test_read_numerical.rb
|
@@ -55,6 +58,7 @@ files:
|
|
55
58
|
- test/test_special.rb
|
56
59
|
- test/test_special_dates.rb
|
57
60
|
- test/test_write.rb
|
61
|
+
- Tutorial.rdoc
|
58
62
|
homepage: http://gitorious.org/mini_exiftool
|
59
63
|
licenses: []
|
60
64
|
metadata: {}
|
@@ -81,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
85
|
version: '0'
|
82
86
|
requirements: []
|
83
87
|
rubyforge_project:
|
84
|
-
rubygems_version: 2.0.
|
88
|
+
rubygems_version: 2.0.3
|
85
89
|
signing_key:
|
86
90
|
specification_version: 4
|
87
91
|
summary: This library is wrapper for the Exiftool command-line application (http://www.sno.phy.queensu.ca/~phil/exiftool).
|