exifr 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/bin/exifr +8 -0
- data/lib/jpeg.rb +4 -1
- data/lib/tiff.rb +38 -16
- data/tests/data/negative-exposure-bias-value.exif +0 -0
- data/tests/tiff_test.rb +5 -1
- metadata +18 -10
data/CHANGELOG
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
EXIF Reader 1.0.1
|
2
|
+
* bug fix; "[GH#7] Unable to properly display exposure_bias_value"; thanks to John Krueger
|
3
|
+
|
1
4
|
EXIF Reader 1.0.0
|
2
5
|
* bug fix; "ArgumentError: invalid byte sequence in UTF-8" when reading messy field using Ruby 1.9+
|
3
6
|
* enhancement; "[GH#4] more informative inspect for EXIFR::TIFF::Orientation instance"
|
data/bin/exifr
CHANGED
@@ -38,6 +38,14 @@ end
|
|
38
38
|
|
39
39
|
if ARGV.size == 0
|
40
40
|
STDERR.puts "Usage: #{$0} FILE .."
|
41
|
+
elsif ARGV[0] == "--dump-exif"
|
42
|
+
ARGV[1..-1].each do |fname|
|
43
|
+
STDOUT.write JPEG.new(fname).exif_data
|
44
|
+
end
|
45
|
+
elsif ARGV[0] == "--dump-thumbnail"
|
46
|
+
ARGV[1..-1].each do |fname|
|
47
|
+
STDOUT.write JPEG.new(fname).thumbnail
|
48
|
+
end
|
41
49
|
else
|
42
50
|
ARGV.each do |fname|
|
43
51
|
case fname
|
data/lib/jpeg.rb
CHANGED
@@ -20,6 +20,8 @@ module EXIFR
|
|
20
20
|
attr_reader :comment
|
21
21
|
# EXIF data if available
|
22
22
|
attr_reader :exif
|
23
|
+
# raw EXIF data
|
24
|
+
attr_reader :exif_data # :nodoc:
|
23
25
|
|
24
26
|
# +file+ is a filename or an IO object. Hint: use StringIO when working with slurped data like blobs.
|
25
27
|
def initialize(file)
|
@@ -102,7 +104,8 @@ module EXIFR
|
|
102
104
|
@comment = @comment.first if @comment && @comment.size == 1
|
103
105
|
|
104
106
|
if app1 = app1s.find { |d| d[0..5] == "Exif\0\0" }
|
105
|
-
@
|
107
|
+
@exif_data = app1[6..-1]
|
108
|
+
@exif = TIFF.new(StringIO.new(@exif_data))
|
106
109
|
end
|
107
110
|
end
|
108
111
|
end
|
data/lib/tiff.rb
CHANGED
@@ -459,17 +459,20 @@ module EXIFR
|
|
459
459
|
@type = data.readshort(pos + 2)
|
460
460
|
|
461
461
|
case @type
|
462
|
-
when 1
|
463
|
-
# TODO handle signed bytes
|
462
|
+
when 1 # byte
|
464
463
|
len, pack = count, proc { |d| d }
|
464
|
+
when 6 # signed byte
|
465
|
+
len, pack = count, proc { |d| sign_byte(d) }
|
465
466
|
when 2 # ascii
|
466
467
|
len, pack = count, proc { |d| d.unpack("A*") }
|
467
|
-
when 3
|
468
|
-
# TODO handle signed
|
468
|
+
when 3 # short
|
469
469
|
len, pack = count * 2, proc { |d| d.unpack(data.short + '*') }
|
470
|
-
when
|
471
|
-
|
470
|
+
when 8 # signed short
|
471
|
+
len, pack = count * 2, proc { |d| d.unpack(data.short + '*').map{|n| sign_short(n)} }
|
472
|
+
when 4 # long
|
472
473
|
len, pack = count * 4, proc { |d| d.unpack(data.long + '*') }
|
474
|
+
when 9 # signed long
|
475
|
+
len, pack = count * 4, proc { |d| d.unpack(data.long + '*').map{|n| sign_long(n)} }
|
473
476
|
when 7 # undefined
|
474
477
|
# UserComment
|
475
478
|
if @tag == 0x9286
|
@@ -478,18 +481,16 @@ module EXIFR
|
|
478
481
|
start = len > 4 ? @offset + 8 : (pos + 8) # UserComment first 8-bytes is char code
|
479
482
|
@value = [pack[data[start..(start + len - 1)]]].flatten
|
480
483
|
end
|
481
|
-
when 5
|
484
|
+
when 5 # unsigned rational
|
482
485
|
len, pack = count * 8, proc do |d|
|
483
|
-
|
484
|
-
|
485
|
-
i % 2 == 0 ? r << [v] : r.last << v
|
486
|
+
d.unpack(data.long + '*').each_slice(2).map do |f|
|
487
|
+
rational(*f)
|
486
488
|
end
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
end
|
489
|
+
end
|
490
|
+
when 10 # signed rational
|
491
|
+
len, pack = count * 8, proc do |d|
|
492
|
+
d.unpack(data.long + '*').map{|n| sign_long(n)}.each_slice(2).map do |f|
|
493
|
+
rational(*f)
|
493
494
|
end
|
494
495
|
end
|
495
496
|
end
|
@@ -500,6 +501,27 @@ module EXIFR
|
|
500
501
|
@value = d && [pack[d]].flatten
|
501
502
|
end
|
502
503
|
end
|
504
|
+
|
505
|
+
private
|
506
|
+
def sign_byte(n)
|
507
|
+
(n & 0x80) != 0 ? n - 0x100 : n
|
508
|
+
end
|
509
|
+
|
510
|
+
def sign_short(n)
|
511
|
+
(n & 0x8000) != 0 ? n - 0x10000 : n
|
512
|
+
end
|
513
|
+
|
514
|
+
def sign_long(n)
|
515
|
+
(n & 0x80000000) != 0 ? n - 0x100000000 : n
|
516
|
+
end
|
517
|
+
|
518
|
+
def rational(n, d)
|
519
|
+
if d == 0 # allow NaN and Infinity
|
520
|
+
n.to_f.quo(d)
|
521
|
+
else
|
522
|
+
Rational.respond_to?(:reduce) ? Rational.reduce(n, d) : n.quo(d)
|
523
|
+
end
|
524
|
+
end
|
503
525
|
end
|
504
526
|
|
505
527
|
class Data #:nodoc:
|
Binary file
|
data/tests/tiff_test.rb
CHANGED
@@ -91,7 +91,7 @@ class TIFFTest < Test::Unit::TestCase
|
|
91
91
|
assert_equal [678886.quo(100000), 0.quo(1), 0.quo(1)], t.gps_longitude
|
92
92
|
assert_equal 'WGS84', t.gps_map_datum
|
93
93
|
|
94
|
-
(all_test_exifs - %w(gps user-comment out-of-range).map{|v| f("#{v}.exif")}).each do |fname|
|
94
|
+
(all_test_exifs - %w(gps user-comment out-of-range negative-exposure-bias-value).map{|v| f("#{v}.exif")}).each do |fname|
|
95
95
|
assert_nil TIFF.new(fname).gps_version_id
|
96
96
|
end
|
97
97
|
end
|
@@ -172,4 +172,8 @@ class TIFFTest < Test::Unit::TestCase
|
|
172
172
|
assert 'NIKON', TIFF.new(f('out-of-range.exif')).make
|
173
173
|
end
|
174
174
|
end
|
175
|
+
|
176
|
+
def test_negative_exposure_bias_value
|
177
|
+
assert_equal -1.quo(3), TIFF.new(f('negative-exposure-bias-value.exif')).exposure_bias_value
|
178
|
+
end
|
175
179
|
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exifr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 1.0.1
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- R.W. van 't Veer
|
@@ -9,7 +14,7 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-26 00:00:00 +02:00
|
13
18
|
default_executable:
|
14
19
|
dependencies: []
|
15
20
|
|
@@ -29,21 +34,22 @@ files:
|
|
29
34
|
- lib/jpeg.rb
|
30
35
|
- lib/tiff.rb
|
31
36
|
- tests/data/1x1.jpg
|
32
|
-
- tests/data/Canon_PowerShot_A85.exif
|
33
|
-
- tests/data/Casio-EX-S20.exif
|
34
|
-
- tests/data/FUJIFILM-FinePix_S3000.exif
|
35
|
-
- tests/data/Panasonic-DMC-LC33.exif
|
36
|
-
- tests/data/Trust-DC3500_MINI.exif
|
37
37
|
- tests/data/apple-aperture-1.5.exif
|
38
38
|
- tests/data/canon-g3.exif
|
39
|
+
- tests/data/Canon_PowerShot_A85.exif
|
40
|
+
- tests/data/Casio-EX-S20.exif
|
39
41
|
- tests/data/endless-loop.exif
|
40
42
|
- tests/data/exif.jpg
|
43
|
+
- tests/data/FUJIFILM-FinePix_S3000.exif
|
41
44
|
- tests/data/gps.exif
|
42
45
|
- tests/data/image.jpg
|
43
46
|
- tests/data/multiple-app1.jpg
|
47
|
+
- tests/data/negative-exposure-bias-value.exif
|
44
48
|
- tests/data/nikon_d1x.tif
|
45
49
|
- tests/data/out-of-range.exif
|
50
|
+
- tests/data/Panasonic-DMC-LC33.exif
|
46
51
|
- tests/data/plain.tif
|
52
|
+
- tests/data/Trust-DC3500_MINI.exif
|
47
53
|
- tests/data/user-comment.exif
|
48
54
|
- tests/data/weird_date.exif
|
49
55
|
- tests/jpeg_test.rb
|
@@ -67,18 +73,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
73
|
requirements:
|
68
74
|
- - ">="
|
69
75
|
- !ruby/object:Gem::Version
|
76
|
+
segments:
|
77
|
+
- 0
|
70
78
|
version: "0"
|
71
|
-
version:
|
72
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
80
|
requirements:
|
74
81
|
- - ">="
|
75
82
|
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 0
|
76
85
|
version: "0"
|
77
|
-
version:
|
78
86
|
requirements: []
|
79
87
|
|
80
88
|
rubyforge_project:
|
81
|
-
rubygems_version: 1.3.
|
89
|
+
rubygems_version: 1.3.6
|
82
90
|
signing_key:
|
83
91
|
specification_version: 3
|
84
92
|
summary: EXIF Reader is a module to read EXIF from JPEG images.
|