fastimage 2.2.3 → 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fastimage.rb +163 -2
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4124655c4f8af69e9b8bf9bfa433a11161e9ea97c23e755a196555012eadf75b
4
- data.tar.gz: 40fef6aa908fc14799f2cb53e80d5081bef11ce0482d86c5947841fb29ee9604
3
+ metadata.gz: 074e776db55bfd4766292bca262afc562d4d38d07d86f56f1299a666b4dc3e30
4
+ data.tar.gz: 7e079013cbd7802773119a5a6b7f25377e2878c1afbeb610c68d8a8a069ad0a1
5
5
  SHA512:
6
- metadata.gz: 205fb43dacd3239f8425dd8cbd311be8c375f3c377cbf71771b87304b0c62780905a366783b1b5606e7386edf9ed2fe1cab138b8a20ad47f238150d5143b93db
7
- data.tar.gz: 219ac67b55c23bb59458fc57d165a76c0bf5855c971c705d033103c01848cbb9f3fb4a1e8024419192ced93f076d223fb6e3ce77289b8ed94858d0e58c5387df
6
+ metadata.gz: 4c82693c20723bc22b41e9839104097b0cb435c392e8ddd19edff93aeaa1802f3319c6ad49f1b82ba3926bd1bdcc5e04870d02401ff20e745e61d26a81473c6b
7
+ data.tar.gz: 230fbfd667aab5c59ce7bc53909454d2d9134fdb3c6705173d5df264a3c8a36df2d879c959df1ab4662d5e216a554ada7ba482ba3e0872b9c000d087c91e5b29
data/lib/fastimage.rb CHANGED
@@ -89,6 +89,8 @@ class FastImage
89
89
 
90
90
  LocalFileChunkSize = 256 unless const_defined?(:LocalFileChunkSize)
91
91
 
92
+ SUPPORTED_IMAGE_TYPES = [:bmp, :gif, :jpeg, :png, :tiff, :psd, :heic, :heif, :webp, :svg, :ico, :cur].freeze
93
+
92
94
  # Returns an array containing the width and height of the image.
93
95
  # It will return nil if the image could not be fetched, or if the image type was not recognised.
94
96
  #
@@ -538,8 +540,21 @@ class FastImage
538
540
  when '8B'
539
541
  :psd
540
542
  when "\0\0"
541
- # ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
542
543
  case @stream.peek(3).bytes.to_a.last
544
+ when 0
545
+ # http://www.ftyps.com/what.html
546
+ # HEIC is composed of nested "boxes". Each box has a header composed of
547
+ # - Size (32 bit integer)
548
+ # - Box type (4 chars)
549
+ # - Extended size: only if size === 1, the type field is followed by 64 bit integer of extended size
550
+ # - Payload: Type-dependent
551
+ case @stream.peek(12)[4..-1]
552
+ when "ftypheic"
553
+ :heic
554
+ when "ftypmif1"
555
+ :heif
556
+ end
557
+ # ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
543
558
  when 1 then :ico
544
559
  when 2 then :cur
545
560
  end
@@ -547,7 +562,7 @@ class FastImage
547
562
  :webp if @stream.peek(12)[8..11] == "WEBP"
548
563
  when "<s"
549
564
  :svg if @stream.peek(4) == "<svg"
550
- when /\s\s|\s<|<[?!]/
565
+ when /\s\s|\s<|<[?!]/, 0xef.chr + 0xbb.chr
551
566
  # Peek 10 more chars each time, and if end of file is reached just raise
552
567
  # unknown. We assume the <svg tag cannot be within 10 chars of the end of
553
568
  # the file, and is within the first 250 chars.
@@ -568,6 +583,152 @@ class FastImage
568
583
  end
569
584
  alias_method :parse_size_for_cur, :parse_size_for_ico
570
585
 
586
+ class Heic # :nodoc:
587
+ def initialize(stream)
588
+ @stream = stream
589
+ end
590
+
591
+ def width_and_height
592
+ @max_size = nil
593
+ @primary_box = nil
594
+ @ipma_boxes = []
595
+ @ispe_boxes = []
596
+ @final_size = nil
597
+
598
+ catch :finish do
599
+ read_boxes!
600
+ end
601
+
602
+ @final_size
603
+ end
604
+
605
+ private
606
+
607
+ def read_boxes!(max_read_bytes = nil)
608
+ end_pos = max_read_bytes.nil? ? nil : @stream.pos + max_read_bytes
609
+ index = 0
610
+
611
+ loop do
612
+ return if end_pos && @stream.pos >= end_pos
613
+
614
+ box_type, box_size = read_box_header!
615
+
616
+ case box_type
617
+ when "meta"
618
+ handle_meta_box(box_size)
619
+ when "pitm"
620
+ handle_pitm_box(box_size)
621
+ when "ipma"
622
+ handle_ipma_box(box_size)
623
+ when "hdlr"
624
+ handle_hdlr_box(box_size)
625
+ when "iprp", "ipco"
626
+ read_boxes!(box_size)
627
+ when "ispe"
628
+ handle_ispe_box(box_size, index)
629
+ when "mdat"
630
+ throw :finish
631
+ else
632
+ @stream.read(box_size)
633
+ end
634
+
635
+ index += 1
636
+ end
637
+ end
638
+
639
+ def handle_ispe_box(box_size, index)
640
+ throw :finish if box_size < 12
641
+
642
+ data = @stream.read(box_size)
643
+ width, height = data[4...12].unpack("N2")
644
+ @ispe_boxes << { index: index, size: [width, height] }
645
+ end
646
+
647
+ def handle_hdlr_box(box_size)
648
+ throw :finish if box_size < 12
649
+
650
+ data = @stream.read(box_size)
651
+ throw :finish if data[8...12] != "pict"
652
+ end
653
+
654
+ def handle_ipma_box(box_size)
655
+ @stream.read(3)
656
+ flags3 = read_uint8!
657
+ entries_count = read_uint32!
658
+
659
+ entries_count.times do
660
+ id = read_uint16!
661
+ essen_count = read_uint8!
662
+
663
+ essen_count.times do
664
+ property_index = read_uint8! & 0x7F
665
+
666
+ if flags3 & 1 == 1
667
+ property_index = (property_index << 7) + read_uint8!
668
+ end
669
+
670
+ @ipma_boxes << { id: id, property_index: property_index - 1 }
671
+ end
672
+ end
673
+ end
674
+
675
+ def handle_pitm_box(box_size)
676
+ data = @stream.read(box_size)
677
+ @primary_box = data[4...6].unpack("S>")[0]
678
+ end
679
+
680
+ def handle_meta_box(box_size)
681
+ throw :finish if box_size < 4
682
+
683
+ @stream.read(4)
684
+ read_boxes!(box_size - 4)
685
+
686
+ throw :finish if !@primary_box
687
+
688
+ primary_indices = @ipma_boxes
689
+ .select { |box| box[:id] == @primary_box }
690
+ .map { |box| box[:property_index] }
691
+
692
+ ispe_box = @ispe_boxes.find do |box|
693
+ primary_indices.include?(box[:index])
694
+ end
695
+
696
+ if ispe_box
697
+ @final_size = ispe_box[:size]
698
+ end
699
+
700
+ throw :finish
701
+ end
702
+
703
+ def read_box_header!
704
+ size = read_uint32!
705
+ type = @stream.read(4)
706
+ [type, size - 8]
707
+ end
708
+
709
+ def read_uint8!
710
+ @stream.read(1).unpack("C")[0]
711
+ end
712
+
713
+ def read_uint16!
714
+ @stream.read(2).unpack("S>")[0]
715
+ end
716
+
717
+ def read_uint32!
718
+ @stream.read(4).unpack("N")[0]
719
+ end
720
+ end
721
+
722
+ def parse_size_for_heic
723
+ heic = Heic.new(@stream)
724
+ heic.width_and_height
725
+ end
726
+
727
+ def parse_size_for_heif
728
+ heic = Heic.new(@stream)
729
+ heic.width_and_height
730
+ end
731
+
571
732
  class Gif # :nodoc:
572
733
  def initialize(stream)
573
734
  @stream = stream
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.3
4
+ version: 2.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes
@@ -97,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  requirements: []
100
- rubygems_version: 3.2.3
100
+ rubygems_version: 3.1.6
101
101
  signing_key:
102
102
  specification_version: 4
103
103
  summary: FastImage - Image info fast