fastimage 2.1.7 → 2.2.0

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.textile +1 -1
  3. data/lib/fastimage.rb +115 -7
  4. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2aaa7bc9e7b596326f39fc933d836e8d94a0c19601670c0b55c839ba8d0e9ed5
4
- data.tar.gz: b807e4cb3ac6ac16b10c026d15ac6a6440a65a75036482518b1a337475bd723b
3
+ metadata.gz: 53c0966ef5216c189e2950b1ad36c106777175f0d4dca9851abd34472fd9cb61
4
+ data.tar.gz: 29f5a6bc03623e184166e7f9c5e8c4379011b301904d4c690037d5b7b0ba0b33
5
5
  SHA512:
6
- metadata.gz: 8a87fd1e5eb5a209da0c2a2af1d7c0d6cead3f14af8cc591810e0e0d7b853cd519e236f9ec0ed70fdea0c39569631f5b41f88f5fea8942aa55fbe018390102ef
7
- data.tar.gz: 002d20c88557352e4b3ebb80975d2f26cffa221cc3c510a0865ffed55fe251a63f53dfeff53843f351574cff1aa9c9864d5df1a2e5fc9a4550b5e03fd798880a
6
+ metadata.gz: 28e8ec4debe6c2c477da19cafb1ad41e5de4d809136bd86621ae128372c32c1259abea833856f73dfcfe8ef3444bc5e1a148f91b52ee02d3292235c4d95fc542
7
+ data.tar.gz: ba8b4c6bb42146387b1a8af718fbbaf74a9a94532ee5adce082ff676095dad5d5e0eb613f1ec41d7729709847195fa81c4614f2d9d510d6c7def67f8970f168e
@@ -1,5 +1,5 @@
1
1
  !https://img.shields.io/gem/dt/fastimage.svg!:https://rubygems.org/gems/fastimage
2
- !https://travis-ci.org/sdsykes/fastimage.png?branch=master!:https://travis-ci.org/sdsykes/fastimage
2
+ !https://travis-ci.org/sdsykes/fastimage.svg?branch=master!:https://travis-ci.org/sdsykes/fastimage
3
3
 
4
4
  h1. FastImage
5
5
 
@@ -70,7 +70,7 @@ if RUBY_VERSION < "2.2"
70
70
  end
71
71
 
72
72
  class FastImage
73
- attr_reader :size, :type, :content_length, :orientation
73
+ attr_reader :size, :type, :content_length, :orientation, :animated
74
74
 
75
75
  attr_reader :bytes_read
76
76
 
@@ -179,6 +179,34 @@ class FastImage
179
179
  new(uri, options.merge(:type_only=>true)).type
180
180
  end
181
181
 
182
+ # Returns a boolean value indicating the image is animated.
183
+ # It will return nil if the image could not be fetched, or if the image type was not recognised.
184
+ #
185
+ # By default there is a timeout of 2 seconds for opening and reading from a remote server.
186
+ # This can be changed by passing a :timeout => number_of_seconds in the options.
187
+ #
188
+ # If you wish FastImage to raise if it cannot find the type of the image for any reason, then pass
189
+ # :raise_on_failure => true in the options.
190
+ #
191
+ # === Example
192
+ #
193
+ # require 'fastimage'
194
+ #
195
+ # FastImage.animated?("test/fixtures/test.gif")
196
+ # => false
197
+ # FastImage.animated?("test/fixtures/animated.gif")
198
+ # => true
199
+ #
200
+ # === Supported options
201
+ # [:timeout]
202
+ # Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
203
+ # [:raise_on_failure]
204
+ # If set to true causes an exception to be raised if the image type cannot be found for any reason.
205
+ #
206
+ def self.animated?(uri, options={})
207
+ new(uri, options.merge(:animated_only=>true)).animated
208
+ end
209
+
182
210
  def initialize(uri, options={})
183
211
  @uri = uri
184
212
  @options = {
@@ -189,7 +217,13 @@ class FastImage
189
217
  :http_header => {}
190
218
  }.merge(options)
191
219
 
192
- @property = @options[:type_only] ? :type : :size
220
+ @property = if @options[:animated_only]
221
+ :animated
222
+ elsif @options[:type_only]
223
+ :type
224
+ else
225
+ :size
226
+ end
193
227
 
194
228
  @type, @state = nil
195
229
 
@@ -248,7 +282,7 @@ class FastImage
248
282
  begin
249
283
  URI(location)
250
284
  rescue URI::InvalidURIError
251
- URI.escape(location)
285
+ ::URI::DEFAULT_PARSER.escape(location)
252
286
  else
253
287
  location
254
288
  end
@@ -262,7 +296,10 @@ class FastImage
262
296
  if res.is_a?(Net::HTTPRedirection) && @redirect_count < 4
263
297
  @redirect_count += 1
264
298
  begin
265
- @parsed_uri = URI.join(@parsed_uri, escaped_location(res['Location']))
299
+ location = res['Location']
300
+ raise ImageFetchFailure if location.nil? || location.empty?
301
+
302
+ @parsed_uri = URI.join(@parsed_uri, escaped_location(location))
266
303
  rescue URI::InvalidURIError
267
304
  else
268
305
  fetch_using_http_from_parsed_uri
@@ -369,7 +406,7 @@ class FastImage
369
406
 
370
407
  begin
371
408
  result = send("parse_#{@property}")
372
- if result
409
+ if result != nil
373
410
  # extract exif orientation if it was found
374
411
  if @property == :size && result.size == 3
375
412
  @orientation = result.pop
@@ -391,6 +428,11 @@ class FastImage
391
428
  send("parse_size_for_#{@type}")
392
429
  end
393
430
 
431
+ def parse_animated
432
+ @type = parse_type unless @type
433
+ @type == :gif ? send("parse_animated_for_#{@type}") : nil
434
+ end
435
+
394
436
  def fetch_using_base64(uri)
395
437
  data = uri.split(',')[1]
396
438
  decoded = Base64.decode64(data)
@@ -502,7 +544,7 @@ class FastImage
502
544
  when "RI"
503
545
  :webp if @stream.peek(12)[8..11] == "WEBP"
504
546
  when "<s"
505
- :svg
547
+ :svg if @stream.peek(4) == "<svg"
506
548
  when /<[?!]/
507
549
  # Peek 10 more chars each time, and if end of file is reached just raise
508
550
  # unknown. We assume the <svg tag cannot be within 10 chars of the end of
@@ -524,8 +566,69 @@ class FastImage
524
566
  end
525
567
  alias_method :parse_size_for_cur, :parse_size_for_ico
526
568
 
569
+ class Gif # :nodoc:
570
+ def initialize(stream)
571
+ @stream = stream
572
+ end
573
+
574
+ def width_and_height
575
+ @stream.read(11)[6..10].unpack('SS')
576
+ end
577
+
578
+ # Checks if a delay between frames exists and if it does, then the GIFs is
579
+ # animated
580
+ def animated?
581
+ delay = 0
582
+
583
+ @stream.read(10) # "GIF" + version (3) + width (2) + height (2)
584
+
585
+ fields = @stream.read(3).unpack("C")[0] # fields (1) + bg color (1) + pixel ratio (1)
586
+
587
+ # Skip Global Color Table if it exists
588
+ if fields & 0x80
589
+ # 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
590
+ @stream.skip(3 * 2 ** ((fields & 0x7) + 1))
591
+ end
592
+
593
+ loop do
594
+ block_type = @stream.read(1).unpack("C")[0]
595
+ if block_type == 0x21
596
+ extension_type = @stream.read(1).unpack("C")[0]
597
+ size = @stream.read(1).unpack("C")[0]
598
+ if extension_type == 0xF9
599
+ delay = @stream.read(4).unpack("CSC")[1] # fields (1) + delay (2) + transparent index (1)
600
+ break
601
+ elsif extension_type == 0xFF
602
+ @stream.skip(size) # application ID (8) + version (3)
603
+ else
604
+ return # unrecognized extension
605
+ end
606
+ skip_sub_blocks
607
+ else
608
+ return # unrecognized block
609
+ end
610
+ end
611
+
612
+ delay > 0
613
+ end
614
+
615
+ private
616
+
617
+ def skip_sub_blocks
618
+ loop do
619
+ size = @stream.read(1).unpack("C")[0]
620
+ if size == 0
621
+ break
622
+ else
623
+ @stream.skip(size)
624
+ end
625
+ end
626
+ end
627
+ end
628
+
527
629
  def parse_size_for_gif
528
- @stream.read(11)[6..10].unpack('SS')
630
+ gif = Gif.new(@stream)
631
+ gif.width_and_height
529
632
  end
530
633
 
531
634
  def parse_size_for_png
@@ -785,4 +888,9 @@ class FastImage
785
888
  svg = Svg.new(@stream)
786
889
  svg.width_and_height
787
890
  end
891
+
892
+ def parse_animated_for_gif
893
+ gif = Gif.new(@stream)
894
+ gif.animated?
895
+ end
788
896
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.7
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-05 00:00:00.000000000 Z
11
+ date: 2020-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fakeweb-fi
@@ -28,14 +28,14 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.5'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.5'
41
41
  - !ruby/object:Gem::Dependency