fastimage 2.1.5 → 2.2.2

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 +3 -2
  3. data/lib/fastimage.rb +140 -22
  4. metadata +8 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d0945496f100e228621d0ef69bb88b24a5dc137e47f1a1c868c547ca1b8866f
4
- data.tar.gz: 5b78353d899bbf42cc46942275ebdc3f6938f732ad5e9d07201bddb1d52b0d1b
3
+ metadata.gz: 6e4c8a8fb1f0bf8db7dff5aef7fd640d56e0938bd0c0e8bd2f5f0a659009429d
4
+ data.tar.gz: f827ef53ce46af99612e2628f72ed5bfa2c82b4729ea3a5dccd76dc67079b6c3
5
5
  SHA512:
6
- metadata.gz: 17d0ff83ffda0c353cab93a7fa4733681be77f81d1d3dbd67eecab795454c2e25bd341c0c6113d4e287aabef59c7f13327359c2449c469415ecff4d03011b178
7
- data.tar.gz: 6aee4ed8228cb834492c8df5a69c5e4eab869460e81999fcdd5f0ce75745d4bf62b228140de92b08d8a10a63c4b39c3892a37dcb85e64baa2ca10b99b9fba7c8
6
+ metadata.gz: 599ffa78f1020ece118a5f1bc47533ad98085ac6f71ede9ad4b2b0c1d8748c81e4fb060f6a1b9f5001f7df2661d70d9a16972bd118863461d39d491d0e3b2988
7
+ data.tar.gz: d761639e39eae059e2f810c7d6a124515d3c6db1470236044db376b424e78effaf48c51f4197c3a565c1aae3d1f742e1899e221f566a828c4f1f209d4e91d588
@@ -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
 
@@ -132,7 +132,7 @@ h2. Tests
132
132
 
133
133
  You'll need to @gem install fakeweb@ and possibly also @gem install test-unit@ to be able to run the tests.
134
134
 
135
- bc.. $ ruby test.rb
135
+ bc.. $ ruby test/test.rb
136
136
  Run options:
137
137
 
138
138
  # Running tests:
@@ -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,12 +248,11 @@ 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
218
- raise ImageFetchFailure if @options[:raise_on_failure]
219
- rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug
251
+ Errno::ENETUNREACH, ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT,
252
+ OpenSSL::SSL::SSLError
220
253
  raise ImageFetchFailure if @options[:raise_on_failure]
221
254
  rescue UnknownImageType
222
- raise UnknownImageType if @options[:raise_on_failure]
255
+ raise if @options[:raise_on_failure]
223
256
  rescue CannotParseImage
224
257
  if @options[:raise_on_failure]
225
258
  if @property == :size
@@ -247,7 +280,7 @@ class FastImage
247
280
  begin
248
281
  URI(location)
249
282
  rescue URI::InvalidURIError
250
- URI.escape(location)
283
+ ::URI::DEFAULT_PARSER.escape(location)
251
284
  else
252
285
  location
253
286
  end
@@ -261,7 +294,10 @@ class FastImage
261
294
  if res.is_a?(Net::HTTPRedirection) && @redirect_count < 4
262
295
  @redirect_count += 1
263
296
  begin
264
- @parsed_uri = URI.join(@parsed_uri, escaped_location(res['Location']))
297
+ location = res['Location']
298
+ raise ImageFetchFailure if location.nil? || location.empty?
299
+
300
+ @parsed_uri = URI.join(@parsed_uri, escaped_location(location))
265
301
  rescue URI::InvalidURIError
266
302
  else
267
303
  fetch_using_http_from_parsed_uri
@@ -321,7 +357,7 @@ class FastImage
321
357
  proxy = proxy_uri
322
358
 
323
359
  if proxy
324
- @http = Net::HTTP::Proxy(proxy.host, proxy.port).new(@parsed_uri.host, @parsed_uri.port)
360
+ @http = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new(@parsed_uri.host, @parsed_uri.port)
325
361
  else
326
362
  @http = Net::HTTP.new(@parsed_uri.host, @parsed_uri.port)
327
363
  end
@@ -368,7 +404,7 @@ class FastImage
368
404
 
369
405
  begin
370
406
  result = send("parse_#{@property}")
371
- if result
407
+ if result != nil
372
408
  # extract exif orientation if it was found
373
409
  if @property == :size && result.size == 3
374
410
  @orientation = result.pop
@@ -390,9 +426,17 @@ class FastImage
390
426
  send("parse_size_for_#{@type}")
391
427
  end
392
428
 
429
+ def parse_animated
430
+ @type = parse_type unless @type
431
+ @type == :gif ? send("parse_animated_for_#{@type}") : nil
432
+ end
433
+
393
434
  def fetch_using_base64(uri)
394
- data = uri.split(',')[1]
395
- decoded = Base64.decode64(data)
435
+ decoded = begin
436
+ Base64.decode64(uri.split(',')[1])
437
+ rescue
438
+ raise CannotParseImage
439
+ end
396
440
  @content_length = decoded.size
397
441
  fetch_using_read StringIO.new(decoded)
398
442
  end
@@ -428,19 +472,20 @@ class FastImage
428
472
 
429
473
  # Peeking beyond the end of the input will raise
430
474
  def peek(n)
431
- while @strpos + n - 1 >= @str.size
475
+ while @strpos + n > @str.size
432
476
  unused_str = @str[@strpos..-1]
477
+
433
478
  new_string = @read_fiber.resume
479
+ new_string = @read_fiber.resume if new_string.is_a? Net::ReadAdapter
434
480
  raise CannotParseImage if !new_string
435
-
436
481
  # we are dealing with bytes here, so force the encoding
437
- new_string.force_encoding("ASCII-8BIT") if String.method_defined? :force_encoding
482
+ new_string.force_encoding("ASCII-8BIT") if new_string.respond_to? :force_encoding
438
483
 
439
484
  @str = unused_str + new_string
440
485
  @strpos = 0
441
486
  end
442
487
 
443
- @str[@strpos..(@strpos + n - 1)]
488
+ @str[@strpos, n]
444
489
  end
445
490
 
446
491
  def read(n)
@@ -458,7 +503,7 @@ class FastImage
458
503
  new_string = @read_fiber.resume
459
504
  raise CannotParseImage if !new_string
460
505
 
461
- new_string.force_encoding("ASCII-8BIT") if String.method_defined? :force_encoding
506
+ new_string.force_encoding("ASCII-8BIT") if new_string.respond_to? :force_encoding
462
507
 
463
508
  fetched += new_string.size
464
509
  @str = new_string
@@ -501,7 +546,7 @@ class FastImage
501
546
  when "RI"
502
547
  :webp if @stream.peek(12)[8..11] == "WEBP"
503
548
  when "<s"
504
- :svg
549
+ :svg if @stream.peek(4) == "<svg"
505
550
  when /<[?!]/
506
551
  # Peek 10 more chars each time, and if end of file is reached just raise
507
552
  # unknown. We assume the <svg tag cannot be within 10 chars of the end of
@@ -523,8 +568,76 @@ class FastImage
523
568
  end
524
569
  alias_method :parse_size_for_cur, :parse_size_for_ico
525
570
 
571
+ class Gif # :nodoc:
572
+ def initialize(stream)
573
+ @stream = stream
574
+ end
575
+
576
+ def width_and_height
577
+ @stream.read(11)[6..10].unpack('SS')
578
+ end
579
+
580
+ # Checks if a delay between frames exists and if it does, then the GIFs is
581
+ # animated
582
+ def animated?
583
+ frames = 0
584
+
585
+ # "GIF" + version (3) + width (2) + height (2)
586
+ @stream.skip(10)
587
+
588
+ # fields (1) + bg color (1) + pixel ratio (1)
589
+ fields = @stream.read(3).unpack("CCC")[0]
590
+ if fields & 0x80 != 0 # Global Color Table
591
+ # 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
592
+ @stream.skip(3 * 2 ** ((fields & 0x7) + 1))
593
+ end
594
+
595
+ loop do
596
+ block_type = @stream.read(1).unpack("C")[0]
597
+
598
+ if block_type == 0x21 # Graphic Control Extension
599
+ # extension type (1) + size (1)
600
+ size = @stream.read(2).unpack("CC")[1]
601
+ @stream.skip(size)
602
+ skip_sub_blocks
603
+ elsif block_type == 0x2C # Image Descriptor
604
+ frames += 1
605
+ return true if frames > 1
606
+
607
+ # left position (2) + top position (2) + width (2) + height (2) + fields (1)
608
+ fields = @stream.read(9).unpack("SSSSC")[4]
609
+ if fields & 0x80 != 0 # Local Color Table
610
+ # 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
611
+ @stream.skip(3 * 2 ** ((fields & 0x7) + 1))
612
+ end
613
+
614
+ @stream.skip(1) # LZW min code size (1)
615
+ skip_sub_blocks
616
+ else
617
+ break # unrecognized block
618
+ end
619
+ end
620
+
621
+ false
622
+ end
623
+
624
+ private
625
+
626
+ def skip_sub_blocks
627
+ loop do
628
+ size = @stream.read(1).unpack("C")[0]
629
+ if size == 0
630
+ break
631
+ else
632
+ @stream.skip(size)
633
+ end
634
+ end
635
+ end
636
+ end
637
+
526
638
  def parse_size_for_gif
527
- @stream.read(11)[6..10].unpack('SS')
639
+ gif = Gif.new(@stream)
640
+ gif.width_and_height
528
641
  end
529
642
 
530
643
  def parse_size_for_png
@@ -579,10 +692,10 @@ class FastImage
579
692
  d = @stream.read(32)[14..28]
580
693
  header = d.unpack("C")[0]
581
694
 
582
- result = if header == 40
583
- d[4..-1].unpack('l<l<')
584
- else
695
+ result = if header == 12
585
696
  d[4..8].unpack('SS')
697
+ else
698
+ d[4..-1].unpack('l<l<')
586
699
  end
587
700
 
588
701
  # ImageHeight is expressed in pixels. The absolute value is necessary because ImageHeight can be negative
@@ -784,4 +897,9 @@ class FastImage
784
897
  svg = Svg.new(@stream)
785
898
  svg.width_and_height
786
899
  end
900
+
901
+ def parse_animated_for_gif
902
+ gif = Gif.new(@stream)
903
+ gif.animated?
904
+ end
787
905
  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.5
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-29 00:00:00.000000000 Z
11
+ date: 2021-01-30 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
@@ -81,7 +81,7 @@ homepage: http://github.com/sdsykes/fastimage
81
81
  licenses:
82
82
  - MIT
83
83
  metadata: {}
84
- post_install_message:
84
+ post_install_message:
85
85
  rdoc_options:
86
86
  - "--charset=UTF-8"
87
87
  require_paths:
@@ -97,9 +97,8 @@ 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
102
- signing_key:
100
+ rubygems_version: 3.2.3
101
+ signing_key:
103
102
  specification_version: 4
104
103
  summary: FastImage - Image info fast
105
104
  test_files: []