fastimage 2.1.6 → 2.2.3

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 +3 -2
  3. data/lib/fastimage.rb +141 -23
  4. metadata +8 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e7aac521599a47fcc01c2aab866e644c18a0414dd93c2ebc4b04d7ccd294dab
4
- data.tar.gz: 76744799d19d92a539a877dc246968b9ff38d157cda06062ecda401144de363a
3
+ metadata.gz: 4124655c4f8af69e9b8bf9bfa433a11161e9ea97c23e755a196555012eadf75b
4
+ data.tar.gz: 40fef6aa908fc14799f2cb53e80d5081bef11ce0482d86c5947841fb29ee9604
5
5
  SHA512:
6
- metadata.gz: c9d14f0a65fcdf3565cdbbddbf9f1d3fd6532cc8ad8605e72c726d377eb133c3548645bd97788e5b05ee94ceced5c58beb90ac2a1794bf515edbbbd4d0cdb1c1
7
- data.tar.gz: 8bfc2d38b4228ce7b00cb3a8c0323daf7eb604915a36f355b991e95e562c8f759e3bd238f0c1bf3b5aede00c7b8822fb857b2fd398231b91bba4c28b96833678
6
+ metadata.gz: 205fb43dacd3239f8425dd8cbd311be8c375f3c377cbf71771b87304b0c62780905a366783b1b5606e7386edf9ed2fe1cab138b8a20ad47f238150d5143b93db
7
+ data.tar.gz: 219ac67b55c23bb59458fc57d165a76c0bf5855c971c705d033103c01848cbb9f3fb4a1e8024419192ced93f076d223fb6e3ce77289b8ed94858d0e58c5387df
data/README.textile CHANGED
@@ -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
 
data/lib/fastimage.rb CHANGED
@@ -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,8 +546,8 @@ class FastImage
501
546
  when "RI"
502
547
  :webp if @stream.peek(12)[8..11] == "WEBP"
503
548
  when "<s"
504
- :svg
505
- when /<[?!]/
549
+ :svg if @stream.peek(4) == "<svg"
550
+ when /\s\s|\s<|<[?!]/
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
508
553
  # the file, and is within the first 250 chars.
@@ -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.6
4
+ version: 2.2.3
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: 2019-09-05 00:00:00.000000000 Z
11
+ date: 2021-02-28 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: []