mini_exiftool 2.1.0 → 2.2.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.
- 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).
|