Class: MiniExiftool
- Inherits:
-
Object
- Object
- MiniExiftool
- Defined in:
- lib/mini_exiftool.rb
Overview
Simple OO access to the ExifTool command-line application.
Defined Under Namespace
Modules: BackportYAML Classes: Error, TagHash
Constant Summary collapse
- VERSION =
'2.14.0'
- @@cmd =
Name of the ExifTool command-line application
'exiftool'
- @@opts =
Hash of the standard options used when call MiniExiftool.new
{ :numerical => false, :composite => true, :fast => false, :fast2 => false, :ignore_minor_errors => false, :replace_invalid_chars => false, :timestamps => Time }
- @@fs_enc =
Encoding of the filesystem (filenames in command line)
Encoding.find('filesystem')
- @@encoding_types =
%w(exif iptc xmp png id3 pdf photoshop quicktime aiff mie vorbis)
- @@running_on_windows =
Instance Attribute Summary collapse
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#filename ⇒ Object
readonly
Returns the value of attribute filename.
-
#io ⇒ Object
readonly
Returns the value of attribute io.
Class Method Summary collapse
-
.all_tags ⇒ Object
Returns a set of all known tags of ExifTool.
-
.command ⇒ Object
Returns the command name of the called ExifTool application.
-
.command=(cmd) ⇒ Object
Setting the command name of the called ExifTool application.
- .encoding_opt(enc_type) ⇒ Object
-
.exiftool_version ⇒ Object
Returns the version of the ExifTool command-line application.
-
.from_hash(hash, opts = {}) ⇒ Object
Create a MiniExiftool instance from a hash.
-
.from_json(json, opts = {}) ⇒ Object
Create a MiniExiftool instance from JSON data.
-
.from_yaml(yaml, opts = {}) ⇒ Object
Create a MiniExiftool instance from YAML data created with MiniExiftool#to_yaml.
-
.opts ⇒ Object
Returns the options hash.
- .opts_accessor(*attrs) ⇒ Object
-
.original_tag(tag) ⇒ Object
Returns the original ExifTool name of the given tag.
- .pstore_dir ⇒ Object
- .pstore_dir=(dir) ⇒ Object
- .unify(tag) ⇒ Object
-
.writable_tags ⇒ Object
Returns a set of all possible writable tags of ExifTool.
Instance Method Summary collapse
-
#[](tag) ⇒ Object
Returns the value of a tag.
-
#[]=(tag, val) ⇒ Object
Set the value of a tag.
-
#changed?(tag = false) ⇒ Boolean
Returns true if any tag value is changed or if the value of a given tag is changed.
-
#changed_tags ⇒ Object
Returns an array of all changed tags.
- #copy_tags_from(source_filename, tags) ⇒ Object
-
#initialize(filename_or_io = nil, opts = {}) ⇒ MiniExiftool
constructor
filename_or_io
The kind of the parameter is determined via duck typing: if the argument responds toto_str
it is interpreted as filename, if it responds toread
it is interpreted es IO instance. -
#initialize_from_hash(hash) ⇒ Object
:nodoc:.
-
#initialize_from_json(json) ⇒ Object
:nodoc:.
-
#load(filename_or_io) ⇒ Object
Load the tags of filename or io.
-
#reload ⇒ Object
Reload the tags of an already read file.
-
#revert(tag = nil) ⇒ Object
Revert all changes or the change of a given tag.
-
#save ⇒ Object
Save the changes to the file.
- #save! ⇒ Object
-
#tags ⇒ Object
Returns an array of the tags (original tag names) of the read file.
-
#to_hash ⇒ Object
Returns a hash of the original loaded values of the MiniExiftool instance.
-
#to_yaml ⇒ Object
Returns a YAML representation of the original loaded values of the MiniExiftool instance.
Constructor Details
#initialize(filename_or_io = nil, opts = {}) ⇒ MiniExiftool
filename_or_io
The kind of the parameter is determined via duck typing: if the argument responds to to_str
it is interpreted as filename, if it responds to read
it is interpreted es IO instance.
ATTENTION: If using an IO instance writing of meta data is not supported!
opts
support at the moment
-
:numerical
for numerical values, default isfalse
-
:composite
for including composite tags while loading, default istrue
-
:ignore_minor_errors
ignore minor errors (See -m-option of the exiftool command-line application, default isfalse
) -
:coord_format
set format for GPS coordinates (See -c-option of the exiftool command-line application, default isnil
that means exiftool standard) -
:fast
useful when reading JPEGs over a slow network connection (See -fast-option of the exiftool command-line application, default isfalse
) -
:fast2
useful when reading JPEGs over a slow network connection (See -fast2-option of the exiftool command-line application, default isfalse
) -
:replace_invalid_chars
replace string for invalid UTF-8 characters orfalse
if no replacing should be done, default isfalse
-
:timestamps
generating DateTime objects instead of Time objects if set toDateTime
, default isTime
ATTENTION: Time objects are created using
Time.local
therefore they use your local timezone, DateTime objects instead are created without timezone! -
:exif_encoding
,:iptc_encoding
,:xmp_encoding
,:png_encoding
,:id3_encoding
,:pdf_encoding
,:photoshop_encoding
,:quicktime_encoding
,:aiff_encoding
,:mie_encoding
,:vorbis_encoding
to set this specific encoding (see -charset option of the exiftool command-line application, default isnil
: no encoding specified)
107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/mini_exiftool.rb', line 107 def initialize filename_or_io=nil, opts={} @opts = @@opts.merge opts if @opts[:convert_encoding] warn 'Option :convert_encoding is not longer supported!' warn 'Please use the String#encod* methods.' end @filename = nil @io = nil @values = TagHash.new @changed_values = TagHash.new @errors = TagHash.new load filename_or_io unless filename_or_io.nil? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol, *args) ⇒ Object (private)
428 429 430 431 432 433 434 435 |
# File 'lib/mini_exiftool.rb', line 428 def method_missing symbol, *args tag_name = symbol.id2name if tag_name =~ /^(.+)=$/ self[$1] = args.first else self[tag_name] end end |
Instance Attribute Details
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
56 57 58 |
# File 'lib/mini_exiftool.rb', line 56 def errors @errors end |
#filename ⇒ Object (readonly)
Returns the value of attribute filename.
56 57 58 |
# File 'lib/mini_exiftool.rb', line 56 def filename @filename end |
#io ⇒ Object (readonly)
Returns the value of attribute io.
56 57 58 |
# File 'lib/mini_exiftool.rb', line 56 def io @io end |
Class Method Details
.all_tags ⇒ Object
Returns a set of all known tags of ExifTool.
329 330 331 332 333 334 |
# File 'lib/mini_exiftool.rb', line 329 def self. unless defined? @@all_tags @@all_tags = pstore_get :all_tags end @@all_tags end |
.command ⇒ Object
Returns the command name of the called ExifTool application.
314 315 316 |
# File 'lib/mini_exiftool.rb', line 314 def self.command @@cmd end |
.command=(cmd) ⇒ Object
Setting the command name of the called ExifTool application.
319 320 321 |
# File 'lib/mini_exiftool.rb', line 319 def self.command= cmd @@cmd = cmd end |
.encoding_opt(enc_type) ⇒ Object
63 64 65 |
# File 'lib/mini_exiftool.rb', line 63 def self.encoding_opt enc_type (enc_type.to_s + '_encoding').to_sym end |
.exiftool_version ⇒ Object
Returns the version of the ExifTool command-line application.
353 354 355 356 357 358 359 |
# File 'lib/mini_exiftool.rb', line 353 def self.exiftool_version Open3.popen3 "#{MiniExiftool.command} -ver" do |_inp, out, _err, _thr| out.read.chomp! end rescue SystemCallError raise MiniExiftool::Error.new("Command '#{MiniExiftool.command}' not found") end |
.from_hash(hash, opts = {}) ⇒ Object
Create a MiniExiftool instance from a hash. Default value conversions will be applied if neccesary.
293 294 295 296 297 |
# File 'lib/mini_exiftool.rb', line 293 def self.from_hash hash, opts={} instance = MiniExiftool.new nil, opts instance.initialize_from_hash hash instance end |
.from_json(json, opts = {}) ⇒ Object
Create a MiniExiftool instance from JSON data. Default value conversions will be applied if neccesary.
301 302 303 304 305 |
# File 'lib/mini_exiftool.rb', line 301 def self.from_json json, opts={} instance = MiniExiftool.new nil, opts instance.initialize_from_json json instance end |
.from_yaml(yaml, opts = {}) ⇒ Object
Create a MiniExiftool instance from YAML data created with MiniExiftool#to_yaml
309 310 311 |
# File 'lib/mini_exiftool.rb', line 309 def self.from_yaml yaml, opts={} MiniExiftool.from_hash YAML.unsafe_load(yaml), opts end |
.opts ⇒ Object
Returns the options hash.
324 325 326 |
# File 'lib/mini_exiftool.rb', line 324 def self.opts @@opts end |
.opts_accessor(*attrs) ⇒ Object
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/mini_exiftool.rb', line 45 def self.opts_accessor *attrs attrs.each do |a| define_method a do @opts[a] end define_method "#{a}=" do |val| @opts[a] = val end end end |
.original_tag(tag) ⇒ Object
Returns the original ExifTool name of the given tag
345 346 347 348 349 350 |
# File 'lib/mini_exiftool.rb', line 345 def self.original_tag tag unless defined? @@all_tags_map @@all_tags_map = pstore_get :all_tags_map end @@all_tags_map[tag] end |
.pstore_dir ⇒ Object
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/mini_exiftool.rb', line 367 def self.pstore_dir unless defined? @@pstore_dir @@pstore_dir = if env = ENV['MINI_EXIFTOOL_PSTORE_DIR'] env elsif defined?(Gem.cache_home) && File.writable?(Gem.cache_home) File.join(Gem.cache_home, 'mini_exiftool') else # This fallback will hopefully work on *NIX and Windows systems cache_dir = ENV['USERPROFILE'] || Dir.tmpdir File.join(cache_dir, 'mini_exiftool') end end @@pstore_dir end |
.pstore_dir=(dir) ⇒ Object
383 384 385 |
# File 'lib/mini_exiftool.rb', line 383 def self.pstore_dir= dir @@pstore_dir = dir end |
.unify(tag) ⇒ Object
361 362 363 |
# File 'lib/mini_exiftool.rb', line 361 def self.unify tag tag.to_s.gsub(/[-_]/,'').downcase end |
.writable_tags ⇒ Object
Returns a set of all possible writable tags of ExifTool.
337 338 339 340 341 342 |
# File 'lib/mini_exiftool.rb', line 337 def self. unless defined? @@writable_tags @@writable_tags = pstore_get :writable_tags end @@writable_tags end |
Instance Method Details
#[](tag) ⇒ Object
Returns the value of a tag.
173 174 175 |
# File 'lib/mini_exiftool.rb', line 173 def [] tag @changed_values[tag] || @values[tag] end |
#[]=(tag, val) ⇒ Object
Set the value of a tag.
178 179 180 |
# File 'lib/mini_exiftool.rb', line 178 def []= tag, val @changed_values[tag] = val end |
#changed?(tag = false) ⇒ Boolean
Returns true if any tag value is changed or if the value of a given tag is changed.
184 185 186 187 188 189 190 |
# File 'lib/mini_exiftool.rb', line 184 def changed? tag=false if tag @changed_values.include? tag else !@changed_values.empty? end end |
#changed_tags ⇒ Object
Returns an array of all changed tags.
210 211 212 |
# File 'lib/mini_exiftool.rb', line 210 def @changed_values.keys.map { |key| MiniExiftool.original_tag(key) } end |
#copy_tags_from(source_filename, tags) ⇒ Object
261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/mini_exiftool.rb', line 261 def (source_filename, ) @errors.clear unless File.exist?(source_filename) raise MiniExiftool::Error.new("Source file #{source_filename} does not exist!") end params = '-q -P -overwrite_original ' = Array().map {|t| '-' << t.to_s}.join(' ') cmd = [@@cmd, params, '-tagsFromFile', escape(source_filename).encode(@@fs_enc), .encode('UTF-8'), escape(filename).encode(@@fs_enc)].join(' ') cmd.force_encoding('UTF-8') result = run(cmd) reload result end |
#initialize_from_hash(hash) ⇒ Object
:nodoc:
121 122 123 124 125 |
# File 'lib/mini_exiftool.rb', line 121 def initialize_from_hash hash # :nodoc: set_values hash set_opts_by_heuristic self end |
#initialize_from_json(json) ⇒ Object
:nodoc:
127 128 129 130 131 132 |
# File 'lib/mini_exiftool.rb', line 127 def initialize_from_json json # :nodoc: @output = json @errors.clear parse_output self end |
#load(filename_or_io) ⇒ Object
Load the tags of filename or io.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/mini_exiftool.rb', line 135 def load filename_or_io if filename_or_io.respond_to?(:to_str) || filename_or_io.kind_of?(Pathname) # String-like unless filename_or_io && File.exist?(filename_or_io) raise MiniExiftool::Error.new("File '#{filename_or_io}' does not exist.") end if File.directory?(filename_or_io) raise MiniExiftool::Error.new("'#{filename_or_io}' is a directory.") end @filename = filename_or_io.to_s elsif filename_or_io.respond_to? :read # IO-like @io = filename_or_io @filename = '-' else raise MiniExiftool::Error.new("Could not open filename_or_io.") end @values.clear @changed_values.clear params = '-j ' params << (@opts[:numerical] ? '-n ' : '') params << (@opts[:composite] ? '' : '-e ') params << (@opts[:coord_format] ? "-c #{escape(@opts[:coord_format])}" : '') params << (@opts[:fast] ? '-fast ' : '') params << (@opts[:fast2] ? '-fast2 ' : '') params << generate_encoding_params if run(cmd_gen(params, @filename)) parse_output else raise MiniExiftool::Error.new(@error_text) end self end |
#reload ⇒ Object
Reload the tags of an already read file.
168 169 170 |
# File 'lib/mini_exiftool.rb', line 168 def reload load @filename end |
#revert(tag = nil) ⇒ Object
Revert all changes or the change of a given tag.
193 194 195 196 197 198 199 200 201 202 |
# File 'lib/mini_exiftool.rb', line 193 def revert tag=nil if tag val = @changed_values.delete(tag) res = val != nil else res = @changed_values.size > 0 @changed_values.clear end res end |
#save ⇒ Object
Save the changes to the file.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/mini_exiftool.rb', line 215 def save if @io raise MiniExiftool::Error.new('No writing support when using an IO.') end return false if @changed_values.empty? @errors.clear temp_file = Tempfile.new('mini_exiftool') temp_file.close temp_filename = temp_file.path FileUtils.cp filename.encode(@@fs_enc), temp_filename all_ok = true @changed_values.each do |tag, val| original_tag = MiniExiftool.original_tag(tag) arr_val = val.kind_of?(Array) ? val : [val] arr_val.map! {|e| convert_before_save(e)} params = '-q -P -overwrite_original ' params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '') params << (@opts[:ignore_minor_errors] ? '-m ' : '') params << generate_encoding_params arr_val.each do |v| params << %Q(-#{original_tag}=#{escape(v)} ) end result = run(cmd_gen(params, temp_filename)) unless result all_ok = false @errors[tag] = @error_text.gsub(/Nothing to do.\n\z/, '').chomp end end if all_ok FileUtils.cp temp_filename, filename.encode(@@fs_enc) reload end temp_file.delete all_ok end |
#save! ⇒ Object
251 252 253 254 255 256 257 258 259 |
# File 'lib/mini_exiftool.rb', line 251 def save! unless save err = [] @errors.each do |key, value| err << "(#{key}) #{value}" end raise MiniExiftool::Error.new("MiniExiftool couldn't save. The following errors occurred: #{err.empty? ? "None" : err.join(", ")}") end end |
#tags ⇒ Object
Returns an array of the tags (original tag names) of the read file.
205 206 207 |
# File 'lib/mini_exiftool.rb', line 205 def @values.keys.map { |key| MiniExiftool.original_tag(key) } end |
#to_hash ⇒ Object
Returns a hash of the original loaded values of the MiniExiftool instance.
277 278 279 280 281 282 283 |
# File 'lib/mini_exiftool.rb', line 277 def to_hash result = {} @values.each do |k,v| result[MiniExiftool.original_tag(k)] = v end result end |
#to_yaml ⇒ Object
Returns a YAML representation of the original loaded values of the MiniExiftool instance.
287 288 289 |
# File 'lib/mini_exiftool.rb', line 287 def to_yaml to_hash.to_yaml end |