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

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.



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
105
# File 'lib/exiftool.rb', line 63

def initialize(filenames, exiftool_opts = '')
  @file2result = {}
  io_input = nil
  if filenames.is_a?(IO) || filenames.is_a?(StringIO)
    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



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

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

Class Method Details

.exiftool_installed?Boolean

Returns:

  • (Boolean)


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

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.



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

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:



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

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)


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

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

#files_with_resultsObject



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

def files_with_results
  results.map(&:source_file)
end

#result_for(filename) ⇒ Object



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

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

#results(include_results_with_errors: false) ⇒ Object



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

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