class MiniExiftool
Simple OO access to the Exiftool command-line application.
Constants
- VERSION
Attributes
Public Class Methods
Returns the command name of the called Exiftool application.
# File lib/mini_exiftool/mini_exiftool.rb, line 217 def self.command @@cmd end
Setting the command name of the called Exiftool application.
# File lib/mini_exiftool/mini_exiftool.rb, line 222 def self.command= cmd @@cmd = cmd end
Returns the version of the Exiftool command-line application.
# File lib/mini_exiftool/mini_exiftool.rb, line 256 def self.exiftool_version output = `#{MiniExiftool.command} -ver 2>&1` unless $?.exitstatus == 0 raise MiniExiftool::Error.new("Command '#{MiniExiftool.command}' not found") end output.chomp! end
Create a MiniExiftool
instance from a hash
# File lib/mini_exiftool/mini_exiftool.rb, line 204 def self.from_hash hash instance = MiniExiftool.new instance.initialize_from_hash hash instance end
Create a MiniExiftool
instance from YAML data created with MiniExiftool#to_yaml
# File lib/mini_exiftool/mini_exiftool.rb, line 212 def self.from_yaml yaml MiniExiftool.from_hash YAML.load(yaml) end
opts
support at the moment
-
:numerical
for numerical values, default isfalse
-
:composite
for including composite tags while loading, default istrue
-
:convert_encoding
convert encoding (See -L-option of the exiftool command-line application, default isfalse
) -
:ignore_minor_errors
ignore minor errors (See -m-option
of the exiftool command-line application, default is false
)
-
: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!
# File lib/mini_exiftool/mini_exiftool.rb, line 54 def initialize filename=nil, opts={} opts = @@opts.merge opts @numerical = opts[:numerical] @composite = opts[:composite] @convert_encoding = opts[:convert_encoding] @ignore_minor_errors = opts[:ignore_minor_errors] @timestamps = opts[:timestamps] @values = TagHash.new @tag_names = TagHash.new @changed_values = TagHash.new @errors = TagHash.new load filename unless filename.nil? end
Returns the options hash.
# File lib/mini_exiftool/mini_exiftool.rb, line 227 def self.opts @@opts end
Returns the original Exiftool name of the given tag
# File lib/mini_exiftool/mini_exiftool.rb, line 248 def self.original_tag tag unless defined? @@all_tags_map @@all_tags_map = pstore_get :all_tags_map end @@all_tags_map[tag] end
# File lib/mini_exiftool/mini_exiftool.rb, line 264 def self.unify tag tag.to_s.gsub(/[-_]/,'').downcase end
Private Class Methods
# File lib/mini_exiftool/mini_exiftool.rb, line 402 def self.load_or_create_pstore # This will hopefully work on *NIX and Windows systems home = ENV['HOME'] || ENV['HOMEDRIVE'] + ENV['HOMEPATH'] || ENV['USERPROFILE'] subdir = RUBY_PLATFORM =~ /\bmswin/i ? '_mini_exiftool' : '.mini_exiftool' FileUtils.mkdir_p(File.join(home, subdir)) filename = File.join(home, subdir, 'exiftool_tags_' << exiftool_version.gsub('.', '_') << '.pstore') @@pstore = PStore.new filename if !File.exist?(filename) || File.size(filename) == 0 @@pstore.transaction do |ps| ps[:all_tags] = all_tags = determine_tags('list') ps[:writable_tags] = determine_tags('listw') map = {} all_tags.each { |k| map[unify(k)] = k } ps[:all_tags_map] = map end end end
# File lib/mini_exiftool/mini_exiftool.rb, line 393 def self.pstore_get attribute load_or_create_pstore unless defined? @@pstore result = nil @@pstore.transaction(true) do |ps| result = ps[attribute] end result end
Public Instance Methods
Returns the value of a tag.
# File lib/mini_exiftool/mini_exiftool.rb, line 107 def [] tag @changed_values[tag] || @values[tag] end
Set the value of a tag.
# File lib/mini_exiftool/mini_exiftool.rb, line 112 def []=(tag, val) @changed_values[tag] = val end
Returns true if any tag value is changed or if the value of a given tag is changed.
# File lib/mini_exiftool/mini_exiftool.rb, line 118 def changed? tag=false if tag @changed_values.include? tag else !@changed_values.empty? end end
Load the tags of filename.
# File lib/mini_exiftool/mini_exiftool.rb, line 77 def load filename unless filename && File.exist?(filename) raise MiniExiftool::Error.new("File '#{filename}' does not exist.") end if File.directory?(filename) raise MiniExiftool::Error.new("'#{filename}' is a directory.") end @filename = filename @values.clear @tag_names.clear @changed_values.clear opt_params = '' opt_params << (@numerical ? '-n ' : '') opt_params << (@composite ? '' : '-e ') opt_params << (@convert_encoding ? '-L ' : '') cmd = %Q(#@@cmd -q -q -s -t #{opt_params} #{@@sep_op} #{Shellwords.escape(filename)}) if run(cmd) parse_output else raise MiniExiftool::Error.new(@error_text) end self end
Reload the tags of an already read file.
# File lib/mini_exiftool/mini_exiftool.rb, line 102 def reload load @filename end
Revert all changes or the change of a given tag.
# File lib/mini_exiftool/mini_exiftool.rb, line 127 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 the changes to the file.
# File lib/mini_exiftool/mini_exiftool.rb, line 149 def save 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, 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 e} tag_params = '' arr_val.each do |v| tag_params << %Q(-#{original_tag}=#{Shellwords.escape(v.to_s)} ) end opt_params = '' opt_params << (arr_val.detect {|x| x.kind_of?(Numeric)} ? '-n ' : '') opt_params << (@convert_encoding ? '-L ' : '') opt_params << (@ignore_minor_errors ? '-m' : '') cmd = %Q(#@@cmd -q -P -overwrite_original #{opt_params} #{tag_params} #{temp_filename}) if convert_encoding && cmd.respond_to?(:encode) cmd.encode('ISO-8859-1') end result = run(cmd) 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 reload end temp_file.delete all_ok end
Returns a hash of the original loaded values of the MiniExiftool
instance.
# File lib/mini_exiftool/mini_exiftool.rb, line 189 def to_hash result = {} @values.each do |k,v| result[@tag_names[k]] = v end result end
Returns a YAML representation of the original loaded values of the MiniExiftool
instance.
# File lib/mini_exiftool/mini_exiftool.rb, line 199 def to_yaml to_hash.to_yaml end
Private Instance Methods
# File lib/mini_exiftool/mini_exiftool.rb, line 311 def convert val case val when Time val = val.strftime('%Y:%m:%d %H:%M:%S') end val end
# File lib/mini_exiftool/mini_exiftool.rb, line 319 def method_missing symbol, *args tag_name = symbol.id2name if tag_name.sub!(/=$/, '') self[tag_name] = args.first else self[tag_name] end end
# File lib/mini_exiftool/mini_exiftool.rb, line 335 def parse_line line if line =~ /^([^\t]+)\t(.*)$/ tag, value = $1, $2 case value when /^\d{4}:\d\d:\d\d \d\d:\d\d:\d\d/ s = value.sub(/^(\d+):(\d+):/, '\1-\2-') begin if @timestamps == Time value = Time.parse(s) elsif @timestamps == DateTime value = DateTime.parse(s) else raise MiniExiftool::Error.new("Value #@timestamps not allowed for option timestamps.") end rescue ArgumentError value = false end when /^\d+\.\d+$/ value = value.to_f when /^0+[1-9]+$/ # nothing => String when /^-?\d+$/ value = value.to_i when %r(^(\d+)/(\d+)$) value = Rational($1.to_i, $2.to_i) when /^[\d ]+$/ # nothing => String when /#{@@separator}/ value = value.split @@separator end else raise MiniExiftool::Error.new("Malformed line #{line.inspect} of exiftool output.") end return [tag, value] end
# File lib/mini_exiftool/mini_exiftool.rb, line 328 def parse_output @output.each_line do |line| tag, value = parse_line line set_value tag, value end end
# File lib/mini_exiftool/mini_exiftool.rb, line 293 def run cmd if $DEBUG $stderr.puts cmd end @output = `#{cmd} 2>#{@@error_file.path}` if convert_encoding && @output.respond_to?(:force_encoding) @output.force_encoding('ISO-8859-1') end @status = $? unless @status.exitstatus == 0 @error_text = File.readlines(@@error_file.path).join return false else @error_text = '' return true end end
# File lib/mini_exiftool/mini_exiftool.rb, line 376 def set_attributes_by_heuristic self.composite = tags.include?('ImageSize') ? true : false self.numerical = self.file_size.kind_of?(Integer) ? true : false # TODO: Is there a heuristic to determine @convert_encoding? self.timestamps = self.FileModifyDate.kind_of?(DateTime) ? DateTime : Time end
# File lib/mini_exiftool/mini_exiftool.rb, line 371 def set_value tag, value @tag_names[tag] = tag @values[tag] = value end
# File lib/mini_exiftool/mini_exiftool.rb, line 383 def temp_filename unless @temp_filename temp_file = Tempfile.new('mini-exiftool') temp_file.close FileUtils.cp(@filename, temp_file.path) @temp_filename = temp_file.path end @temp_filename end