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.12.1'
- @@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)
106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/mini_exiftool.rb', line 106 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)
421 422 423 424 425 426 427 428 |
# File 'lib/mini_exiftool.rb', line 421 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.
55 56 57 |
# File 'lib/mini_exiftool.rb', line 55 def errors @errors end |
#filename ⇒ Object (readonly)
Returns the value of attribute filename.
55 56 57 |
# File 'lib/mini_exiftool.rb', line 55 def filename @filename end |
#io ⇒ Object (readonly)
Returns the value of attribute io.
55 56 57 |
# File 'lib/mini_exiftool.rb', line 55 def io @io end |
Class Method Details
.all_tags ⇒ Object
Returns a set of all known tags of ExifTool.
328 329 330 331 332 333 |
# File 'lib/mini_exiftool.rb', line 328 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.
313 314 315 |
# File 'lib/mini_exiftool.rb', line 313 def self.command @@cmd end |
.command=(cmd) ⇒ Object
Setting the command name of the called ExifTool application.
318 319 320 |
# File 'lib/mini_exiftool.rb', line 318 def self.command= cmd @@cmd = cmd end |
.encoding_opt(enc_type) ⇒ Object
62 63 64 |
# File 'lib/mini_exiftool.rb', line 62 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.
352 353 354 355 356 357 358 |
# File 'lib/mini_exiftool.rb', line 352 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.
292 293 294 295 296 |
# File 'lib/mini_exiftool.rb', line 292 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.
300 301 302 303 304 |
# File 'lib/mini_exiftool.rb', line 300 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
308 309 310 |
# File 'lib/mini_exiftool.rb', line 308 def self.from_yaml yaml, opts={} MiniExiftool.from_hash YAML.unsafe_load(yaml), opts end |
.opts ⇒ Object
Returns the options hash.
323 324 325 |
# File 'lib/mini_exiftool.rb', line 323 def self.opts @@opts end |
.opts_accessor(*attrs) ⇒ Object
44 45 46 47 48 49 50 51 52 53 |
# File 'lib/mini_exiftool.rb', line 44 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
344 345 346 347 348 349 |
# File 'lib/mini_exiftool.rb', line 344 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
366 367 368 369 370 371 372 373 374 |
# File 'lib/mini_exiftool.rb', line 366 def self.pstore_dir unless defined? @@pstore_dir # This will hopefully work on *NIX and Windows systems home = ENV['HOME'] || ENV['HOMEDRIVE'] + ENV['HOMEPATH'] || ENV['USERPROFILE'] subdir = @@running_on_windows ? '_mini_exiftool' : '.mini_exiftool' @@pstore_dir = File.join(home, subdir) end @@pstore_dir end |
.pstore_dir=(dir) ⇒ Object
376 377 378 |
# File 'lib/mini_exiftool.rb', line 376 def self.pstore_dir= dir @@pstore_dir = dir end |
.unify(tag) ⇒ Object
360 361 362 |
# File 'lib/mini_exiftool.rb', line 360 def self.unify tag tag.to_s.gsub(/[-_]/,'').downcase end |
.writable_tags ⇒ Object
Returns a set of all possible writable tags of ExifTool.
336 337 338 339 340 341 |
# File 'lib/mini_exiftool.rb', line 336 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.
172 173 174 |
# File 'lib/mini_exiftool.rb', line 172 def [] tag @changed_values[tag] || @values[tag] end |
#[]=(tag, val) ⇒ Object
Set the value of a tag.
177 178 179 |
# File 'lib/mini_exiftool.rb', line 177 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.
183 184 185 186 187 188 189 |
# File 'lib/mini_exiftool.rb', line 183 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.
209 210 211 |
# File 'lib/mini_exiftool.rb', line 209 def @changed_values.keys.map { |key| MiniExiftool.original_tag(key) } end |
#copy_tags_from(source_filename, tags) ⇒ Object
260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/mini_exiftool.rb', line 260 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:
120 121 122 123 124 |
# File 'lib/mini_exiftool.rb', line 120 def initialize_from_hash hash # :nodoc: set_values hash set_opts_by_heuristic self end |
#initialize_from_json(json) ⇒ Object
:nodoc:
126 127 128 129 130 131 |
# File 'lib/mini_exiftool.rb', line 126 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.
134 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 |
# File 'lib/mini_exiftool.rb', line 134 def load filename_or_io if filename_or_io.respond_to? :to_str # 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_str 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.
167 168 169 |
# File 'lib/mini_exiftool.rb', line 167 def reload load @filename end |
#revert(tag = nil) ⇒ Object
Revert all changes or the change of a given tag.
192 193 194 195 196 197 198 199 200 201 |
# File 'lib/mini_exiftool.rb', line 192 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.
214 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 |
# File 'lib/mini_exiftool.rb', line 214 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
250 251 252 253 254 255 256 257 258 |
# File 'lib/mini_exiftool.rb', line 250 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.
204 205 206 |
# File 'lib/mini_exiftool.rb', line 204 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.
276 277 278 279 280 281 282 |
# File 'lib/mini_exiftool.rb', line 276 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.
286 287 288 |
# File 'lib/mini_exiftool.rb', line 286 def to_yaml to_hash.to_yaml end |