exifr 1.0.6 → 1.1.1

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.
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