fastimage 2.1.4 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
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