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.
- checksums.yaml +4 -4
- data/README.textile +3 -2
- data/lib/fastimage.rb +141 -23
- metadata +8 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4124655c4f8af69e9b8bf9bfa433a11161e9ea97c23e755a196555012eadf75b
|
4
|
+
data.tar.gz: 40fef6aa908fc14799f2cb53e80d5081bef11ce0482d86c5947841fb29ee9604
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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[:
|
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,
|
218
|
-
|
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
|
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
|
-
|
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
|
-
|
395
|
-
|
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
|
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
|
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
|
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
|
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
|
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 ==
|
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.
|
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:
|
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
|
-
|
101
|
-
|
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: []
|