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 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).