fastimage 2.2.1 → 2.2.5
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 +1 -1
- data/lib/fastimage.rb +192 -13
- data/lib/fastimage/version.rb +3 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfa3d72608b0c236038f0d4917930580df5474e5b46b61bcbb5758190e0050e3
|
4
|
+
data.tar.gz: 759948e3de376e61a038c6a710b1d15a39d0459c2c20efa7fefbf3692bcc26b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49a8af8f7dbed9c9c2de250a67cd9ff2810c7b0a5a41d79c5069b777331573de9633163cbc3a95b7a5710e695065a6266e37a255cfeb3ed380ddd29076ce34d9
|
7
|
+
data.tar.gz: 4c9136b413828a5ef790befb5b16144fdc277979c5e28b855886888ea513aa7343900269c302feb495639cd5647f0e58dcdb1a67dd812f4d1357c42adaf1ebe5
|
data/README.textile
CHANGED
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"
|
@@ -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
|
#
|
@@ -251,10 +254,8 @@ class FastImage
|
|
251
254
|
Errno::ENETUNREACH, ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT,
|
252
255
|
OpenSSL::SSL::SSLError
|
253
256
|
raise ImageFetchFailure if @options[:raise_on_failure]
|
254
|
-
rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug
|
255
|
-
raise ImageFetchFailure if @options[:raise_on_failure]
|
256
257
|
rescue UnknownImageType
|
257
|
-
raise
|
258
|
+
raise if @options[:raise_on_failure]
|
258
259
|
rescue CannotParseImage
|
259
260
|
if @options[:raise_on_failure]
|
260
261
|
if @property == :size
|
@@ -434,8 +435,11 @@ class FastImage
|
|
434
435
|
end
|
435
436
|
|
436
437
|
def fetch_using_base64(uri)
|
437
|
-
|
438
|
-
|
438
|
+
decoded = begin
|
439
|
+
Base64.decode64(uri.split(',')[1])
|
440
|
+
rescue
|
441
|
+
raise CannotParseImage
|
442
|
+
end
|
439
443
|
@content_length = decoded.size
|
440
444
|
fetch_using_read StringIO.new(decoded)
|
441
445
|
end
|
@@ -471,19 +475,20 @@ class FastImage
|
|
471
475
|
|
472
476
|
# Peeking beyond the end of the input will raise
|
473
477
|
def peek(n)
|
474
|
-
while @strpos + n
|
478
|
+
while @strpos + n > @str.size
|
475
479
|
unused_str = @str[@strpos..-1]
|
480
|
+
|
476
481
|
new_string = @read_fiber.resume
|
482
|
+
new_string = @read_fiber.resume if new_string.is_a? Net::ReadAdapter
|
477
483
|
raise CannotParseImage if !new_string
|
478
|
-
|
479
484
|
# we are dealing with bytes here, so force the encoding
|
480
|
-
new_string.force_encoding("ASCII-8BIT") if
|
485
|
+
new_string.force_encoding("ASCII-8BIT") if new_string.respond_to? :force_encoding
|
481
486
|
|
482
487
|
@str = unused_str + new_string
|
483
488
|
@strpos = 0
|
484
489
|
end
|
485
490
|
|
486
|
-
@str[@strpos
|
491
|
+
@str[@strpos, n]
|
487
492
|
end
|
488
493
|
|
489
494
|
def read(n)
|
@@ -501,7 +506,7 @@ class FastImage
|
|
501
506
|
new_string = @read_fiber.resume
|
502
507
|
raise CannotParseImage if !new_string
|
503
508
|
|
504
|
-
new_string.force_encoding("ASCII-8BIT") if
|
509
|
+
new_string.force_encoding("ASCII-8BIT") if new_string.respond_to? :force_encoding
|
505
510
|
|
506
511
|
fetched += new_string.size
|
507
512
|
@str = new_string
|
@@ -536,8 +541,21 @@ class FastImage
|
|
536
541
|
when '8B'
|
537
542
|
:psd
|
538
543
|
when "\0\0"
|
539
|
-
# ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
|
540
544
|
case @stream.peek(3).bytes.to_a.last
|
545
|
+
when 0
|
546
|
+
# http://www.ftyps.com/what.html
|
547
|
+
# HEIC is composed of nested "boxes". Each box has a header composed of
|
548
|
+
# - Size (32 bit integer)
|
549
|
+
# - Box type (4 chars)
|
550
|
+
# - Extended size: only if size === 1, the type field is followed by 64 bit integer of extended size
|
551
|
+
# - Payload: Type-dependent
|
552
|
+
case @stream.peek(12)[4..-1]
|
553
|
+
when "ftypheic"
|
554
|
+
:heic
|
555
|
+
when "ftypmif1"
|
556
|
+
:heif
|
557
|
+
end
|
558
|
+
# ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
|
541
559
|
when 1 then :ico
|
542
560
|
when 2 then :cur
|
543
561
|
end
|
@@ -545,7 +563,7 @@ class FastImage
|
|
545
563
|
:webp if @stream.peek(12)[8..11] == "WEBP"
|
546
564
|
when "<s"
|
547
565
|
:svg if @stream.peek(4) == "<svg"
|
548
|
-
when
|
566
|
+
when /\s\s|\s<|<[?!]/, 0xef.chr + 0xbb.chr
|
549
567
|
# Peek 10 more chars each time, and if end of file is reached just raise
|
550
568
|
# unknown. We assume the <svg tag cannot be within 10 chars of the end of
|
551
569
|
# the file, and is within the first 250 chars.
|
@@ -566,6 +584,167 @@ class FastImage
|
|
566
584
|
end
|
567
585
|
alias_method :parse_size_for_cur, :parse_size_for_ico
|
568
586
|
|
587
|
+
class Heic # :nodoc:
|
588
|
+
def initialize(stream)
|
589
|
+
@stream = stream
|
590
|
+
end
|
591
|
+
|
592
|
+
def width_and_height
|
593
|
+
@rotation = 0
|
594
|
+
@max_size = nil
|
595
|
+
@primary_box = nil
|
596
|
+
@ipma_boxes = []
|
597
|
+
@ispe_boxes = []
|
598
|
+
@final_size = nil
|
599
|
+
|
600
|
+
catch :finish do
|
601
|
+
read_boxes!
|
602
|
+
end
|
603
|
+
|
604
|
+
if [90, 270].include?(@rotation)
|
605
|
+
@final_size.reverse
|
606
|
+
else
|
607
|
+
@final_size
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
private
|
612
|
+
|
613
|
+
# Format specs: https://www.loc.gov/preservation/digital/formats/fdd/fdd000525.shtml
|
614
|
+
|
615
|
+
# If you need to inspect a heic/heif file, use
|
616
|
+
# https://gpac.github.io/mp4box.js/test/filereader.html
|
617
|
+
def read_boxes!(max_read_bytes = nil)
|
618
|
+
end_pos = max_read_bytes.nil? ? nil : @stream.pos + max_read_bytes
|
619
|
+
index = 0
|
620
|
+
|
621
|
+
loop do
|
622
|
+
return if end_pos && @stream.pos >= end_pos
|
623
|
+
|
624
|
+
box_type, box_size = read_box_header!
|
625
|
+
|
626
|
+
case box_type
|
627
|
+
when "meta"
|
628
|
+
handle_meta_box(box_size)
|
629
|
+
when "pitm"
|
630
|
+
handle_pitm_box(box_size)
|
631
|
+
when "ipma"
|
632
|
+
handle_ipma_box(box_size)
|
633
|
+
when "hdlr"
|
634
|
+
handle_hdlr_box(box_size)
|
635
|
+
when "iprp", "ipco"
|
636
|
+
read_boxes!(box_size)
|
637
|
+
when "irot"
|
638
|
+
handle_irot_box
|
639
|
+
when "ispe"
|
640
|
+
handle_ispe_box(box_size, index)
|
641
|
+
when "mdat"
|
642
|
+
throw :finish
|
643
|
+
else
|
644
|
+
@stream.read(box_size)
|
645
|
+
end
|
646
|
+
|
647
|
+
index += 1
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
def handle_irot_box
|
652
|
+
@rotation = (read_uint8! & 0x3) * 90
|
653
|
+
end
|
654
|
+
|
655
|
+
def handle_ispe_box(box_size, index)
|
656
|
+
throw :finish if box_size < 12
|
657
|
+
|
658
|
+
data = @stream.read(box_size)
|
659
|
+
width, height = data[4...12].unpack("N2")
|
660
|
+
@ispe_boxes << { index: index, size: [width, height] }
|
661
|
+
end
|
662
|
+
|
663
|
+
def handle_hdlr_box(box_size)
|
664
|
+
throw :finish if box_size < 12
|
665
|
+
|
666
|
+
data = @stream.read(box_size)
|
667
|
+
throw :finish if data[8...12] != "pict"
|
668
|
+
end
|
669
|
+
|
670
|
+
def handle_ipma_box(box_size)
|
671
|
+
@stream.read(3)
|
672
|
+
flags3 = read_uint8!
|
673
|
+
entries_count = read_uint32!
|
674
|
+
|
675
|
+
entries_count.times do
|
676
|
+
id = read_uint16!
|
677
|
+
essen_count = read_uint8!
|
678
|
+
|
679
|
+
essen_count.times do
|
680
|
+
property_index = read_uint8! & 0x7F
|
681
|
+
|
682
|
+
if flags3 & 1 == 1
|
683
|
+
property_index = (property_index << 7) + read_uint8!
|
684
|
+
end
|
685
|
+
|
686
|
+
@ipma_boxes << { id: id, property_index: property_index - 1 }
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
def handle_pitm_box(box_size)
|
692
|
+
data = @stream.read(box_size)
|
693
|
+
@primary_box = data[4...6].unpack("S>")[0]
|
694
|
+
end
|
695
|
+
|
696
|
+
def handle_meta_box(box_size)
|
697
|
+
throw :finish if box_size < 4
|
698
|
+
|
699
|
+
@stream.read(4)
|
700
|
+
read_boxes!(box_size - 4)
|
701
|
+
|
702
|
+
throw :finish if !@primary_box
|
703
|
+
|
704
|
+
primary_indices = @ipma_boxes
|
705
|
+
.select { |box| box[:id] == @primary_box }
|
706
|
+
.map { |box| box[:property_index] }
|
707
|
+
|
708
|
+
ispe_box = @ispe_boxes.find do |box|
|
709
|
+
primary_indices.include?(box[:index])
|
710
|
+
end
|
711
|
+
|
712
|
+
if ispe_box
|
713
|
+
@final_size = ispe_box[:size]
|
714
|
+
end
|
715
|
+
|
716
|
+
throw :finish
|
717
|
+
end
|
718
|
+
|
719
|
+
def read_box_header!
|
720
|
+
size = read_uint32!
|
721
|
+
type = @stream.read(4)
|
722
|
+
[type, size - 8]
|
723
|
+
end
|
724
|
+
|
725
|
+
def read_uint8!
|
726
|
+
@stream.read(1).unpack("C")[0]
|
727
|
+
end
|
728
|
+
|
729
|
+
def read_uint16!
|
730
|
+
@stream.read(2).unpack("S>")[0]
|
731
|
+
end
|
732
|
+
|
733
|
+
def read_uint32!
|
734
|
+
@stream.read(4).unpack("N")[0]
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
def parse_size_for_heic
|
739
|
+
heic = Heic.new(@stream)
|
740
|
+
heic.width_and_height
|
741
|
+
end
|
742
|
+
|
743
|
+
def parse_size_for_heif
|
744
|
+
heic = Heic.new(@stream)
|
745
|
+
heic.width_and_height
|
746
|
+
end
|
747
|
+
|
569
748
|
class Gif # :nodoc:
|
570
749
|
def initialize(stream)
|
571
750
|
@stream = stream
|
@@ -585,7 +764,7 @@ class FastImage
|
|
585
764
|
|
586
765
|
# fields (1) + bg color (1) + pixel ratio (1)
|
587
766
|
fields = @stream.read(3).unpack("CCC")[0]
|
588
|
-
if fields & 0x80 # Global Color Table
|
767
|
+
if fields & 0x80 != 0 # Global Color Table
|
589
768
|
# 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
|
590
769
|
@stream.skip(3 * 2 ** ((fields & 0x7) + 1))
|
591
770
|
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.2.
|
4
|
+
version: 2.2.5
|
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
|
@@ -77,11 +77,12 @@ 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
|
83
84
|
metadata: {}
|
84
|
-
post_install_message:
|
85
|
+
post_install_message:
|
85
86
|
rdoc_options:
|
86
87
|
- "--charset=UTF-8"
|
87
88
|
require_paths:
|
@@ -97,8 +98,8 @@ 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
|
-
signing_key:
|
101
|
+
rubygems_version: 3.1.6
|
102
|
+
signing_key:
|
102
103
|
specification_version: 4
|
103
104
|
summary: FastImage - Image info fast
|
104
105
|
test_files: []
|