exiftoolr 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ecd656c3093b0eb6f3f94cc402bf5ee14a9b13ba
4
- data.tar.gz: a8129d314f15fe908720f07393581b251ae95bfa
3
+ metadata.gz: 86c98c6b3dee0ab28c3ca8f2d5a5707abceb771a
4
+ data.tar.gz: 0e3a10c593d43ad8a1eac4cad6e2771f3adb82d8
5
5
  SHA512:
6
- metadata.gz: d8bcb6cc7a2dce7917f64c00e616f2493662562ff11ecfbc1bc49665311fd372c6ce057db7e343d45e7cd09e815cdf1ea3dd1f0bed395e086e57c17bbb62c685
7
- data.tar.gz: 051740e233bd226e7293e4dd332bd22f1de4cc785f670bd3f43b324481d958c75f7ae515199bb8e654f58bd7c002ac3e8a2487b46dbc8f32068909b5d892d9e4
6
+ metadata.gz: 9bfcc98ac2e68a9d958d1879170ab6adae73e026239f5978c1db7d0fd887f25796dda5b30cb3d94f270deb4b1f056aee62166295978eebeee6672fe8588da130
7
+ data.tar.gz: 232d3ac4d5d4f0993d6801a7ce16ff6681185be71bc2ca6a9306cfe35e95666e419e667da6b7c95c2264e8e30f2152b7a53be1ac9d9f4b88066fa44add6846dc
data/README.md CHANGED
@@ -8,77 +8,19 @@ This gem is the simplest thing that could possibly work that
8
8
  reads the output of [exiftool](http://www.sno.phy.queensu.ca/~phil/exiftool)
9
9
  and renders it into a ruby hash, with correctly typed values and symbolized keys.
10
10
 
11
- Rubies 1.9 and later are supported.
11
+ Note that this gem was renamed from 'exiftoolr' to the less-ungainly 'exiftool'
12
+ as of version 0.2.0. This gem simply adds a "class alias" from Exiftoolr to Exiftool,
13
+ and is dependant on that new gem.
12
14
 
13
- ## What constitutes "correct values"?
15
+ Consumers should switch to the new gem's namespace as soon as possible.
14
16
 
15
- * GPS latitude and longitude are rendered as signed floats,
16
- where north and east are positive, and west and south are negative.
17
- * Values like shutter speed and exposure time are rendered as Rationals,
18
- which lets the caller show them as fractions (1/250) or as comparable numeric instances.
19
- * String values like "interop" and "serial number" are kept as strings
20
- (which preserves zero prefixes)
21
- * Timestamps are attempted to be interpreted with correct timezones and sub-second resolution, if
22
- the header contains that data.
23
- Please note that EXIF headers don't always include a timezone offset, so we just adopt the system
24
- timezone, which may, of course, be wrong.
17
+ Go to [exiftool](https://github.com/mceachen/exiftool) for more information!
25
18
 
26
- ## Usage
27
-
28
- ```ruby
29
- require 'exiftoolr'
30
- e = Exiftoolr.new("path/to/iPhone 4S.jpg")
31
- e.to_hash
32
- # => {:make => "Apple", :gps_longitude => -122.47566667, …
33
- e.to_display_hash
34
- # => {"Make" => "Apple", "GPS Longitude" => -122.47566667, …
35
- ```
36
-
37
- ### Multiple file support
38
-
39
- This gem supports Exiftool's multiget, which lets you fetch metadata for many files at once.
40
-
41
- This can be dramatically more efficient (like, 60x faster) than spinning up the ```exiftool```
42
- process for each file.
43
-
44
- Supply an array to the Exiftoolr initializer, then use ```.result_for```:
45
-
46
- ```ruby
47
- require 'exiftoolr'
48
- e = Exiftoolr.new(Dir["**/*.jpg"])
49
- result = e.result_for("path/to/iPhone 4S.jpg")
50
- result.to_hash
51
- # => {:make => "Apple", :gps_longitude => -122.47566667, …
52
- result[:gps_longitude]
53
- # => -122.47566667
54
-
55
- e.files_with_results
56
- # => ["path/to/iPhone 4S.jpg", "path/to/Droid X.jpg", …
57
- ```
58
-
59
- ### When things go wrong
60
-
61
- * ```Exiftoolr::NoSuchFile``` is raised if the provided filename doesn't exist.
62
- * ```Exiftoolr::ExiftoolNotInstalled``` is raised if ```exiftool``` isn't in your ```PATH```.
63
- * If ExifTool has a problem reading EXIF data, no exception is raised, but ```#errors?``` will return true:
64
-
65
- ```ruby
66
- Exiftoolr.new("Gemfile").errors?
67
- #=> true
68
- ```
69
-
70
-
71
- ## Installation
72
-
73
- First [install ExifTool](http://www.sno.phy.queensu.ca/~phil/exiftool/install.html).
74
-
75
- Then, add this your Gemfile:
76
-
77
- gem 'exiftoolr'
19
+ ## Change history
78
20
 
79
- and then run ```bundle```.
21
+ ### 0.2.0
80
22
 
81
- ## Change history
23
+ * Renamed to 'exiftool' (but kept backward compatibility)
82
24
 
83
25
  ### 0.1.0
84
26
 
@@ -1,11 +1,10 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'exiftoolr/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
6
  spec.name = 'exiftoolr'
8
- spec.version = Exiftoolr::VERSION
7
+ spec.version = Gem::Version.new('0.2.0')
9
8
  spec.authors = ['Matthew McEachen']
10
9
  spec.email = %w(matthew-github@mceachen.org)
11
10
  spec.homepage = 'https://github.com/mceachen/exiftoolr'
@@ -21,6 +20,7 @@ Gem::Specification.new do |spec|
21
20
  spec.requirements << 'ExifTool (see http://www.sno.phy.queensu.ca/~phil/exiftool/)'
22
21
 
23
22
  spec.add_dependency 'json'
23
+ spec.add_dependency 'exiftool'
24
24
  spec.add_development_dependency 'rake'
25
25
  spec.add_development_dependency 'bundler'
26
26
  spec.add_development_dependency 'yard'
@@ -1,73 +1,3 @@
1
- require 'json'
2
- require 'shellwords'
3
- require 'exiftoolr/result'
1
+ require 'exiftool'
4
2
 
5
- class Exiftoolr
6
- class NoSuchFile < StandardError ; end
7
- class NotAFile < StandardError ; end
8
- class ExiftoolNotInstalled < StandardError ; end
9
-
10
- def self.exiftool_installed?
11
- exiftool_version > 0
12
- end
13
-
14
- def self.exiftool_version
15
- @@exiftool_version ||= `exiftool -ver 2> /dev/null`.to_f
16
- end
17
-
18
- def self.expand_path(filename)
19
- raise(NoSuchFile, filename) unless File.exist?(filename)
20
- raise(NotAFile, filename) unless File.file?(filename)
21
- File.expand_path(filename)
22
- end
23
-
24
- def initialize(filenames, exiftool_opts = '')
25
- @file2result = {}
26
- filenames = [filenames] if filenames.is_a?(String)
27
- unless filenames.empty?
28
- escaped_filenames = filenames.collect do |f|
29
- Shellwords.escape(self.class.expand_path(f.to_s))
30
- end.join(" ")
31
- # I'd like to use -dateformat, but it doesn't support timezone offsets properly,
32
- # nor sub-second timestamps.
33
- cmd = "exiftool #{exiftool_opts} -j -coordFormat \"%.8f\" #{escaped_filenames} 2> /dev/null"
34
- json = `#{cmd}`
35
- raise ExiftoolNotInstalled if json == ""
36
- JSON.parse(json).each do |raw|
37
- result = Result.new(raw)
38
- @file2result[result.source_file] = result
39
- end
40
- end
41
- end
42
-
43
- def result_for(filename)
44
- @file2result[self.class.expand_path(filename)]
45
- end
46
-
47
- def files_with_results
48
- @file2result.values.collect { |r| r.source_file unless r.errors? }.compact
49
- end
50
-
51
- def to_hash
52
- first.to_hash
53
- end
54
-
55
- def to_display_hash
56
- first.to_display_hash
57
- end
58
-
59
- def symbol_display_hash
60
- first.symbol_display_hash
61
- end
62
-
63
- def errors?
64
- @file2result.values.any? { |ea| ea.errors? }
65
- end
66
-
67
- private
68
-
69
- def first
70
- raise InvalidArgument, 'use #result_for when multiple filenames are used' if @file2result.size > 1
71
- @file2result.values.first
72
- end
73
- end
3
+ Exiftoolr = Exiftool
@@ -18,7 +18,7 @@ describe Exiftoolr do
18
18
  end
19
19
 
20
20
  it 'has errors with files without EXIF headers' do
21
- e = Exiftoolr.new("Gemfile")
21
+ e = Exiftoolr.new('Gemfile')
22
22
  e.errors?.must_be_true
23
23
  end
24
24
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exiftoolr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew McEachen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-14 00:00:00.000000000 Z
11
+ date: 2013-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: exiftool
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -122,9 +136,6 @@ files:
122
136
  - Rakefile
123
137
  - exiftoolr.gemspec
124
138
  - lib/exiftoolr.rb
125
- - lib/exiftoolr/parser.rb
126
- - lib/exiftoolr/result.rb
127
- - lib/exiftoolr/version.rb
128
139
  - test/Canon 20D.jpg
129
140
  - test/Canon 20D.jpg.yaml
130
141
  - test/Droid X.jpg
@@ -1,63 +0,0 @@
1
- require 'time'
2
- require 'date'
3
- require 'rational'
4
-
5
- class Exiftoolr
6
- class Parser
7
-
8
- WORD_BOUNDARY_RES = [/([A-Z\d]+)([A-Z][a-z])/, /([a-z\d])([A-Z])/]
9
- FRACTION_RE = /^(\d+)\/(\d+)$/
10
-
11
- attr_reader :key, :display_key, :sym_key, :raw_value
12
-
13
- def initialize(key, raw_value)
14
- @key = key
15
- @display_key = WORD_BOUNDARY_RES.inject(key) { |k, regex| k.gsub(regex, '\1 \2') }
16
- @sym_key = display_key.downcase.gsub(' ', '_').to_sym
17
- @raw_value = raw_value
18
- end
19
-
20
- def value
21
- for_lat_long ||
22
- for_date ||
23
- for_fraction ||
24
- raw_value
25
- rescue StandardError => e
26
- "Warning: Parsing '#{raw_value}' for attribute '#{key}' raised #{e.message}"
27
- end
28
-
29
- private
30
-
31
- def for_lat_long
32
- if sym_key == :gps_latitude || sym_key == :gps_longitude
33
- value, direction = raw_value.split(" ")
34
- if value =~ /\A\d+\.?\d*\z/
35
- value.to_f * (['S', 'W'].include?(direction) ? -1 : 1)
36
- end
37
- end
38
- end
39
-
40
- def for_date
41
- if raw_value.is_a?(String) && display_key =~ /\bdate\b/i
42
- try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S%z') } ||
43
- try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S') } ||
44
- try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S.%L%z') } ||
45
- try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S.%L') } ||
46
- try_parse { Time.parse(raw_value) }
47
- end
48
- end
49
-
50
- def try_parse
51
- yield
52
- rescue ArgumentError
53
- nil
54
- end
55
-
56
- def for_fraction
57
- if raw_value.is_a?(String)
58
- scan = raw_value.scan(FRACTION_RE).first
59
- v = Rational(*scan.map { |ea| ea.to_i }) unless scan.nil?
60
- end
61
- end
62
- end
63
- end
@@ -1,32 +0,0 @@
1
- require 'exiftoolr/parser'
2
-
3
- class Exiftoolr
4
- class Result
5
- attr_reader :to_hash, :to_display_hash, :symbol_display_hash
6
-
7
- def initialize(raw_hash)
8
- @raw_hash = raw_hash
9
- @to_hash = {}
10
- @to_display_hash = {}
11
- @symbol_display_hash = {}
12
- @raw_hash.each do |key, raw_value|
13
- p = Parser.new(key, raw_value)
14
- @to_hash[p.sym_key] = p.value
15
- @to_display_hash[p.display_key] = p.value
16
- @symbol_display_hash[p.sym_key] = p.display_key
17
- end
18
- end
19
-
20
- def [](key)
21
- @to_hash[key]
22
- end
23
-
24
- def source_file
25
- self[:source_file]
26
- end
27
-
28
- def errors?
29
- self[:error] == 'Unknown file type' || self[:warning] == 'Unsupported file type'
30
- end
31
- end
32
- end
@@ -1,3 +0,0 @@
1
- class Exiftoolr
2
- VERSION = Gem::Version.new('0.1.0')
3
- end