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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1912be3f9461bf694e7907689e59f190dd57b8e3
4
- data.tar.gz: 936637b9820b7dfcde601b5a3651511e09735f05
3
+ metadata.gz: 2970f3d46bd1c8af75467b6914b3bc0f13723615
4
+ data.tar.gz: 2ac12585911106fe8b086b24f8d881f4f2b830aa
5
5
  SHA512:
6
- metadata.gz: 3473fbaae4cf7b83d3e0ac540eb2929ae8ce49d28d2466584199f41ddbf8d8f432603e99db695349a73627de8fc9ec5ad4662528c9891beea133987e7661465a
7
- data.tar.gz: d59167d91ce3b8d6ff5686d909a3d12e87a5861c9ea948fd814267e96a0c62c02b47725d08fb26bd37ffd1f63fc855442d7b6445cf71b964562fd21e9ca3db9b
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
@@ -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
- Tutorial[link://file.Tutorial.html] and have a look at the examples in
58
- directory examples.
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 |
@@ -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.
@@ -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, :timestamps => Time }
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, :timestamps
39
+ attr_accessor :numerical, :composite, :ignore_minor_errors, :errors,
40
+ :replace_invalid_chars, :timestamps
35
41
 
36
- VERSION = '2.1.0'
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
- # of the exiftool command-line application, default is +false+)
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, perform_conversions(value)
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
- opt_params = ''
93
- opt_params << (@numerical ? '-n ' : '')
94
- opt_params << (@composite ? '' : '-e ')
95
- opt_params << (@coord_format ? "-c \"#{@coord_format}\"" : '')
96
- cmd = %Q(#@@cmd -j -q -q -s -t #{opt_params} #{MiniExiftool.escape(filename)})
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 []=(tag, val)
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| convert e}
166
- tag_params = ''
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
- tag_params << %Q(-#{original_tag}=#{MiniExiftool.escape(v)} )
186
+ params << %Q(-#{original_tag}=#{escape(v)} )
169
187
  end
170
- opt_params = ''
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 conversions will be applied if neccesary.
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 convert val
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 = perform_conversions(value)
360
+ value = convert_after_load(value)
329
361
  set_value tag, value
330
362
  end
331
363
  end
332
364
 
333
- def perform_conversions(value)
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 = RUBY_PLATFORM =~ /\bmswin/i ? '_mini_exiftool' : '.mini_exiftool'
420
+ subdir = @@running_on_windows ? '_mini_exiftool' : '.mini_exiftool'
397
421
  FileUtils.mkdir_p(File.join(home, subdir))
398
- filename = File.join(home, subdir, 'exiftool_tags_' << exiftool_version.gsub('.', '_') << '.pstore')
399
- @@pstore = PStore.new filename
400
- if !File.exist?(filename) || File.size(filename) == 0
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
- def self.escape(val)
423
- '"' << val.to_s.gsub(/\\/, '\\'*4).gsub(/"/, '\"') << '"'
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-J’W=�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.1.0
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-06 00:00:00.000000000 Z
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.2
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).