exiftoolr 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|