exifr 1.3.9 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91531cf59588956e8b9675148197cdca2b8bcbe35edb42476bfe56f73959470b
4
- data.tar.gz: ddd951e6773d11ce0a0db5214983774b8078e410451920cc441fdd55926c574e
3
+ metadata.gz: 2799bf290120d558fe48495596a987705abb4bc394622e459d597a746c5b57d6
4
+ data.tar.gz: e84597a7f20fa3f45219372403851390679841a27f90e50b57bf4d0aba88d1be
5
5
  SHA512:
6
- metadata.gz: a8ebe84816409a77d19b67d1ac8a244ef63bd3a8046e08f7193e40f8bb01c2866320aa52a3664a43ed07dc6d30c2f17005d33d2408e69574987b2e5127425b0a
7
- data.tar.gz: 296a144056ee9da865e663c9ef47dfc59811e24485c133a28a2b6978b62b37f7e8419a6c76e6e6aaacb52a03b599f04e18a9715e287f89c9fbff9fbac67a2c63
6
+ metadata.gz: c6eef386c693e4ba34e715dbc8c1334a48dbc2d454abeda218beed9cf4184a868089576e5253f3f592a3c0ab4efc9e0315da908332bfb962b070f0519ea549db
7
+ data.tar.gz: 421ecfff8bffbb3300b48ab7e0c670f3980ce7d39c33c079d7b53096ae7527d6ee47edaf151396979f96c78bb7fd841c31227ab66ceea9dc0590fd90f8b76c14
data/lib/exifr/jpeg.rb CHANGED
@@ -29,11 +29,11 @@ module EXIFR
29
29
  attr_reader :app1s
30
30
 
31
31
  # +file+ is a filename or an IO object. Hint: use StringIO when working with slurped data like blobs.
32
- def initialize(file)
32
+ def initialize(file, load_thumbnails: true)
33
33
  if file.kind_of? String
34
- File.open(file, 'rb') { |io| examine(io) }
34
+ File.open(file, 'rb') { |io| examine(io, load_thumbnails: load_thumbnails) }
35
35
  else
36
- examine(file.dup)
36
+ examine(file.dup, load_thumbnails: load_thumbnails)
37
37
  end
38
38
  end
39
39
 
@@ -95,7 +95,7 @@ module EXIFR
95
95
  end
96
96
  end
97
97
 
98
- def examine(io)
98
+ def examine(io, load_thumbnails: true)
99
99
  io = Reader.new(io)
100
100
 
101
101
  unless io.getbyte == 0xFF && io.getbyte == 0xD8 # SOI
@@ -121,7 +121,7 @@ module EXIFR
121
121
 
122
122
  if app1 = @app1s.find { |d| d[0..5] == "Exif\0\0" }
123
123
  @exif_data = app1[6..-1]
124
- @exif = TIFF.new(StringIO.new(@exif_data))
124
+ @exif = TIFF.new(StringIO.new(@exif_data), load_thumbnails: load_thumbnails)
125
125
  end
126
126
  end
127
127
  end
data/lib/exifr/tiff.rb CHANGED
@@ -375,7 +375,7 @@ module EXIFR
375
375
  TAGS = [TAG_MAPPING.keys, TAG_MAPPING.values.map{|v|v.values}].flatten.uniq - IFD_TAGS
376
376
 
377
377
  # +file+ is a filename or an +IO+ object. Hint: use +StringIO+ when working with slurped data like blobs.
378
- def initialize(file)
378
+ def initialize(file, load_thumbnails: true)
379
379
  Data.open(file) do |data|
380
380
  @ifds = [IFD.new(data)]
381
381
  while ifd = @ifds.last.next
@@ -383,17 +383,21 @@ module EXIFR
383
383
  @ifds << ifd
384
384
  end
385
385
 
386
- @jpeg_thumbnails = @ifds.map do |v|
387
- if v.jpeg_interchange_format && v.jpeg_interchange_format_length
388
- start, length = v.jpeg_interchange_format, v.jpeg_interchange_format_length
389
- if Integer === start && Integer === length
390
- data[start..(start + length)]
391
- else
392
- EXIFR.logger.warn("Non numeric JpegInterchangeFormat data")
393
- nil
386
+ if load_thumbnails
387
+ @jpeg_thumbnails = @ifds.map do |v|
388
+ if v.jpeg_interchange_format && v.jpeg_interchange_format_length
389
+ start, length = v.jpeg_interchange_format, v.jpeg_interchange_format_length
390
+ if Integer === start && Integer === length
391
+ data[start..(start + length)]
392
+ else
393
+ EXIFR.logger.warn("Non numeric JpegInterchangeFormat data")
394
+ nil
395
+ end
394
396
  end
395
- end
396
- end.compact
397
+ end.compact
398
+ else
399
+ @jpeg_thumbnails = []
400
+ end
397
401
  end
398
402
  end
399
403
 
@@ -482,10 +486,10 @@ module EXIFR
482
486
  end
483
487
 
484
488
  class IFD # :nodoc:
485
- attr_reader :type, :fields, :offset
489
+ attr_reader :type, :raw_fields, :fields, :offset
486
490
 
487
491
  def initialize(data, offset = nil, type = :image)
488
- @data, @offset, @type, @fields = data, offset, type, {}
492
+ @data, @offset, @type, @raw_fields, @fields = data, offset, type, {}, {}
489
493
 
490
494
  pos = offset || @data.readlong(4)
491
495
  num = @data.readshort(pos)
@@ -546,15 +550,16 @@ module EXIFR
546
550
 
547
551
  private
548
552
  def add_field(field)
549
- return unless tag = TAG_MAPPING[@type][field.tag]
550
- return if @fields[tag]
553
+ return if @raw_fields.include?(field.tag) # first encountered value wins
554
+ @raw_fields[field.tag] = field.value
551
555
 
552
- if IFD_TAGS.include? tag
553
- @fields[tag] = IFD.new(@data, field.offset, tag)
554
- else
555
- value = ADAPTERS[tag][field.value]
556
- @fields[tag] = value.kind_of?(Array) && value.size == 1 ? value.first : value
557
- end
556
+ return unless tag = TAG_MAPPING[@type][field.tag]
557
+ @fields[tag] = if IFD_TAGS.include?(tag)
558
+ IFD.new(@data, field.offset, tag)
559
+ else
560
+ value = ADAPTERS[tag][field.value]
561
+ value.kind_of?(Array) && value.size == 1 ? value.first : value
562
+ end
558
563
  end
559
564
  end
560
565
 
@@ -604,6 +609,10 @@ module EXIFR
604
609
  end
605
610
  rationals
606
611
  end
612
+ when 11 # float
613
+ len, pack = count * 4, proc { |d| d.unpack(data.float + '*') }
614
+ when 12 # double
615
+ len, pack = count * 8, proc { |d| d.unpack(data.double + '*') }
607
616
  else
608
617
  return
609
618
  end
@@ -638,7 +647,7 @@ module EXIFR
638
647
  end
639
648
 
640
649
  class Data #:nodoc:
641
- attr_reader :short, :long, :file
650
+ attr_reader :short, :long, :float, :double, :file
642
651
 
643
652
  def initialize(file)
644
653
  @io = file.respond_to?(:read) ? file : (@file = File.open(file, 'rb'))
@@ -646,8 +655,8 @@ module EXIFR
646
655
  @pos = 0
647
656
 
648
657
  case self[0..1]
649
- when 'II'; @short, @long = 'v', 'V'
650
- when 'MM'; @short, @long = 'n', 'N'
658
+ when 'II'; @short, @long, @float, @double = 'v', 'V', 'e', 'E'
659
+ when 'MM'; @short, @long, @float, @double = 'n', 'N', 'g', 'G'
651
660
  else
652
661
  raise MalformedTIFF, "no byte order information found"
653
662
  end
Binary file
Binary file
data/tests/jpeg_test.rb CHANGED
@@ -127,6 +127,13 @@ class JPEGTest < TestCase
127
127
  assert count > 0, 'no thumbnails found'
128
128
  end
129
129
 
130
+ def test_skippable_thumbnail
131
+ all_test_jpegs.each do |fname|
132
+ jpeg = JPEG.new(fname, load_thumbnails: false)
133
+ assert jpeg.thumbnail.nil?
134
+ end
135
+ end
136
+
130
137
  def test_gps_with_altitude
131
138
  t = JPEG.new(f('gps-altitude.jpg'))
132
139
 
data/tests/tiff_test.rb CHANGED
@@ -165,7 +165,12 @@ class TIFFTest < TestCase
165
165
  all_test_tiffs.each do |fname|
166
166
  t = TIFF.new(fname)
167
167
  y = YAML.dump(t)
168
- assert_literally_equal t.to_hash, YAML.load(y).to_hash
168
+ v = if YAML.respond_to?(:unsafe_load)
169
+ YAML.unsafe_load(y)
170
+ else
171
+ YAML.load(y)
172
+ end
173
+ assert_literally_equal t.to_hash, v.to_hash
169
174
  end
170
175
  end
171
176
 
@@ -183,6 +188,13 @@ class TIFFTest < TestCase
183
188
  assert count > 0, 'no thumbnails found'
184
189
  end
185
190
 
191
+ def test_skippable_jpeg_thumbnails
192
+ all_test_tiffs.each do |fname|
193
+ t = TIFF.new(fname, load_thumbnails: false)
194
+ assert t.jpeg_thumbnails.empty?
195
+ end
196
+ end
197
+
186
198
  def test_should_not_loop_endlessly
187
199
  TIFF.new(f('endless-loop.exif'))
188
200
  assert true
@@ -215,4 +227,8 @@ class TIFFTest < TestCase
215
227
  assert t.methods(true).include?(:make)
216
228
  assert ! t.methods(false).include?(:make)
217
229
  end
230
+
231
+ def test_unknow_field
232
+ assert_equal [1, 1, 1, 1], TIFF.new(f('plain.tif')).first.raw_fields[0x0153] # TIFF Tag SampleFormat
233
+ end
218
234
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exifr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.9
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - R.W. van 't Veer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-19 00:00:00.000000000 Z
11
+ date: 2023-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -59,6 +59,7 @@ files:
59
59
  - tests/data/Trust-DC3500_MINI.exif
60
60
  - tests/data/apple-aperture-1.5.exif
61
61
  - tests/data/bad-shutter_speed_value.exif
62
+ - tests/data/bad_gps.exif
62
63
  - tests/data/canon-g3.exif
63
64
  - tests/data/endless-loop.exif
64
65
  - tests/data/exif.jpg
@@ -66,6 +67,7 @@ files:
66
67
  - tests/data/gps-altitude.jpg
67
68
  - tests/data/gps.exif
68
69
  - tests/data/image.jpg
70
+ - tests/data/ios-mspix-milliseconds.jpg
69
71
  - tests/data/multiple-app1.jpg
70
72
  - tests/data/negative-exposure-bias-value.exif
71
73
  - tests/data/nikon_d1x.tif
@@ -73,6 +75,7 @@ files:
73
75
  - tests/data/plain.tif
74
76
  - tests/data/samsung-sc-02b.jpg
75
77
  - tests/data/sony-a7ii.exif
78
+ - tests/data/truncated.exif
76
79
  - tests/data/user-comment.exif
77
80
  - tests/data/weird_date.exif
78
81
  - tests/jpeg_test.rb
@@ -95,14 +98,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
98
  requirements:
96
99
  - - ">="
97
100
  - !ruby/object:Gem::Version
98
- version: 1.8.7
101
+ version: '2.0'
99
102
  required_rubygems_version: !ruby/object:Gem::Requirement
100
103
  requirements:
101
104
  - - ">="
102
105
  - !ruby/object:Gem::Version
103
106
  version: '0'
104
107
  requirements: []
105
- rubygems_version: 3.1.4
108
+ rubygems_version: 3.4.6
106
109
  signing_key:
107
110
  specification_version: 4
108
111
  summary: Read EXIF from JPEG and TIFF images