exiftool 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/README.md +113 -0
- data/Rakefile +17 -0
- data/exiftool.gemspec +30 -0
- data/lib/exiftool.rb +73 -0
- data/lib/exiftool/parser.rb +62 -0
- data/lib/exiftool/result.rb +32 -0
- data/lib/exiftool/version.rb +3 -0
- data/test/Canon 20D.jpg +0 -0
- data/test/Canon 20D.jpg.yaml +225 -0
- data/test/Droid X.jpg +0 -0
- data/test/Droid X.jpg.yaml +89 -0
- data/test/IMG_2452.jpg +0 -0
- data/test/IMG_2452.jpg.yaml +211 -0
- data/test/exiftoolr_test.rb +87 -0
- data/test/faces.jpg +0 -0
- data/test/faces.jpg.yaml +318 -0
- data/test/iPhone 4S.jpg +0 -0
- data/test/iPhone 4S.jpg.yaml +82 -0
- data/test/parser_test.rb +58 -0
- data/test/test_helper.rb +14 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 97cc49e13b847ed687dca2430f6e3974d1327998
|
4
|
+
data.tar.gz: 7a6c7e780ad4962983b491c517d2f4a8a890264b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 614fee303365b7d799ebf3d29109502194ed89f35685f4dfabe45a729fd184a23e3d657bc4c91270e5c9ffdda7873f613956c4fa511bfa067f52996500f93f28
|
7
|
+
data.tar.gz: 97ad66d4cab65ea08313ae3b24222852ab9477113deb276eecb88dbda568d59833ddcd164485a5d68857cbca6393729443ddd792d9924d136785c4d1873136f9
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# Ruby wrapper for ExifTool
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/mceachen/exiftool.png?branch=master)](http://travis-ci.org/mceachen/exiftool)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/exiftool.png)](http://rubygems.org/gems/exiftool)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/mceachen/exiftool.png)](https://codeclimate.com/github/mceachen/exiftool)
|
6
|
+
|
7
|
+
This gem is the simplest thing that could possibly work that
|
8
|
+
reads the output of [exiftool](http://www.sno.phy.queensu.ca/~phil/exiftool)
|
9
|
+
and renders it into a ruby hash, with correctly typed values and symbolized keys.
|
10
|
+
|
11
|
+
Rubies 1.9 and later are supported.
|
12
|
+
|
13
|
+
## Features
|
14
|
+
|
15
|
+
* GPS latitude and longitude values are parsed 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.
|
25
|
+
* No method_missing madness
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'Exiftool'
|
31
|
+
e = Exiftool.new("path/to/iPhone 4S.jpg")
|
32
|
+
e.to_hash
|
33
|
+
# => {:make => "Apple", :gps_longitude => -122.47566667, …
|
34
|
+
e.to_display_hash
|
35
|
+
# => {"Make" => "Apple", "GPS Longitude" => -122.47566667, …
|
36
|
+
```
|
37
|
+
|
38
|
+
### Multiple file support
|
39
|
+
|
40
|
+
This gem supports Exiftool's multiget, which lets you fetch metadata for many files at once.
|
41
|
+
|
42
|
+
This can be dramatically more efficient (like, 60x faster) than spinning up the ```exiftool```
|
43
|
+
process for each file.
|
44
|
+
|
45
|
+
Supply an array to the Exiftool initializer, then use ```.result_for```:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'Exiftool'
|
49
|
+
e = Exiftool.new(Dir["**/*.jpg"])
|
50
|
+
result = e.result_for("path/to/iPhone 4S.jpg")
|
51
|
+
result.to_hash
|
52
|
+
# => {:make => "Apple", :gps_longitude => -122.47566667, …
|
53
|
+
result[:gps_longitude]
|
54
|
+
# => -122.47566667
|
55
|
+
|
56
|
+
e.files_with_results
|
57
|
+
# => ["path/to/iPhone 4S.jpg", "path/to/Droid X.jpg", …
|
58
|
+
```
|
59
|
+
|
60
|
+
### When things go wrong
|
61
|
+
|
62
|
+
* ```Exiftool::NoSuchFile``` is raised if the provided filename doesn't exist.
|
63
|
+
* ```Exiftool::ExiftoolNotInstalled``` is raised if ```exiftool``` isn't in your ```PATH```.
|
64
|
+
* If ExifTool has a problem reading EXIF data, no exception is raised, but ```#errors?``` will return true:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
Exiftool.new("Gemfile").errors?
|
68
|
+
#=> true
|
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 'exiftool'
|
78
|
+
|
79
|
+
and then run ```bundle```.
|
80
|
+
|
81
|
+
## Change history
|
82
|
+
|
83
|
+
### 0.2.0
|
84
|
+
|
85
|
+
* Renamed from exiftoolr to exiftool
|
86
|
+
|
87
|
+
### 0.1.0
|
88
|
+
|
89
|
+
* Better timestamp parsing—now both sub-second and timezone offsets are handled correctly
|
90
|
+
* Switched to minitest-spec
|
91
|
+
* Ruby 1.8.7 is no longer supported, hence the minor version uptick.
|
92
|
+
|
93
|
+
### 0.0.9
|
94
|
+
|
95
|
+
* Explicitly added MIT licensing to the gemspec.
|
96
|
+
|
97
|
+
### 0.0.8
|
98
|
+
|
99
|
+
* Extracted methods in parsing to make the code complexity lower. FOUR DOT OH GPA
|
100
|
+
|
101
|
+
### 0.0.7
|
102
|
+
|
103
|
+
* Added warning values for EXIF headers that are corrupt
|
104
|
+
* Made initialize gracefully accept an empty array, or an array of Pathname instances
|
105
|
+
* Added support for ruby 1.9.3 and exiftool v8.15 (Ubuntu Natty) and v8.85 (current stable version)
|
106
|
+
|
107
|
+
### 0.0.5
|
108
|
+
|
109
|
+
Fixed homepage URL in gemspec
|
110
|
+
|
111
|
+
### 0.0.4
|
112
|
+
|
113
|
+
Added support for multiple file fetching (which is *much* faster for large directories)
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'yard'
|
4
|
+
YARD::Rake::YardocTask.new do |t|
|
5
|
+
t.files = ['lib/**/*.rb', 'README.md']
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'rake/testtask'
|
9
|
+
|
10
|
+
Rake::TestTask.new do |t|
|
11
|
+
t.libs.push "lib"
|
12
|
+
t.libs.push "test"
|
13
|
+
t.pattern = 'test/**/*_test.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => :test
|
data/exiftool.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'exiftool/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'exiftool'
|
8
|
+
spec.version = Exiftool::VERSION
|
9
|
+
spec.authors = ['Matthew McEachen']
|
10
|
+
spec.email = %w(matthew-github@mceachen.org)
|
11
|
+
spec.homepage = 'https://github.com/mceachen/exiftoolr'
|
12
|
+
spec.summary = %q{Multiget ExifTool wrapper for ruby}
|
13
|
+
spec.description = %q{Multiget ExifTool wrapper for ruby}
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split("\n")
|
17
|
+
spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.requirements << 'ExifTool (see http://www.sno.phy.queensu.ca/~phil/exiftool/)'
|
22
|
+
|
23
|
+
spec.add_dependency 'json'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'bundler'
|
26
|
+
spec.add_development_dependency 'yard'
|
27
|
+
spec.add_development_dependency 'minitest'
|
28
|
+
spec.add_development_dependency 'minitest-great_expectations'
|
29
|
+
spec.add_development_dependency 'minitest-reporters' unless ENV['CI']
|
30
|
+
end
|
data/lib/exiftool.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'shellwords'
|
3
|
+
require 'exiftool/result'
|
4
|
+
|
5
|
+
class Exiftool
|
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
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'rational'
|
3
|
+
|
4
|
+
class Exiftool
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
WORD_BOUNDARY_RES = [/([A-Z\d]+)([A-Z][a-z])/, /([a-z\d])([A-Z])/]
|
8
|
+
FRACTION_RE = /^(\d+)\/(\d+)$/
|
9
|
+
|
10
|
+
attr_reader :key, :display_key, :sym_key, :raw_value
|
11
|
+
|
12
|
+
def initialize(key, raw_value)
|
13
|
+
@key = key
|
14
|
+
@display_key = WORD_BOUNDARY_RES.inject(key) { |k, regex| k.gsub(regex, '\1 \2') }
|
15
|
+
@sym_key = display_key.downcase.gsub(' ', '_').to_sym
|
16
|
+
@raw_value = raw_value
|
17
|
+
end
|
18
|
+
|
19
|
+
def value
|
20
|
+
for_lat_long ||
|
21
|
+
for_date ||
|
22
|
+
for_fraction ||
|
23
|
+
raw_value
|
24
|
+
rescue StandardError => e
|
25
|
+
"Warning: Parsing '#{raw_value}' for attribute '#{key}' raised #{e.message}"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def for_lat_long
|
31
|
+
if sym_key == :gps_latitude || sym_key == :gps_longitude
|
32
|
+
value, direction = raw_value.split(" ")
|
33
|
+
if value =~ /\A\d+\.?\d*\z/
|
34
|
+
value.to_f * (['S', 'W'].include?(direction) ? -1 : 1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def for_date
|
40
|
+
if raw_value.is_a?(String) && display_key =~ /\bdate\b/i
|
41
|
+
try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S%z') } ||
|
42
|
+
try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S') } ||
|
43
|
+
try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S.%L%z') } ||
|
44
|
+
try_parse { Time.strptime(raw_value, '%Y:%m:%d %H:%M:%S.%L') } ||
|
45
|
+
try_parse { Time.parse(raw_value) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def try_parse
|
50
|
+
yield
|
51
|
+
rescue ArgumentError
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def for_fraction
|
56
|
+
if raw_value.is_a?(String)
|
57
|
+
scan = raw_value.scan(FRACTION_RE).first
|
58
|
+
v = Rational(*scan.map { |ea| ea.to_i }) unless scan.nil?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'exiftool/parser'
|
2
|
+
|
3
|
+
class Exiftool
|
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
|
data/test/Canon 20D.jpg
ADDED
Binary file
|
@@ -0,0 +1,225 @@
|
|
1
|
+
---
|
2
|
+
:source_file: /Users/mrm/Dropbox/code/exiftoolr/test/Canon 20D.jpg
|
3
|
+
:exif_tool_version: 9.31
|
4
|
+
:file_name: Canon 20D.jpg
|
5
|
+
:directory: /Users/mrm/Dropbox/code/exiftoolr/test
|
6
|
+
:file_size: 2.9 MB
|
7
|
+
:file_modify_date: 2012-02-23 05:22:17.000000000 +00:00
|
8
|
+
:file_access_date: 2013-07-14 20:25:41.000000000 +00:00
|
9
|
+
:file_inode_change_date: 2013-02-16 19:21:59.000000000 +00:00
|
10
|
+
:file_permissions: rw-r--r--
|
11
|
+
:file_type: JPEG
|
12
|
+
:mime_type: image/jpeg
|
13
|
+
:exif_byte_order: Little-endian (Intel, II)
|
14
|
+
:make: Canon
|
15
|
+
:model: Canon EOS 20D
|
16
|
+
:orientation: Horizontal (normal)
|
17
|
+
:x_resolution: 72
|
18
|
+
:y_resolution: 72
|
19
|
+
:resolution_unit: inches
|
20
|
+
:modify_date: 2004-09-19 12:25:20.000000000 +00:00
|
21
|
+
:y_cb_cr_positioning: Co-sited
|
22
|
+
:exposure_time: !ruby/object:Rational
|
23
|
+
denominator: 250
|
24
|
+
numerator: 1
|
25
|
+
:f_number: 9.0
|
26
|
+
:exposure_program: Program AE
|
27
|
+
:iso: 200
|
28
|
+
:exif_version: '0221'
|
29
|
+
:date_time_original: 2004-09-19 12:25:20.000000000 +00:00
|
30
|
+
:create_date: 2004-09-19 12:25:20.000000000 +00:00
|
31
|
+
:components_configuration: Y, Cb, Cr, -
|
32
|
+
:shutter_speed_value: !ruby/object:Rational
|
33
|
+
denominator: 250
|
34
|
+
numerator: 1
|
35
|
+
:aperture_value: 9.0
|
36
|
+
:flash: Off, Did not fire
|
37
|
+
:focal_length: 85.0 mm
|
38
|
+
:macro_mode: Normal
|
39
|
+
:self_timer: 'Off'
|
40
|
+
:quality: Fine
|
41
|
+
:canon_flash_mode: 'Off'
|
42
|
+
:continuous_drive: Single
|
43
|
+
:focus_mode: One-shot AF
|
44
|
+
:record_mode: JPEG
|
45
|
+
:canon_image_size: Large
|
46
|
+
:easy_mode: Manual
|
47
|
+
:digital_zoom: None
|
48
|
+
:contrast: '+1'
|
49
|
+
:saturation: '+1'
|
50
|
+
:sharpness: '+1'
|
51
|
+
:metering_mode: Evaluative
|
52
|
+
:focus_range: Not Known
|
53
|
+
:canon_exposure_mode: Program AE
|
54
|
+
:lens_type: Unknown (-1)
|
55
|
+
:max_focal_length: 85 mm
|
56
|
+
:min_focal_length: 17 mm
|
57
|
+
:focal_units: 1/mm
|
58
|
+
:max_aperture: 5.6
|
59
|
+
:min_aperture: 32
|
60
|
+
:flash_activity: 0
|
61
|
+
:flash_bits: (none)
|
62
|
+
:focus_continuous: Single
|
63
|
+
:zoom_source_width: 0
|
64
|
+
:zoom_target_width: 0
|
65
|
+
:photo_effect: 'Off'
|
66
|
+
:manual_flash_output: n/a
|
67
|
+
:focal_type: Zoom
|
68
|
+
:focal_plane_x_size: 23.04 mm
|
69
|
+
:focal_plane_y_size: 15.37 mm
|
70
|
+
:auto_iso: 100
|
71
|
+
:base_iso: 200
|
72
|
+
:measured_ev: 13.25
|
73
|
+
:target_aperture: 9
|
74
|
+
:target_exposure_time: !ruby/object:Rational
|
75
|
+
denominator: 251
|
76
|
+
numerator: 1
|
77
|
+
:exposure_compensation: 0
|
78
|
+
:white_balance: Auto
|
79
|
+
:slow_shutter: None
|
80
|
+
:sequence_number: 0
|
81
|
+
:optical_zoom_code: n/a
|
82
|
+
:flash_guide_number: 0
|
83
|
+
:flash_exposure_comp: 0
|
84
|
+
:auto_exposure_bracketing: 'Off'
|
85
|
+
:aeb_bracket_value: 0
|
86
|
+
:control_mode: Camera Local Control
|
87
|
+
:measured_ev2: 13.5
|
88
|
+
:bulb_duration: 0
|
89
|
+
:camera_type: EOS Mid-range
|
90
|
+
:auto_rotate: None
|
91
|
+
:nd_filter: n/a
|
92
|
+
:self_timer2: 0
|
93
|
+
:canon_image_type: Canon EOS 20D
|
94
|
+
:canon_firmware_version: Firmware 1.0.2
|
95
|
+
:owner_name: unknown
|
96
|
+
:serial_number: 0330113864
|
97
|
+
:set_function_when_shooting: Image replay
|
98
|
+
:long_exposure_noise_reduction: 'Off'
|
99
|
+
:flash_sync_speed_av: Auto
|
100
|
+
:shutter-ae_lock: AF/AE lock
|
101
|
+
:af_assist_beam: Emits
|
102
|
+
:exposure_level_increments: 1/3 Stop
|
103
|
+
:flash_firing: Fires
|
104
|
+
:iso_expansion: 'On'
|
105
|
+
:aeb_sequence_auto_cancel: 0,-,+/Enabled
|
106
|
+
:superimposed_display: 'On'
|
107
|
+
:menu_button_display_position: Previous (top if power off)
|
108
|
+
:mirror_lockup: Disable
|
109
|
+
:af_point_selection_method: Normal
|
110
|
+
:ettlii: Evaluative
|
111
|
+
:shutter_curtain_sync: 1st-curtain sync
|
112
|
+
:safety_shift_in_av_or_tv: Disable
|
113
|
+
:lens_af_stop_button: AF stop
|
114
|
+
:add_original_decision_data: 'Off'
|
115
|
+
:canon_model_id: EOS 20D
|
116
|
+
:num_af_points: 9
|
117
|
+
:valid_af_points: 9
|
118
|
+
:canon_image_width: 3504
|
119
|
+
:canon_image_height: 2336
|
120
|
+
:af_image_width: 3504
|
121
|
+
:af_image_height: 2336
|
122
|
+
:af_area_width: 78
|
123
|
+
:af_area_height: 78
|
124
|
+
:af_area_x_positions: 8 -555 571 -931 8 947 -555 571 8
|
125
|
+
:af_area_y_positions: 504 270 270 4 4 4 -262 -262 -496
|
126
|
+
:af_points_in_focus: 4
|
127
|
+
:thumbnail_image_valid_area: 0 159 7 112
|
128
|
+
:serial_number_format: Format 2
|
129
|
+
:original_decision_data_offset: 0
|
130
|
+
:file_number: 793-9390
|
131
|
+
:bracket_mode: 'Off'
|
132
|
+
:bracket_value: 0
|
133
|
+
:bracket_shot_number: 0
|
134
|
+
:long_exposure_noise_reduction2: 'Off'
|
135
|
+
:wb_bracket_mode: 'Off'
|
136
|
+
:wb_bracket_value_ab: 0
|
137
|
+
:wb_bracket_value_gm: 0
|
138
|
+
:filter_effect: None
|
139
|
+
:toning_effect: None
|
140
|
+
:tone_curve: Standard
|
141
|
+
:sharpness_frequency: n/a
|
142
|
+
:sensor_red_level: 0
|
143
|
+
:sensor_blue_level: 0
|
144
|
+
:white_balance_red: 0
|
145
|
+
:white_balance_blue: 0
|
146
|
+
:color_temperature: 4800
|
147
|
+
:picture_style: None
|
148
|
+
:digital_gain: 0
|
149
|
+
:wb_shift_ab: 0
|
150
|
+
:wb_shift_gm: 0
|
151
|
+
:measured_rggb: 674 1024 1024 670
|
152
|
+
:vrd_offset: 0
|
153
|
+
:sensor_width: 3596
|
154
|
+
:sensor_height: 2360
|
155
|
+
:sensor_left_border: 84
|
156
|
+
:sensor_top_border: 19
|
157
|
+
:sensor_right_border: 3587
|
158
|
+
:sensor_bottom_border: 2354
|
159
|
+
:black_mask_left_border: 0
|
160
|
+
:black_mask_top_border: 0
|
161
|
+
:black_mask_right_border: 0
|
162
|
+
:black_mask_bottom_border: 0
|
163
|
+
:wb_rggb_levels_as_shot: 1973 1015 1015 1663
|
164
|
+
:color_temp_as_shot: 4662
|
165
|
+
:wb_rggb_levels_auto: 1973 1023 1023 1663
|
166
|
+
:color_temp_auto: 4662
|
167
|
+
:wb_rggb_levels_daylight: 1995 1023 1023 1509
|
168
|
+
:color_temp_daylight: 5200
|
169
|
+
:wb_rggb_levels_shade: 2292 1023 1023 1267
|
170
|
+
:color_temp_shade: 7000
|
171
|
+
:wb_rggb_levels_cloudy: 2160 1023 1023 1373
|
172
|
+
:color_temp_cloudy: 6000
|
173
|
+
:wb_rggb_levels_tungsten: 1410 1023 1023 2408
|
174
|
+
:color_temp_tungsten: 3196
|
175
|
+
:wb_rggb_levels_fluorescent: 1797 1023 1023 2058
|
176
|
+
:color_temp_fluorescent: 3952
|
177
|
+
:wb_rggb_levels_flash: 2187 1023 1023 1333
|
178
|
+
:color_temp_flash: 6309
|
179
|
+
:wb_rggb_levels_custom1: 2095 1023 1023 1316
|
180
|
+
:color_temp_custom1: 6163
|
181
|
+
:wb_rggb_levels_custom2: 1912 1023 1023 1627
|
182
|
+
:color_temp_custom2: 4792
|
183
|
+
:color_tone: Normal
|
184
|
+
:user_comment: ''
|
185
|
+
:flashpix_version: '0100'
|
186
|
+
:color_space: sRGB
|
187
|
+
:exif_image_width: 3504
|
188
|
+
:exif_image_height: 2336
|
189
|
+
:interop_index: R98 - DCF basic file (sRGB)
|
190
|
+
:interop_version: '0100'
|
191
|
+
:focal_plane_x_resolution: 2886.363636
|
192
|
+
:focal_plane_y_resolution: 2885.805763
|
193
|
+
:focal_plane_resolution_unit: inches
|
194
|
+
:custom_rendered: Normal
|
195
|
+
:exposure_mode: Auto
|
196
|
+
:scene_capture_type: Standard
|
197
|
+
:compression: JPEG (old-style)
|
198
|
+
:thumbnail_offset: 9728
|
199
|
+
:thumbnail_length: 11259
|
200
|
+
:image_width: 3504
|
201
|
+
:image_height: 2336
|
202
|
+
:encoding_process: Baseline DCT, Huffman coding
|
203
|
+
:bits_per_sample: 8
|
204
|
+
:color_components: 3
|
205
|
+
:y_cb_cr_sub_sampling: YCbCr4:2:2 (2 1)
|
206
|
+
:aperture: 9.0
|
207
|
+
:drive_mode: Single-frame Shooting
|
208
|
+
:image_size: 3504x2336
|
209
|
+
:lens: 17.0 - 85.0 mm
|
210
|
+
:lens_id: Unknown 17-85mm
|
211
|
+
:scale_factor35efl: 1.0
|
212
|
+
:shooting_mode: Program AE
|
213
|
+
:shutter_speed: !ruby/object:Rational
|
214
|
+
denominator: 250
|
215
|
+
numerator: 1
|
216
|
+
:thumbnail_image: (Binary data 11259 bytes)
|
217
|
+
:wb_rggb_levels: 1973 1015 1015 1663
|
218
|
+
:blue_balance: 1.638424
|
219
|
+
:circle_of_confusion: 0.030 mm
|
220
|
+
:fov: 23.7 deg
|
221
|
+
:focal_length35efl: '85.0 mm (35 mm equivalent: 85.6 mm)'
|
222
|
+
:hyperfocal_distance: 26.91 m
|
223
|
+
:lens35efl: '17.0 - 85.0 mm (35 mm equivalent: 17.1 - 85.6 mm)'
|
224
|
+
:light_value: 13.3
|
225
|
+
:red_balance: 1.943842
|