fastimage 2.1.7 → 2.2.6
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/version.rb +5 -0
- data/lib/fastimage.rb +322 -19
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7667683a4bbc8ac16d583fb3ed7c93e6a58a25c19bf8df909ab7dae8d4ef782
|
4
|
+
data.tar.gz: 0baf5dcf6af104d0edd38baf65b7b35c972e6fc4271363d52855071e22b97a82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9261157ade925ba5be4761028b4d70a698f1cc4d54e4ef0fcb7f4b23b6120ae6f9c42516b0dc17f915c423d168a4ef66c805a686ea20e3ca311556ce3e930593
|
7
|
+
data.tar.gz: 2d319a0aa6c4e7c7a3d951b3025d6215ac999bc2efe5d054720dac9c063cb3e2939e35e30660cf360bfae5f88285b91bb8029ec594c64ca1eb9e3e4144fa6b4c
|
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
@@ -61,6 +61,7 @@ require 'pathname'
|
|
61
61
|
require 'zlib'
|
62
62
|
require 'base64'
|
63
63
|
require 'uri'
|
64
|
+
require_relative 'fastimage/version'
|
64
65
|
|
65
66
|
# see http://stackoverflow.com/questions/5208851/i/41048816#41048816
|
66
67
|
if RUBY_VERSION < "2.2"
|
@@ -70,7 +71,7 @@ if RUBY_VERSION < "2.2"
|
|
70
71
|
end
|
71
72
|
|
72
73
|
class FastImage
|
73
|
-
attr_reader :size, :type, :content_length, :orientation
|
74
|
+
attr_reader :size, :type, :content_length, :orientation, :animated
|
74
75
|
|
75
76
|
attr_reader :bytes_read
|
76
77
|
|
@@ -89,6 +90,8 @@ class FastImage
|
|
89
90
|
|
90
91
|
LocalFileChunkSize = 256 unless const_defined?(:LocalFileChunkSize)
|
91
92
|
|
93
|
+
SUPPORTED_IMAGE_TYPES = [:bmp, :gif, :jpeg, :png, :tiff, :psd, :heic, :heif, :webp, :svg, :ico, :cur].freeze
|
94
|
+
|
92
95
|
# Returns an array containing the width and height of the image.
|
93
96
|
# It will return nil if the image could not be fetched, or if the image type was not recognised.
|
94
97
|
#
|
@@ -179,6 +182,34 @@ class FastImage
|
|
179
182
|
new(uri, options.merge(:type_only=>true)).type
|
180
183
|
end
|
181
184
|
|
185
|
+
# Returns a boolean value indicating the image is animated.
|
186
|
+
# It will return nil if the image could not be fetched, or if the image type was not recognised.
|
187
|
+
#
|
188
|
+
# By default there is a timeout of 2 seconds for opening and reading from a remote server.
|
189
|
+
# This can be changed by passing a :timeout => number_of_seconds in the options.
|
190
|
+
#
|
191
|
+
# If you wish FastImage to raise if it cannot find the type of the image for any reason, then pass
|
192
|
+
# :raise_on_failure => true in the options.
|
193
|
+
#
|
194
|
+
# === Example
|
195
|
+
#
|
196
|
+
# require 'fastimage'
|
197
|
+
#
|
198
|
+
# FastImage.animated?("test/fixtures/test.gif")
|
199
|
+
# => false
|
200
|
+
# FastImage.animated?("test/fixtures/animated.gif")
|
201
|
+
# => true
|
202
|
+
#
|
203
|
+
# === Supported options
|
204
|
+
# [:timeout]
|
205
|
+
# Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
|
206
|
+
# [:raise_on_failure]
|
207
|
+
# If set to true causes an exception to be raised if the image type cannot be found for any reason.
|
208
|
+
#
|
209
|
+
def self.animated?(uri, options={})
|
210
|
+
new(uri, options.merge(:animated_only=>true)).animated
|
211
|
+
end
|
212
|
+
|
182
213
|
def initialize(uri, options={})
|
183
214
|
@uri = uri
|
184
215
|
@options = {
|
@@ -189,7 +220,13 @@ class FastImage
|
|
189
220
|
:http_header => {}
|
190
221
|
}.merge(options)
|
191
222
|
|
192
|
-
@property = @options[:
|
223
|
+
@property = if @options[:animated_only]
|
224
|
+
:animated
|
225
|
+
elsif @options[:type_only]
|
226
|
+
:type
|
227
|
+
else
|
228
|
+
:size
|
229
|
+
end
|
193
230
|
|
194
231
|
@type, @state = nil
|
195
232
|
|
@@ -217,10 +254,8 @@ class FastImage
|
|
217
254
|
Errno::ENETUNREACH, ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT,
|
218
255
|
OpenSSL::SSL::SSLError
|
219
256
|
raise ImageFetchFailure if @options[:raise_on_failure]
|
220
|
-
rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug
|
221
|
-
raise ImageFetchFailure if @options[:raise_on_failure]
|
222
257
|
rescue UnknownImageType
|
223
|
-
raise
|
258
|
+
raise if @options[:raise_on_failure]
|
224
259
|
rescue CannotParseImage
|
225
260
|
if @options[:raise_on_failure]
|
226
261
|
if @property == :size
|
@@ -248,7 +283,7 @@ class FastImage
|
|
248
283
|
begin
|
249
284
|
URI(location)
|
250
285
|
rescue URI::InvalidURIError
|
251
|
-
URI.escape(location)
|
286
|
+
::URI::DEFAULT_PARSER.escape(location)
|
252
287
|
else
|
253
288
|
location
|
254
289
|
end
|
@@ -262,7 +297,10 @@ class FastImage
|
|
262
297
|
if res.is_a?(Net::HTTPRedirection) && @redirect_count < 4
|
263
298
|
@redirect_count += 1
|
264
299
|
begin
|
265
|
-
|
300
|
+
location = res['Location']
|
301
|
+
raise ImageFetchFailure if location.nil? || location.empty?
|
302
|
+
|
303
|
+
@parsed_uri = URI.join(@parsed_uri, escaped_location(location))
|
266
304
|
rescue URI::InvalidURIError
|
267
305
|
else
|
268
306
|
fetch_using_http_from_parsed_uri
|
@@ -369,7 +407,7 @@ class FastImage
|
|
369
407
|
|
370
408
|
begin
|
371
409
|
result = send("parse_#{@property}")
|
372
|
-
if result
|
410
|
+
if result != nil
|
373
411
|
# extract exif orientation if it was found
|
374
412
|
if @property == :size && result.size == 3
|
375
413
|
@orientation = result.pop
|
@@ -391,9 +429,17 @@ class FastImage
|
|
391
429
|
send("parse_size_for_#{@type}")
|
392
430
|
end
|
393
431
|
|
432
|
+
def parse_animated
|
433
|
+
@type = parse_type unless @type
|
434
|
+
@type == :gif ? send("parse_animated_for_#{@type}") : nil
|
435
|
+
end
|
436
|
+
|
394
437
|
def fetch_using_base64(uri)
|
395
|
-
|
396
|
-
|
438
|
+
decoded = begin
|
439
|
+
Base64.decode64(uri.split(',')[1])
|
440
|
+
rescue
|
441
|
+
raise CannotParseImage
|
442
|
+
end
|
397
443
|
@content_length = decoded.size
|
398
444
|
fetch_using_read StringIO.new(decoded)
|
399
445
|
end
|
@@ -429,19 +475,20 @@ class FastImage
|
|
429
475
|
|
430
476
|
# Peeking beyond the end of the input will raise
|
431
477
|
def peek(n)
|
432
|
-
while @strpos + n
|
478
|
+
while @strpos + n > @str.size
|
433
479
|
unused_str = @str[@strpos..-1]
|
480
|
+
|
434
481
|
new_string = @read_fiber.resume
|
482
|
+
new_string = @read_fiber.resume if new_string.is_a? Net::ReadAdapter
|
435
483
|
raise CannotParseImage if !new_string
|
436
|
-
|
437
484
|
# we are dealing with bytes here, so force the encoding
|
438
|
-
new_string.force_encoding("ASCII-8BIT") if
|
485
|
+
new_string.force_encoding("ASCII-8BIT") if new_string.respond_to? :force_encoding
|
439
486
|
|
440
487
|
@str = unused_str + new_string
|
441
488
|
@strpos = 0
|
442
489
|
end
|
443
490
|
|
444
|
-
@str[@strpos
|
491
|
+
@str[@strpos, n]
|
445
492
|
end
|
446
493
|
|
447
494
|
def read(n)
|
@@ -459,7 +506,7 @@ class FastImage
|
|
459
506
|
new_string = @read_fiber.resume
|
460
507
|
raise CannotParseImage if !new_string
|
461
508
|
|
462
|
-
new_string.force_encoding("ASCII-8BIT") if
|
509
|
+
new_string.force_encoding("ASCII-8BIT") if new_string.respond_to? :force_encoding
|
463
510
|
|
464
511
|
fetched += new_string.size
|
465
512
|
@str = new_string
|
@@ -494,16 +541,26 @@ class FastImage
|
|
494
541
|
when '8B'
|
495
542
|
:psd
|
496
543
|
when "\0\0"
|
497
|
-
# ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
|
498
544
|
case @stream.peek(3).bytes.to_a.last
|
545
|
+
when 0
|
546
|
+
# http://www.ftyps.com/what.html
|
547
|
+
case @stream.peek(12)[4..-1]
|
548
|
+
when "ftypavif"
|
549
|
+
:avif
|
550
|
+
when "ftypheic"
|
551
|
+
:heic
|
552
|
+
when "ftypmif1"
|
553
|
+
:heif
|
554
|
+
end
|
555
|
+
# ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
|
499
556
|
when 1 then :ico
|
500
557
|
when 2 then :cur
|
501
558
|
end
|
502
559
|
when "RI"
|
503
560
|
:webp if @stream.peek(12)[8..11] == "WEBP"
|
504
561
|
when "<s"
|
505
|
-
:svg
|
506
|
-
when
|
562
|
+
:svg if @stream.peek(4) == "<svg"
|
563
|
+
when /\s\s|\s<|<[?!]/, 0xef.chr + 0xbb.chr
|
507
564
|
# Peek 10 more chars each time, and if end of file is reached just raise
|
508
565
|
# unknown. We assume the <svg tag cannot be within 10 chars of the end of
|
509
566
|
# the file, and is within the first 250 chars.
|
@@ -524,8 +581,249 @@ class FastImage
|
|
524
581
|
end
|
525
582
|
alias_method :parse_size_for_cur, :parse_size_for_ico
|
526
583
|
|
584
|
+
# HEIC/AVIF are a special case of the general ISO_BMFF format, in which all data is encapsulated in typed boxes,
|
585
|
+
# with a mandatory ftyp box that is used to indicate particular file types. Is composed of nested "boxes". Each
|
586
|
+
# box has a header composed of
|
587
|
+
# - Size (32 bit integer)
|
588
|
+
# - Box type (4 chars)
|
589
|
+
# - Extended size: only if size === 1, the type field is followed by 64 bit integer of extended size
|
590
|
+
# - Payload: Type-dependent
|
591
|
+
class IsoBmff # :nodoc:
|
592
|
+
def initialize(stream)
|
593
|
+
@stream = stream
|
594
|
+
end
|
595
|
+
|
596
|
+
def width_and_height
|
597
|
+
@rotation = 0
|
598
|
+
@max_size = nil
|
599
|
+
@primary_box = nil
|
600
|
+
@ipma_boxes = []
|
601
|
+
@ispe_boxes = []
|
602
|
+
@final_size = nil
|
603
|
+
|
604
|
+
catch :finish do
|
605
|
+
read_boxes!
|
606
|
+
end
|
607
|
+
|
608
|
+
if [90, 270].include?(@rotation)
|
609
|
+
@final_size.reverse
|
610
|
+
else
|
611
|
+
@final_size
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
private
|
616
|
+
|
617
|
+
# Format specs: https://www.loc.gov/preservation/digital/formats/fdd/fdd000525.shtml
|
618
|
+
|
619
|
+
# If you need to inspect a heic/heif file, use
|
620
|
+
# https://gpac.github.io/mp4box.js/test/filereader.html
|
621
|
+
def read_boxes!(max_read_bytes = nil)
|
622
|
+
end_pos = max_read_bytes.nil? ? nil : @stream.pos + max_read_bytes
|
623
|
+
index = 0
|
624
|
+
|
625
|
+
loop do
|
626
|
+
return if end_pos && @stream.pos >= end_pos
|
627
|
+
|
628
|
+
box_type, box_size = read_box_header!
|
629
|
+
|
630
|
+
case box_type
|
631
|
+
when "meta"
|
632
|
+
handle_meta_box(box_size)
|
633
|
+
when "pitm"
|
634
|
+
handle_pitm_box(box_size)
|
635
|
+
when "ipma"
|
636
|
+
handle_ipma_box(box_size)
|
637
|
+
when "hdlr"
|
638
|
+
handle_hdlr_box(box_size)
|
639
|
+
when "iprp", "ipco"
|
640
|
+
read_boxes!(box_size)
|
641
|
+
when "irot"
|
642
|
+
handle_irot_box
|
643
|
+
when "ispe"
|
644
|
+
handle_ispe_box(box_size, index)
|
645
|
+
when "mdat"
|
646
|
+
throw :finish
|
647
|
+
else
|
648
|
+
@stream.read(box_size)
|
649
|
+
end
|
650
|
+
|
651
|
+
index += 1
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
def handle_irot_box
|
656
|
+
@rotation = (read_uint8! & 0x3) * 90
|
657
|
+
end
|
658
|
+
|
659
|
+
def handle_ispe_box(box_size, index)
|
660
|
+
throw :finish if box_size < 12
|
661
|
+
|
662
|
+
data = @stream.read(box_size)
|
663
|
+
width, height = data[4...12].unpack("N2")
|
664
|
+
@ispe_boxes << { index: index, size: [width, height] }
|
665
|
+
end
|
666
|
+
|
667
|
+
def handle_hdlr_box(box_size)
|
668
|
+
throw :finish if box_size < 12
|
669
|
+
|
670
|
+
data = @stream.read(box_size)
|
671
|
+
throw :finish if data[8...12] != "pict"
|
672
|
+
end
|
673
|
+
|
674
|
+
def handle_ipma_box(box_size)
|
675
|
+
@stream.read(3)
|
676
|
+
flags3 = read_uint8!
|
677
|
+
entries_count = read_uint32!
|
678
|
+
|
679
|
+
entries_count.times do
|
680
|
+
id = read_uint16!
|
681
|
+
essen_count = read_uint8!
|
682
|
+
|
683
|
+
essen_count.times do
|
684
|
+
property_index = read_uint8! & 0x7F
|
685
|
+
|
686
|
+
if flags3 & 1 == 1
|
687
|
+
property_index = (property_index << 7) + read_uint8!
|
688
|
+
end
|
689
|
+
|
690
|
+
@ipma_boxes << { id: id, property_index: property_index - 1 }
|
691
|
+
end
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
def handle_pitm_box(box_size)
|
696
|
+
data = @stream.read(box_size)
|
697
|
+
@primary_box = data[4...6].unpack("S>")[0]
|
698
|
+
end
|
699
|
+
|
700
|
+
def handle_meta_box(box_size)
|
701
|
+
throw :finish if box_size < 4
|
702
|
+
|
703
|
+
@stream.read(4)
|
704
|
+
read_boxes!(box_size - 4)
|
705
|
+
|
706
|
+
throw :finish if !@primary_box
|
707
|
+
|
708
|
+
primary_indices = @ipma_boxes
|
709
|
+
.select { |box| box[:id] == @primary_box }
|
710
|
+
.map { |box| box[:property_index] }
|
711
|
+
|
712
|
+
ispe_box = @ispe_boxes.find do |box|
|
713
|
+
primary_indices.include?(box[:index])
|
714
|
+
end
|
715
|
+
|
716
|
+
if ispe_box
|
717
|
+
@final_size = ispe_box[:size]
|
718
|
+
end
|
719
|
+
|
720
|
+
throw :finish
|
721
|
+
end
|
722
|
+
|
723
|
+
def read_box_header!
|
724
|
+
size = read_uint32!
|
725
|
+
type = @stream.read(4)
|
726
|
+
[type, size - 8]
|
727
|
+
end
|
728
|
+
|
729
|
+
def read_uint8!
|
730
|
+
@stream.read(1).unpack("C")[0]
|
731
|
+
end
|
732
|
+
|
733
|
+
def read_uint16!
|
734
|
+
@stream.read(2).unpack("S>")[0]
|
735
|
+
end
|
736
|
+
|
737
|
+
def read_uint32!
|
738
|
+
@stream.read(4).unpack("N")[0]
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
def parse_size_for_avif
|
743
|
+
bmff = IsoBmff.new(@stream)
|
744
|
+
bmff.width_and_height
|
745
|
+
end
|
746
|
+
|
747
|
+
def parse_size_for_heic
|
748
|
+
bmff = IsoBmff.new(@stream)
|
749
|
+
bmff.width_and_height
|
750
|
+
end
|
751
|
+
|
752
|
+
def parse_size_for_heif
|
753
|
+
bmff = IsoBmff.new(@stream)
|
754
|
+
bmff.width_and_height
|
755
|
+
end
|
756
|
+
|
757
|
+
class Gif # :nodoc:
|
758
|
+
def initialize(stream)
|
759
|
+
@stream = stream
|
760
|
+
end
|
761
|
+
|
762
|
+
def width_and_height
|
763
|
+
@stream.read(11)[6..10].unpack('SS')
|
764
|
+
end
|
765
|
+
|
766
|
+
# Checks if a delay between frames exists and if it does, then the GIFs is
|
767
|
+
# animated
|
768
|
+
def animated?
|
769
|
+
frames = 0
|
770
|
+
|
771
|
+
# "GIF" + version (3) + width (2) + height (2)
|
772
|
+
@stream.skip(10)
|
773
|
+
|
774
|
+
# fields (1) + bg color (1) + pixel ratio (1)
|
775
|
+
fields = @stream.read(3).unpack("CCC")[0]
|
776
|
+
if fields & 0x80 != 0 # Global Color Table
|
777
|
+
# 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
|
778
|
+
@stream.skip(3 * 2 ** ((fields & 0x7) + 1))
|
779
|
+
end
|
780
|
+
|
781
|
+
loop do
|
782
|
+
block_type = @stream.read(1).unpack("C")[0]
|
783
|
+
|
784
|
+
if block_type == 0x21 # Graphic Control Extension
|
785
|
+
# extension type (1) + size (1)
|
786
|
+
size = @stream.read(2).unpack("CC")[1]
|
787
|
+
@stream.skip(size)
|
788
|
+
skip_sub_blocks
|
789
|
+
elsif block_type == 0x2C # Image Descriptor
|
790
|
+
frames += 1
|
791
|
+
return true if frames > 1
|
792
|
+
|
793
|
+
# left position (2) + top position (2) + width (2) + height (2) + fields (1)
|
794
|
+
fields = @stream.read(9).unpack("SSSSC")[4]
|
795
|
+
if fields & 0x80 != 0 # Local Color Table
|
796
|
+
# 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
|
797
|
+
@stream.skip(3 * 2 ** ((fields & 0x7) + 1))
|
798
|
+
end
|
799
|
+
|
800
|
+
@stream.skip(1) # LZW min code size (1)
|
801
|
+
skip_sub_blocks
|
802
|
+
else
|
803
|
+
break # unrecognized block
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
false
|
808
|
+
end
|
809
|
+
|
810
|
+
private
|
811
|
+
|
812
|
+
def skip_sub_blocks
|
813
|
+
loop do
|
814
|
+
size = @stream.read(1).unpack("C")[0]
|
815
|
+
if size == 0
|
816
|
+
break
|
817
|
+
else
|
818
|
+
@stream.skip(size)
|
819
|
+
end
|
820
|
+
end
|
821
|
+
end
|
822
|
+
end
|
823
|
+
|
527
824
|
def parse_size_for_gif
|
528
|
-
@stream
|
825
|
+
gif = Gif.new(@stream)
|
826
|
+
gif.width_and_height
|
529
827
|
end
|
530
828
|
|
531
829
|
def parse_size_for_png
|
@@ -785,4 +1083,9 @@ class FastImage
|
|
785
1083
|
svg = Svg.new(@stream)
|
786
1084
|
svg.width_and_height
|
787
1085
|
end
|
1086
|
+
|
1087
|
+
def parse_animated_for_gif
|
1088
|
+
gif = Gif.new(@stream)
|
1089
|
+
gif.animated?
|
1090
|
+
end
|
788
1091
|
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.6
|
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: 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
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- MIT-LICENSE
|
78
78
|
- README.textile
|
79
79
|
- lib/fastimage.rb
|
80
|
+
- lib/fastimage/version.rb
|
80
81
|
homepage: http://github.com/sdsykes/fastimage
|
81
82
|
licenses:
|
82
83
|
- MIT
|
@@ -97,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
98
|
- !ruby/object:Gem::Version
|
98
99
|
version: '0'
|
99
100
|
requirements: []
|
100
|
-
rubygems_version: 3.
|
101
|
+
rubygems_version: 3.1.6
|
101
102
|
signing_key:
|
102
103
|
specification_version: 4
|
103
104
|
summary: FastImage - Image info fast
|