Class: Exiftool

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/exiftool.rb,
lib/exiftool/result.rb,
lib/exiftool/version.rb,
lib/exiftool/field_parser.rb

Overview

Exiftool Class

Defined Under Namespace

Classes: ExiftoolNotInstalled, FieldParser, NoDefaultResultWithMultiget, NoSuchFile, NotAFile, Result

Constant Summary collapse

VERSION =
Gem::Version.new('1.3.0')

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filenames, exiftool_opts = '') ⇒ Exiftool

Returns a new instance of Exiftool.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/exiftool.rb', line 62

def initialize(filenames, exiftool_opts = '')
  @file2result = {}
  io_input = nil
  if filenames.is_a?(IO)
    io_input = filenames
    filenames = ['-']
  end

  filenames = [filenames] if filenames.is_a?(String) || filenames.is_a?(Pathname)
  return if filenames.empty?

  expanded_filenames = filenames.map do |f|
    f == '-' ? '-' : self.class.expand_path(f.to_s)
  end
  args = [
    self.class.command,
    *Shellwords.split(exiftool_opts),
    '-j',
    '-coordFormat', '%.8f',
    *expanded_filenames
  ]

  json = ''
  begin
    Open3.popen3(*args) do |stdin, stdout, _stderr, wait_thr|
      if io_input
        IO.copy_stream(io_input, stdin)
        stdin.close
      end
      json = stdout.read.to_s.chomp
      wait_thr.value
    end
  rescue Errno::ENOENT
    json = ''
  end

  raise ExiftoolNotInstalled if json == ''

  JSON.parse(json).each do |raw|
    result = Result.new(raw)
    @file2result[result.source_file] = result
  end
end

Class Attribute Details

.commandObject



24
25
26
# File 'lib/exiftool.rb', line 24

def self.command
  @command ||= 'exiftool'
end

Class Method Details

.exiftool_installed?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/exiftool.rb', line 28

def self.exiftool_installed?
  exiftool_version.to_f.positive?
end

.exiftool_versionObject

This is a string, not a float, to handle versions like “9.40” properly.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/exiftool.rb', line 33

def self.exiftool_version
  return @exiftool_version if defined?(@exiftool_version) && @exiftool_version

  stdout_str = ''
  begin
    Open3.popen3(command, '-ver') do |_stdin, stdout, _stderr, wait_thr|
      stdout_str = stdout.read.to_s.chomp
      # Ensure the process is reaped
      wait_thr.value
    end
  rescue Errno::ENOENT
    stdout_str = ''
  end

  @exiftool_version = stdout_str
end

.expand_path(filename) ⇒ Object

Raises:



50
51
52
53
54
55
56
# File 'lib/exiftool.rb', line 50

def self.expand_path(filename)
  raise(NoSuchFile, filename) unless File.exist?(filename)

  raise(NotAFile, filename) unless File.file?(filename)

  File.expand_path(filename)
end

Instance Method Details

#errors?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/exiftool.rb', line 122

def errors?
  @file2result.values.any?(&:errors?)
end

#files_with_resultsObject



118
119
120
# File 'lib/exiftool.rb', line 118

def files_with_results
  results.map(&:source_file)
end

#result_for(filename) ⇒ Object



114
115
116
# File 'lib/exiftool.rb', line 114

def result_for(filename)
  @file2result[self.class.expand_path(filename)]
end

#results(include_results_with_errors: false) ⇒ Object



106
107
108
109
110
111
112
# File 'lib/exiftool.rb', line 106

def results(include_results_with_errors: false)
  if include_results_with_errors
    @file2result.values
  else
    @file2result.values.reject(&:errors?)
  end
end