exifr 1.0.6 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ EXIF Reader 1.1.1
2
+ * feature; "added gps convenience method to make accessing location data easier (degrees to float conversion)"
3
+ * bug fix; "[GH#22] Fix warnings about uninitialized @comment"; thanks to Ryan Greenberg"
4
+
1
5
  EXIF Reader 1.0.6
2
6
  * bug fix: "[GH#20] `readlong': undefined method `unpack' for nil:NilClass (NoMethodError)"
3
7
 
data/README.rdoc CHANGED
@@ -17,6 +17,9 @@ EXIF Reader is a module to read metadata from JPEG and TIFF images.
17
17
  EXIFR::TIFF.new('DSC_0218.TIF').exposure_time.to_s # => "1/100"
18
18
  EXIFR::TIFF.new('DSC_0218.TIF').f_number.to_f # => 5.0
19
19
 
20
+ EXIFR::JPEG.new('enkhuizen.jpg').gps.latitude # => 52.7197888888889
21
+ EXIFR::JPEG.new('enkhuizen.jpg').gps.longitude # => 5.28397777777778
22
+
20
23
  == XMP data access
21
24
  If you need to access XMP data you can use the xmp gem. More info and
22
25
  examples at https://github.com/amberbit/xmp
data/lib/exifr/jpeg.rb CHANGED
@@ -42,7 +42,7 @@ module EXIFR
42
42
 
43
43
  # Return thumbnail data when available.
44
44
  def thumbnail
45
- @exif && @exif.jpeg_thumbnails && @exif.jpeg_thumbnails.first
45
+ defined?(@exif) && @exif && @exif.jpeg_thumbnails && @exif.jpeg_thumbnails.first
46
46
  end
47
47
 
48
48
  # Get a hash presentation of the image.
@@ -56,22 +56,22 @@ module EXIFR
56
56
  # +method+ does exist for EXIF data +nil+ will be returned.
57
57
  def method_missing(method, *args)
58
58
  super unless args.empty?
59
- super unless TIFF::TAGS.include?(method.to_s)
60
- @exif.send method if @exif
59
+ super unless methods.include?(method.to_s)
60
+ @exif.send method if defined?(@exif) && @exif
61
61
  end
62
62
 
63
63
  def respond_to?(method) # :nodoc:
64
- super || TIFF::TAGS.include?(method.to_s)
64
+ super || methods.include?(method.to_s)
65
65
  end
66
66
 
67
67
  def methods # :nodoc:
68
- super + TIFF::TAGS
68
+ super + TIFF::TAGS << "gps"
69
69
  end
70
70
 
71
71
  class << self
72
72
  alias instance_methods_without_jpeg_extras instance_methods
73
73
  def instance_methods(include_super = true) # :nodoc:
74
- instance_methods_without_jpeg_extras(include_super) + TIFF::TAGS
74
+ instance_methods_without_jpeg_extras(include_super) + TIFF::TAGS << "gps"
75
75
  end
76
76
  end
77
77
 
@@ -108,7 +108,7 @@ module EXIFR
108
108
  end
109
109
  end
110
110
 
111
- @comment = @comment.first if @comment && @comment.size == 1
111
+ @comment = @comment.first if defined?(@comment) && @comment && @comment.size == 1
112
112
 
113
113
  if app1 = @app1s.find { |d| d[0..5] == "Exif\0\0" }
114
114
  @exif_data = app1[6..-1]
data/lib/exifr/tiff.rb CHANGED
@@ -239,10 +239,12 @@ module EXIFR
239
239
  IFD_TAGS = [:image, :exif, :gps] # :nodoc:
240
240
 
241
241
  time_proc = proc do |value|
242
- if value =~ /^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/
243
- Time.mktime($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i) rescue nil
244
- else
245
- value
242
+ value.map do |value|
243
+ if value =~ /^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/
244
+ Time.mktime($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i) rescue nil
245
+ else
246
+ value
247
+ end
246
248
  end
247
249
  end
248
250
 
@@ -298,12 +300,27 @@ module EXIFR
298
300
  const_set("#{type}Orientation", ORIENTATIONS[index] = Orientation.new(index, type))
299
301
  end
300
302
 
303
+ class Degrees < Array
304
+ def initialize(arr)
305
+ raise MalformedTIFF, "expected [degrees, minutes, seconds]" unless arr.length == 3
306
+ super
307
+ end
308
+
309
+ def to_f
310
+ reduce { |m,v| m * 60 + v}.to_f / 3600
311
+ end
312
+ end
313
+
301
314
  ADAPTERS = Hash.new { proc { |v| v } } # :nodoc:
302
315
  ADAPTERS.merge!({
303
316
  :date_time_original => time_proc,
304
317
  :date_time_digitized => time_proc,
305
318
  :date_time => time_proc,
306
- :orientation => proc { |v| ORIENTATIONS[v] }
319
+ :orientation => proc { |v| v.map{|v| ORIENTATIONS[v]} },
320
+ :gps_latitude => proc { |v| Degrees.new(v) },
321
+ :gps_longitude => proc { |v| Degrees.new(v) },
322
+ :gps_dest_latitude => proc { |v| Degrees.new(v) },
323
+ :gps_dest_longitude => proc { |v| Degrees.new(v) }
307
324
  })
308
325
 
309
326
  # Names for all recognized TIFF fields.
@@ -357,7 +374,7 @@ module EXIFR
357
374
 
358
375
  def respond_to?(method) # :nodoc:
359
376
  super ||
360
- (@ifds && @ifds.first && @ifds.first.respond_to?(method)) ||
377
+ (defined?(@ifds) && @ifds && @ifds.first && @ifds.first.respond_to?(method)) ||
361
378
  TAGS.include?(method.to_s)
362
379
  end
363
380
 
@@ -381,6 +398,17 @@ module EXIFR
381
398
  # Get a hash presentation of the (first) image.
382
399
  def to_hash; @ifds.first.to_hash; end
383
400
 
401
+ GPS = Struct.new(:latitude, :longitude, :altitude, :image_direction)
402
+
403
+ # Get GPS location, altitude and image direction return nil when not available.
404
+ def gps
405
+ return nil unless gps_latitude && gps_longitude
406
+ GPS.new(gps_latitude.to_f * (gps_latitude_ref == 'S' ? -1 : 1),
407
+ gps_longitude.to_f * (gps_longitude_ref == 'W' ? -1 : 1),
408
+ gps_altitude && (gps_altitude.to_f * (gps_altitude_ref == "\1" ? -1 : 1)),
409
+ gps_img_direction && gps_img_direction.to_f)
410
+ end
411
+
384
412
  def inspect # :nodoc:
385
413
  @ifds.inspect
386
414
  end
@@ -449,7 +477,7 @@ module EXIFR
449
477
  if IFD_TAGS.include? tag
450
478
  @fields[tag] = IFD.new(@data, field.offset, tag)
451
479
  else
452
- value = field.value.map { |v| ADAPTERS[tag][v] } if field.value
480
+ value = ADAPTERS[tag][field.value]
453
481
  @fields[tag] = value.kind_of?(Array) && value.size == 1 ? value.first : value
454
482
  end
455
483
  end
data/tests/test_helper.rb CHANGED
@@ -29,11 +29,17 @@ def f(fname)
29
29
  end
30
30
 
31
31
  def assert_literally_equal(expected, actual, *args)
32
- assert_equal expected.to_s, actual.to_s, *args
32
+ assert_equal expected.to_s_literally, actual.to_s_literally, *args
33
33
  end
34
34
 
35
35
  class Hash
36
- def to_s
36
+ def to_s_literally
37
37
  keys.map{|k| k.to_s}.sort.map{|k| "#{k.inspect} => #{self[k].inspect}" }.join(', ')
38
38
  end
39
39
  end
40
+
41
+ class Object
42
+ def to_s_literally
43
+ to_s
44
+ end
45
+ end
data/tests/tiff_test.rb CHANGED
@@ -30,32 +30,32 @@ class TIFFTest < Test::Unit::TestCase
30
30
  end
31
31
 
32
32
  def test_multiple_images
33
- assert_equal 2, @t.size
33
+ assert_equal(2, @t.size)
34
34
  end
35
35
 
36
36
  def test_size
37
- assert_equal 269, @t.image_width
38
- assert_equal 269, @t.image_length
39
- assert_equal 269, @t.width
40
- assert_equal 269, @t.height
41
- assert_equal 120, @t[1].image_width
42
- assert_equal 160, @t[1].image_length
43
- assert_equal 120, @t[1].width
44
- assert_equal 160, @t[1].height
37
+ assert_equal(269, @t.image_width)
38
+ assert_equal(269, @t.image_length)
39
+ assert_equal(269, @t.width)
40
+ assert_equal(269, @t.height)
41
+ assert_equal(120, @t[1].image_width)
42
+ assert_equal(160, @t[1].image_length)
43
+ assert_equal(120, @t[1].width)
44
+ assert_equal(160, @t[1].height)
45
45
 
46
46
  @t = TIFF.new(f('plain.tif'))
47
- assert_equal 23, @t.image_width
48
- assert_equal 24, @t.image_length
49
- assert_equal 23, @t.width
50
- assert_equal 24, @t.height
47
+ assert_equal(23, @t.image_width)
48
+ assert_equal(24, @t.image_length)
49
+ assert_equal(23, @t.width)
50
+ assert_equal(24, @t.height)
51
51
  end
52
52
 
53
53
  def test_enumerable
54
- assert_equal @t[1], @t.find { |i| i.f_number.nil? }
54
+ assert_equal(@t[1], @t.find { |i| i.f_number.nil? })
55
55
  end
56
56
 
57
57
  def test_misc_fields
58
- assert_equal 'Canon PowerShot G3', TIFF.new(f('canon-g3.exif')).model
58
+ assert_equal('Canon PowerShot G3', TIFF.new(f('canon-g3.exif')).model)
59
59
  end
60
60
 
61
61
  def test_dates
@@ -90,12 +90,14 @@ class TIFFTest < Test::Unit::TestCase
90
90
 
91
91
  def test_gps
92
92
  t = TIFF.new(f('gps.exif'))
93
- assert_equal "\2\2\0\0", t.gps_version_id
94
- assert_equal 'N', t.gps_latitude_ref
95
- assert_equal 'W', t.gps_longitude_ref
96
- assert_equal [5355537.quo(100000), 0.quo(1), 0.quo(1)], t.gps_latitude
97
- assert_equal [678886.quo(100000), 0.quo(1), 0.quo(1)], t.gps_longitude
98
- assert_equal 'WGS84', t.gps_map_datum
93
+ assert_equal("\2\2\0\0", t.gps_version_id)
94
+ assert_equal('N', t.gps_latitude_ref)
95
+ assert_equal('W', t.gps_longitude_ref)
96
+ assert_equal([5355537.quo(100000), 0.quo(1), 0.quo(1)], t.gps_latitude)
97
+ assert_equal([678886.quo(100000), 0.quo(1), 0.quo(1)], t.gps_longitude)
98
+ assert_equal('WGS84', t.gps_map_datum)
99
+ assert_equal(54, t.gps.latitude.round)
100
+ assert_equal(-7, t.gps.longitude.round)
99
101
 
100
102
  (all_test_exifs - %w(gps user-comment out-of-range negative-exposure-bias-value).map{|v| f("#{v}.exif")}).each do |fname|
101
103
  assert_nil TIFF.new(fname).gps_version_id
@@ -170,7 +172,7 @@ class TIFFTest < Test::Unit::TestCase
170
172
  end
171
173
 
172
174
  def test_user_comment
173
- assert_equal "Manassas Battlefield", TIFF.new(f('user-comment.exif')).user_comment
175
+ assert_equal("Manassas Battlefield", TIFF.new(f('user-comment.exif')).user_comment)
174
176
  end
175
177
 
176
178
  def test_handle_out_of_range_offset
@@ -180,6 +182,6 @@ class TIFFTest < Test::Unit::TestCase
180
182
  end
181
183
 
182
184
  def test_negative_exposure_bias_value
183
- assert_equal -1.quo(3), TIFF.new(f('negative-exposure-bias-value.exif')).exposure_bias_value
185
+ assert_equal(-1.quo(3), TIFF.new(f('negative-exposure-bias-value.exif')).exposure_bias_value)
184
186
  end
185
187
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exifr
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 0
9
- - 6
10
- version: 1.0.6
8
+ - 1
9
+ - 1
10
+ version: 1.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - R.W. van 't Veer
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-23 00:00:00 +02:00
18
+ date: 2011-09-12 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21