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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72e83c6f6d442c29071e060cca8a8b0a0a17024a7871cd19a64b83f77e0c0ced
4
- data.tar.gz: 56d0f5f86e11f1a8922cdf5bbe292fef2753f5637df402fd7532ef21d8393537
3
+ metadata.gz: cfa3d72608b0c236038f0d4917930580df5474e5b46b61bcbb5758190e0050e3
4
+ data.tar.gz: 759948e3de376e61a038c6a710b1d15a39d0459c2c20efa7fefbf3692bcc26b7
5
5
  SHA512:
6
- metadata.gz: 002eb40a04b2ce79f8cdc34ee2fdc0d70fe35ff964d380096302682756a17e4b22f8275e335822f5229080aada2ca8d5d17603607cb0cf6479b61ac6d4dd64ef
7
- data.tar.gz: 17c8efefdc90fae00178d045bb0670e2914f9f19eabdb0be983c49ffb573b752672f02678e38b1395129d7f55ffc42905fa1cbeb9017445ffa295db6cc4fe119
6
+ metadata.gz: 49a8af8f7dbed9c9c2de250a67cd9ff2810c7b0a5a41d79c5069b777331573de9633163cbc3a95b7a5710e695065a6266e37a255cfeb3ed380ddd29076ce34d9
7
+ data.tar.gz: 4c9136b413828a5ef790befb5b16144fdc277979c5e28b855886888ea513aa7343900269c302feb495639cd5647f0e58dcdb1a67dd812f4d1357c42adaf1ebe5
data/README.textile CHANGED
@@ -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:
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 UnknownImageType if @options[:raise_on_failure]
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
- data = uri.split(',')[1]
438
- decoded = Base64.decode64(data)
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 - 1 >= @str.size
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 String.method_defined? :force_encoding
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..(@strpos + n - 1)]
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 String.method_defined? :force_encoding
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
@@ -0,0 +1,3 @@
1
+ class FastImage
2
+ VERSION = "2.2.5"
3
+ 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.1
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: 2020-07-23 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
@@ -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.0.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: []