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.
- checksums.yaml +4 -4
- data/README.textile +2 -1
- data/lib/fastimage.rb +129 -12
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72e83c6f6d442c29071e060cca8a8b0a0a17024a7871cd19a64b83f77e0c0ced
|
4
|
+
data.tar.gz: 56d0f5f86e11f1a8922cdf5bbe292fef2753f5637df402fd7532ef21d8393537
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 002eb40a04b2ce79f8cdc34ee2fdc0d70fe35ff964d380096302682756a17e4b22f8275e335822f5229080aada2ca8d5d17603607cb0cf6479b61ac6d4dd64ef
|
7
|
+
data.tar.gz: 17c8efefdc90fae00178d045bb0670e2914f9f19eabdb0be983c49ffb573b752672f02678e38b1395129d7f55ffc42905fa1cbeb9017445ffa295db6cc4fe119
|
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.
|
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
|
|
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[:
|
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,
|
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
|
-
|
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
|
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 ==
|
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
|
+
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:
|
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
|
-
|
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
|