exiftoolr 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/README.md +29 -17
- data/Rakefile +14 -2
- data/exiftoolr.gemspec +24 -20
- data/lib/exiftoolr.rb +6 -6
- data/lib/exiftoolr/parser.rb +63 -0
- data/lib/exiftoolr/result.rb +2 -47
- data/lib/exiftoolr/version.rb +1 -1
- data/test/Canon 20D.jpg.yaml +201 -199
- data/test/Droid X.jpg.yaml +74 -72
- 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.yaml +281 -264
- data/test/iPhone 4S.jpg.yaml +68 -66
- data/test/parser_test.rb +58 -0
- data/test/test_helper.rb +14 -0
- metadata +84 -4
- data/test/test_exiftoolr.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecd656c3093b0eb6f3f94cc402bf5ee14a9b13ba
|
4
|
+
data.tar.gz: a8129d314f15fe908720f07393581b251ae95bfa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8bcb6cc7a2dce7917f64c00e616f2493662562ff11ecfbc1bc49665311fd372c6ce057db7e343d45e7cd09e815cdf1ea3dd1f0bed395e086e57c17bbb62c685
|
7
|
+
data.tar.gz: 051740e233bd226e7293e4dd332bd22f1de4cc785f670bd3f43b324481d958c75f7ae515199bb8e654f58bd7c002ac3e8a2487b46dbc8f32068909b5d892d9e4
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,9 @@ 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
|
-
|
11
|
+
Rubies 1.9 and later are supported.
|
12
|
+
|
13
|
+
## What constitutes "correct values"?
|
12
14
|
|
13
15
|
* GPS latitude and longitude are rendered as signed floats,
|
14
16
|
where north and east are positive, and west and south are negative.
|
@@ -16,22 +18,10 @@ and renders it into a ruby hash, with correctly typed values and symbolized keys
|
|
16
18
|
which lets the caller show them as fractions (1/250) or as comparable numeric instances.
|
17
19
|
* String values like "interop" and "serial number" are kept as strings
|
18
20
|
(which preserves zero prefixes)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
```
|
25
|
-
gem install exiftoolr
|
26
|
-
```
|
27
|
-
|
28
|
-
or add to your Gemfile:
|
29
|
-
|
30
|
-
```
|
31
|
-
gem 'exiftoolr'
|
32
|
-
```
|
33
|
-
|
34
|
-
and run ```bundle```.
|
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.
|
35
25
|
|
36
26
|
## Usage
|
37
27
|
|
@@ -46,6 +36,11 @@ e.to_display_hash
|
|
46
36
|
|
47
37
|
### Multiple file support
|
48
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
|
+
|
49
44
|
Supply an array to the Exiftoolr initializer, then use ```.result_for```:
|
50
45
|
|
51
46
|
```ruby
|
@@ -72,8 +67,25 @@ Exiftoolr.new("Gemfile").errors?
|
|
72
67
|
#=> true
|
73
68
|
```
|
74
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'
|
78
|
+
|
79
|
+
and then run ```bundle```.
|
80
|
+
|
75
81
|
## Change history
|
76
82
|
|
83
|
+
### 0.1.0
|
84
|
+
|
85
|
+
* Better timestamp parsing—now both sub-second and timezone offsets are handled correctly
|
86
|
+
* Switched to minitest-spec
|
87
|
+
* Ruby 1.8.7 is no longer supported, hence the minor version uptick.
|
88
|
+
|
77
89
|
### 0.0.9
|
78
90
|
|
79
91
|
* Explicitly added MIT licensing to the gemspec.
|
data/Rakefile
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require "rake/testtask"
|
3
2
|
|
4
|
-
|
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
|
+
|
5
17
|
task :default => :test
|
data/exiftoolr.gemspec
CHANGED
@@ -1,26 +1,30 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'exiftoolr/version'
|
4
5
|
|
5
|
-
Gem::Specification.new do |
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'exiftoolr'
|
8
|
+
spec.version = Exiftoolr::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'
|
14
15
|
|
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"]
|
16
20
|
|
17
|
-
|
18
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
-
s.require_paths = ["lib"]
|
21
|
+
spec.requirements << 'ExifTool (see http://www.sno.phy.queensu.ca/~phil/exiftool/)'
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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']
|
26
30
|
end
|
data/lib/exiftoolr.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
require "exiftoolr/version"
|
2
|
-
require "exiftoolr/result"
|
3
|
-
|
4
1
|
require 'json'
|
5
2
|
require 'shellwords'
|
3
|
+
require 'exiftoolr/result'
|
6
4
|
|
7
5
|
class Exiftoolr
|
8
6
|
class NoSuchFile < StandardError ; end
|
@@ -23,14 +21,16 @@ class Exiftoolr
|
|
23
21
|
File.expand_path(filename)
|
24
22
|
end
|
25
23
|
|
26
|
-
def initialize(filenames, exiftool_opts =
|
24
|
+
def initialize(filenames, exiftool_opts = '')
|
27
25
|
@file2result = {}
|
28
26
|
filenames = [filenames] if filenames.is_a?(String)
|
29
27
|
unless filenames.empty?
|
30
28
|
escaped_filenames = filenames.collect do |f|
|
31
29
|
Shellwords.escape(self.class.expand_path(f.to_s))
|
32
30
|
end.join(" ")
|
33
|
-
|
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
34
|
json = `#{cmd}`
|
35
35
|
raise ExiftoolNotInstalled if json == ""
|
36
36
|
JSON.parse(json).each do |raw|
|
@@ -67,7 +67,7 @@ class Exiftoolr
|
|
67
67
|
private
|
68
68
|
|
69
69
|
def first
|
70
|
-
raise InvalidArgument,
|
70
|
+
raise InvalidArgument, 'use #result_for when multiple filenames are used' if @file2result.size > 1
|
71
71
|
@file2result.values.first
|
72
72
|
end
|
73
73
|
end
|
@@ -0,0 +1,63 @@
|
|
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
|
data/lib/exiftoolr/result.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'rational'
|
1
|
+
require 'exiftoolr/parser'
|
3
2
|
|
4
3
|
class Exiftoolr
|
5
4
|
class Result
|
@@ -27,51 +26,7 @@ class Exiftoolr
|
|
27
26
|
end
|
28
27
|
|
29
28
|
def errors?
|
30
|
-
self[:error] ==
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class Parser
|
35
|
-
WORD_BOUNDARY_RES = [/([A-Z\d]+)([A-Z][a-z])/, /([a-z\d])([A-Z])/]
|
36
|
-
FRACTION_RE = /^(\d+)\/(\d+)$/
|
37
|
-
|
38
|
-
attr_reader :display_key, :sym_key, :raw_value
|
39
|
-
|
40
|
-
def initialize(key, raw_value)
|
41
|
-
@display_key = WORD_BOUNDARY_RES.inject(key) { |k, regex| k.gsub(regex, '\1 \2') }
|
42
|
-
@sym_key = display_key.downcase.gsub(' ', '_').to_sym
|
43
|
-
@raw_value = raw_value
|
44
|
-
end
|
45
|
-
|
46
|
-
def value
|
47
|
-
for_lat_long ||
|
48
|
-
for_date ||
|
49
|
-
for_fraction ||
|
50
|
-
raw_value
|
51
|
-
rescue StandardError => e
|
52
|
-
v = "Warning: Parsing '#{raw_value}' for attribute '#{k}' raised #{e.message}"
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def for_lat_long
|
58
|
-
if sym_key == :gps_latitude || sym_key == :gps_longitude
|
59
|
-
value, direction = raw_value.split(" ")
|
60
|
-
value.to_f * (['S', 'W'].include?(direction) ? -1 : 1)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def for_date
|
65
|
-
if raw_value.is_a?(String) && display_key =~ /\bdate\b/i
|
66
|
-
Time.parse(raw_value)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def for_fraction
|
71
|
-
if raw_value.is_a?(String)
|
72
|
-
scan = raw_value.scan(FRACTION_RE).first
|
73
|
-
v = Rational(*scan.collect { |ea| ea.to_i }) unless scan.nil?
|
74
|
-
end
|
29
|
+
self[:error] == 'Unknown file type' || self[:warning] == 'Unsupported file type'
|
75
30
|
end
|
76
31
|
end
|
77
32
|
end
|
data/lib/exiftoolr/version.rb
CHANGED
data/test/Canon 20D.jpg.yaml
CHANGED
@@ -1,223 +1,225 @@
|
|
1
|
-
---
|
2
|
-
:
|
3
|
-
:
|
4
|
-
:flash_activity: 0
|
5
|
-
:measured_rggb: 674 1024 1024 670
|
6
|
-
:photo_effect: "Off"
|
7
|
-
:digital_zoom: None
|
8
|
-
:af_points_in_focus: 4
|
9
|
-
:color_temp_shade: 7000
|
10
|
-
:y_cb_cr_sub_sampling: YCbCr4:2:2 (2 1)
|
11
|
-
:metering_mode: Evaluative
|
12
|
-
:image_size: 3504x2336
|
13
|
-
:canon_model_id: EOS 20D
|
14
|
-
:bracket_mode: "Off"
|
15
|
-
:camera_type: EOS Mid-range
|
16
|
-
:exposure_mode: Auto
|
17
|
-
:tone_curve: Standard
|
18
|
-
:af_area_x_positions: 8 -555 571 -931 8 947 -555 571 8
|
19
|
-
:color_tone: Normal
|
20
|
-
:af_image_width: 3504
|
21
|
-
:max_aperture: 5.6
|
22
|
-
:aeb_bracket_value: 0
|
23
|
-
:shutter_curtain_sync: 1st-curtain sync
|
24
|
-
:aeb_sequence_auto_cancel: 0,-,+/Enabled
|
25
|
-
:scale_factor35efl: 1.6
|
26
|
-
:lens_af_stop_button: AF stop
|
27
|
-
:add_original_decision_data: "Off"
|
28
|
-
:thumbnail_image: (Binary data 11259 bytes)
|
29
|
-
:flash_sync_speed_av: Auto
|
30
|
-
:black_mask_right_border: 0
|
31
|
-
:base_iso: 200
|
32
|
-
:image_width: 3504
|
33
|
-
:focal_plane_x_resolution: 2886.363636
|
34
|
-
:exposure_program: Program AE
|
35
|
-
:safety_shift_in_av_or_tv: Disable
|
36
|
-
:measured_ev: 13.25
|
37
|
-
:continuous_drive: Single
|
38
|
-
:red_balance: 1.943842
|
1
|
+
---
|
2
|
+
:source_file: /Users/mrm/Dropbox/code/exiftoolr/test/Canon 20D.jpg
|
3
|
+
:exif_tool_version: 9.31
|
39
4
|
:file_name: Canon 20D.jpg
|
40
|
-
:
|
41
|
-
:lens: 17.0 - 85.0 mm
|
42
|
-
:digital_gain: 0
|
43
|
-
:macro_mode: Normal
|
44
|
-
:wb_rggb_levels_flash: 2187 1023 1023 1333
|
45
|
-
:menu_button_display_position: Previous (top if power off)
|
46
|
-
:sensor_height: 2360
|
5
|
+
:directory: /Users/mrm/Dropbox/code/exiftoolr/test
|
47
6
|
:file_size: 2.9 MB
|
48
|
-
:
|
49
|
-
:
|
50
|
-
:
|
51
|
-
:
|
52
|
-
:
|
53
|
-
:
|
54
|
-
:
|
55
|
-
:toning_effect: None
|
56
|
-
:af_area_y_positions: 504 270 270 4 4 4 -262 -262 -496
|
57
|
-
:focal_plane_y_resolution: 2885.805763
|
58
|
-
:target_aperture: 9
|
59
|
-
:focus_mode: One-shot AF
|
60
|
-
:mirror_lockup: Disable
|
61
|
-
:color_temp_flash: 6309
|
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)
|
62
14
|
:make: Canon
|
63
|
-
:
|
64
|
-
:
|
65
|
-
:
|
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
|
66
23
|
denominator: 250
|
67
24
|
numerator: 1
|
68
|
-
:
|
69
|
-
:
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:
|
75
|
-
:
|
76
|
-
:lens_id: Unknown 17-85mm
|
77
|
-
:shutter_speed: !ruby/object:Rational
|
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
|
78
33
|
denominator: 250
|
79
34
|
numerator: 1
|
80
|
-
:light_value: 13.3
|
81
|
-
:superimposed_display: "On"
|
82
|
-
:exposure_compensation: 0
|
83
|
-
:orientation: Horizontal (normal)
|
84
|
-
:components_configuration: Y, Cb, Cr, -
|
85
|
-
:"shutter-ae_lock": AF/AE lock
|
86
|
-
:focal_length: 85.0 mm
|
87
|
-
:focal_length35efl: "85.0 mm (35 mm equivalent: 132.8 mm)"
|
88
|
-
:bracket_shot_number: 0
|
89
|
-
:model: Canon EOS 20D
|
90
35
|
:aperture_value: 9.0
|
91
|
-
:
|
92
|
-
:
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:
|
96
|
-
:
|
97
|
-
:
|
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
|
98
53
|
:canon_exposure_mode: Program AE
|
99
|
-
:interop_version: "0100"
|
100
|
-
:canon_image_width: 3504
|
101
|
-
:color_temp_fluorescent: 3952
|
102
|
-
:canon_firmware_version: Firmware 1.0.2
|
103
|
-
:sharpness: "+1"
|
104
|
-
:color_temp_auto: 4662
|
105
|
-
:af_assist_beam: Emits
|
106
|
-
:iso: 200
|
107
|
-
:black_mask_left_border: 0
|
108
|
-
:color_temp_custom1: 6163
|
109
|
-
:focal_plane_resolution_unit: inches
|
110
|
-
:wb_rggb_levels_custom1: 2095 1023 1023 1316
|
111
|
-
:flash_bits: (none)
|
112
|
-
:sensor_right_border: 3587
|
113
|
-
:bracket_value: 0
|
114
|
-
:canon_image_type: Canon EOS 20D
|
115
|
-
:exif_version: "0221"
|
116
|
-
:exif_image_width: 3504
|
117
|
-
:encoding_process: Baseline DCT, Huffman coding
|
118
|
-
:contrast: "+1"
|
119
|
-
:file_modify_date: 2012-02-19 21:49:48 -08:00
|
120
|
-
:white_balance_red: 0
|
121
|
-
:auto_rotate: None
|
122
|
-
:scene_capture_type: Standard
|
123
|
-
:compression: JPEG (old-style)
|
124
|
-
:sensor_red_level: 0
|
125
|
-
:control_mode: Camera Local Control
|
126
|
-
:sensor_width: 3596
|
127
|
-
:shooting_mode: Program AE
|
128
54
|
:lens_type: Unknown (-1)
|
129
|
-
:
|
130
|
-
:
|
131
|
-
:
|
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)
|
132
62
|
:focus_continuous: Single
|
133
|
-
:
|
134
|
-
:
|
135
|
-
:
|
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
|
136
75
|
denominator: 251
|
137
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
|
138
117
|
:valid_af_points: 9
|
139
|
-
:
|
140
|
-
:wb_rggb_levels_daylight: 1995 1023 1023 1509
|
141
|
-
:interop_index: R98 - DCF basic file (sRGB)
|
118
|
+
:canon_image_width: 3504
|
142
119
|
:canon_image_height: 2336
|
143
|
-
:
|
144
|
-
:
|
145
|
-
:
|
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
|
146
128
|
:serial_number_format: Format 2
|
147
|
-
:
|
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
|
148
156
|
:sensor_top_border: 19
|
149
|
-
:
|
150
|
-
:
|
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
|
151
164
|
:color_temp_as_shot: 4662
|
152
|
-
:
|
153
|
-
:
|
154
|
-
:
|
155
|
-
:
|
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
|
156
173
|
:wb_rggb_levels_tungsten: 1410 1023 1023 2408
|
157
|
-
:
|
158
|
-
:
|
159
|
-
:
|
160
|
-
:
|
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
|
161
194
|
:custom_rendered: Normal
|
162
|
-
:
|
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
|
163
204
|
:color_components: 3
|
164
|
-
:
|
165
|
-
:exif_image_height: 2336
|
205
|
+
:y_cb_cr_sub_sampling: YCbCr4:2:2 (2 1)
|
166
206
|
:aperture: 9.0
|
167
|
-
:
|
168
|
-
:
|
169
|
-
:
|
170
|
-
:
|
171
|
-
:
|
172
|
-
:
|
173
|
-
:
|
174
|
-
:self_timer2: 0
|
175
|
-
:lens35efl: "17.0 - 85.0 mm (35 mm equivalent: 26.6 - 132.8 mm)"
|
176
|
-
:mime_type: image/jpeg
|
177
|
-
:wb_rggb_levels_shade: 2292 1023 1023 1267
|
178
|
-
:canon_image_size: Large
|
179
|
-
:hyperfocal_distance: 41.74 m
|
180
|
-
:wb_rggb_levels_auto: 1973 1023 1023 1663
|
181
|
-
:zoom_source_width: 0
|
182
|
-
:auto_iso: 100
|
183
|
-
:vrd_offset: 0
|
184
|
-
:wb_shift_gm: 0
|
185
|
-
:wb_rggb_levels_fluorescent: 1797 1023 1023 2058
|
186
|
-
:color_temperature: 4800
|
187
|
-
:wb_rggb_levels: 1973 1015 1015 1663
|
188
|
-
:wb_shift_ab: 0
|
189
|
-
:user_comment: ""
|
190
|
-
:zoom_target_width: 0
|
191
|
-
:quality: Fine
|
192
|
-
:color_temp_cloudy: 6000
|
193
|
-
:af_image_height: 2336
|
194
|
-
:manual_flash_output: n/a
|
195
|
-
:flash_exposure_comp: 0
|
196
|
-
:wb_rggb_levels_cloudy: 2160 1023 1023 1373
|
197
|
-
:source_file: test/Canon 20D.jpg
|
198
|
-
:color_temp_daylight: 5200
|
199
|
-
:sharpness_frequency: n/a
|
200
|
-
:slow_shutter: None
|
201
|
-
:modify_date: 2004-09-19 12:25:20 -07:00
|
202
|
-
:bulb_duration: 0
|
203
|
-
:bits_per_sample: 8
|
204
|
-
:focus_range: Not Known
|
205
|
-
:saturation: "+1"
|
206
|
-
:focal_type: Zoom
|
207
|
-
:wb_rggb_levels_as_shot: 1973 1015 1015 1663
|
208
|
-
:min_aperture: 32
|
209
|
-
:exif_tool_version: 8.59
|
210
|
-
:y_resolution: 72
|
211
|
-
:date_time_original: 2004-09-19 12:25:20 -07:00
|
212
|
-
:shutter_speed_value: !ruby/object:Rational
|
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
|
213
214
|
denominator: 250
|
214
215
|
numerator: 1
|
215
|
-
:
|
216
|
-
:
|
217
|
-
:
|
218
|
-
:
|
219
|
-
:
|
220
|
-
:
|
221
|
-
:
|
222
|
-
:
|
223
|
-
:
|
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
|