fastimage 2.1.4 → 2.2.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.textile +2 -1
  3. data/lib/fastimage.rb +129 -12
  4. metadata +5 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 902efb5765c025c827bb5f757f9516a5c2fb023c0d6113d98107a8f83435f9f6
4
- data.tar.gz: 2394630697a1bfc4cddfa102eecab62bb46df3feca9b0a9996ca52ec365045b9
3
+ metadata.gz: 72e83c6f6d442c29071e060cca8a8b0a0a17024a7871cd19a64b83f77e0c0ced
4
+ data.tar.gz: 56d0f5f86e11f1a8922cdf5bbe292fef2753f5637df402fd7532ef21d8393537
5
5
  SHA512:
6
- metadata.gz: de2b26a82e0ddd6587dcbbbcda836d2edcef668939f9bf37df5910b5cf2dbcda9fb3668146d72d802cb45fde546cc16c44e62845c0e82194c3a6d83598d9ecbd
7
- data.tar.gz: 720f45a86ef6c3261f2d66606c1fff42157738e4b4353f549eb576212d54ec8f6f934c229f22b62d0757c2db6784b8b2dae13b33a4a80ce60b15ea092d259b69
6
+ metadata.gz: 002eb40a04b2ce79f8cdc34ee2fdc0d70fe35ff964d380096302682756a17e4b22f8275e335822f5229080aada2ca8d5d17603607cb0cf6479b61ac6d4dd64ef
7
+ data.tar.gz: 17c8efefdc90fae00178d045bb0670e2914f9f19eabdb0be983c49ffb573b752672f02678e38b1395129d7f55ffc42905fa1cbeb9017445ffa295db6cc4fe119
@@ -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
 
@@ -156,6 +156,7 @@ h2. FastImage in other languages
156
156
  * "Node.js by ShogunPanda":https://github.com/ShogunPanda/fastimage
157
157
  * "Objective C by kylehickinson":https://github.com/kylehickinson/FastImage
158
158
  * "Android by qstumn":https://github.com/qstumn/FastImageSize
159
+ * "Flutter by ky1vstar":https://github.com/ky1vstar/fastimage.dart
159
160
 
160
161
  h2. Licence
161
162
 
@@ -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
 
@@ -214,7 +248,8 @@ class FastImage
214
248
  raise SizeNotFound if @options[:raise_on_failure] && @property == :size && !@size
215
249
 
216
250
  rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET,
217
- ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT, OpenSSL::SSL::SSLError
251
+ Errno::ENETUNREACH, ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT,
252
+ OpenSSL::SSL::SSLError
218
253
  raise ImageFetchFailure if @options[:raise_on_failure]
219
254
  rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug
220
255
  raise ImageFetchFailure if @options[:raise_on_failure]
@@ -247,7 +282,7 @@ class FastImage
247
282
  begin
248
283
  URI(location)
249
284
  rescue URI::InvalidURIError
250
- URI.escape(location)
285
+ ::URI::DEFAULT_PARSER.escape(location)
251
286
  else
252
287
  location
253
288
  end
@@ -261,7 +296,10 @@ class FastImage
261
296
  if res.is_a?(Net::HTTPRedirection) && @redirect_count < 4
262
297
  @redirect_count += 1
263
298
  begin
264
- @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))
265
303
  rescue URI::InvalidURIError
266
304
  else
267
305
  fetch_using_http_from_parsed_uri
@@ -321,7 +359,7 @@ class FastImage
321
359
  proxy = proxy_uri
322
360
 
323
361
  if proxy
324
- @http = Net::HTTP::Proxy(proxy.host, proxy.port).new(@parsed_uri.host, @parsed_uri.port)
362
+ @http = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new(@parsed_uri.host, @parsed_uri.port)
325
363
  else
326
364
  @http = Net::HTTP.new(@parsed_uri.host, @parsed_uri.port)
327
365
  end
@@ -332,6 +370,7 @@ class FastImage
332
370
  end
333
371
 
334
372
  def fetch_using_read(readable)
373
+ readable.rewind if readable.respond_to?(:rewind)
335
374
  # Pathnames respond to read, but always return the first
336
375
  # chunk of the file unlike an IO (even though the
337
376
  # docuementation for it refers to IO). Need to supply
@@ -367,7 +406,7 @@ class FastImage
367
406
 
368
407
  begin
369
408
  result = send("parse_#{@property}")
370
- if result
409
+ if result != nil
371
410
  # extract exif orientation if it was found
372
411
  if @property == :size && result.size == 3
373
412
  @orientation = result.pop
@@ -389,6 +428,11 @@ class FastImage
389
428
  send("parse_size_for_#{@type}")
390
429
  end
391
430
 
431
+ def parse_animated
432
+ @type = parse_type unless @type
433
+ @type == :gif ? send("parse_animated_for_#{@type}") : nil
434
+ end
435
+
392
436
  def fetch_using_base64(uri)
393
437
  data = uri.split(',')[1]
394
438
  decoded = Base64.decode64(data)
@@ -500,7 +544,7 @@ class FastImage
500
544
  when "RI"
501
545
  :webp if @stream.peek(12)[8..11] == "WEBP"
502
546
  when "<s"
503
- :svg
547
+ :svg if @stream.peek(4) == "<svg"
504
548
  when /<[?!]/
505
549
  # Peek 10 more chars each time, and if end of file is reached just raise
506
550
  # unknown. We assume the <svg tag cannot be within 10 chars of the end of
@@ -522,8 +566,76 @@ class FastImage
522
566
  end
523
567
  alias_method :parse_size_for_cur, :parse_size_for_ico
524
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
+ frames = 0
582
+
583
+ # "GIF" + version (3) + width (2) + height (2)
584
+ @stream.skip(10)
585
+
586
+ # fields (1) + bg color (1) + pixel ratio (1)
587
+ fields = @stream.read(3).unpack("CCC")[0]
588
+ if fields & 0x80 # Global Color Table
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
+
596
+ if block_type == 0x21 # Graphic Control Extension
597
+ # extension type (1) + size (1)
598
+ size = @stream.read(2).unpack("CC")[1]
599
+ @stream.skip(size)
600
+ skip_sub_blocks
601
+ elsif block_type == 0x2C # Image Descriptor
602
+ frames += 1
603
+ return true if frames > 1
604
+
605
+ # left position (2) + top position (2) + width (2) + height (2) + fields (1)
606
+ fields = @stream.read(9).unpack("SSSSC")[4]
607
+ if fields & 0x80 != 0 # Local Color Table
608
+ # 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
609
+ @stream.skip(3 * 2 ** ((fields & 0x7) + 1))
610
+ end
611
+
612
+ @stream.skip(1) # LZW min code size (1)
613
+ skip_sub_blocks
614
+ else
615
+ break # unrecognized block
616
+ end
617
+ end
618
+
619
+ false
620
+ end
621
+
622
+ private
623
+
624
+ def skip_sub_blocks
625
+ loop do
626
+ size = @stream.read(1).unpack("C")[0]
627
+ if size == 0
628
+ break
629
+ else
630
+ @stream.skip(size)
631
+ end
632
+ end
633
+ end
634
+ end
635
+
525
636
  def parse_size_for_gif
526
- @stream.read(11)[6..10].unpack('SS')
637
+ gif = Gif.new(@stream)
638
+ gif.width_and_height
527
639
  end
528
640
 
529
641
  def parse_size_for_png
@@ -578,10 +690,10 @@ class FastImage
578
690
  d = @stream.read(32)[14..28]
579
691
  header = d.unpack("C")[0]
580
692
 
581
- result = if header == 40
582
- d[4..-1].unpack('l<l<')
583
- else
693
+ result = if header == 12
584
694
  d[4..8].unpack('SS')
695
+ else
696
+ d[4..-1].unpack('l<l<')
585
697
  end
586
698
 
587
699
  # ImageHeight is expressed in pixels. The absolute value is necessary because ImageHeight can be negative
@@ -783,4 +895,9 @@ class FastImage
783
895
  svg = Svg.new(@stream)
784
896
  svg.width_and_height
785
897
  end
898
+
899
+ def parse_animated_for_gif
900
+ gif = Gif.new(@stream)
901
+ gif.animated?
902
+ end
786
903
  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.4
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-09 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
@@ -97,8 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  requirements: []
100
- rubyforge_project:
101
- rubygems_version: 2.7.6
100
+ rubygems_version: 3.0.3
102
101
  signing_key:
103
102
  specification_version: 4
104
103
  summary: FastImage - Image info fast