Class: Flipbook::GIF::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/flipbook/gif/reader.rb,
sig/flipbook.rbs

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bytes, max_pixels: 16_384 * 16_384, max_frames: 10_000, max_total_pixels: 100_000_000) ⇒ Reader

Returns a new instance of Reader.

Raises:

  • (ArgumentError)


10
11
12
13
14
15
16
17
# File 'lib/flipbook/gif/reader.rb', line 10

def initialize(bytes, max_pixels: 16_384 * 16_384, max_frames: 10_000, max_total_pixels: 100_000_000)
  @bytes = String(bytes).b
  @offset = 0
  @max_pixels = Integer(max_pixels)
  @max_frames = Integer(max_frames)
  @max_total_pixels = Integer(max_total_pixels)
  raise ArgumentError, "limits must be positive" unless @max_pixels.positive? && @max_frames.positive? && @max_total_pixels.positive?
end

Class Method Details

.read(path, max_pixels: 16_384 * 16_384, max_frames: 10_000, max_total_pixels: 100_000_000) ⇒ Array[Tessel::Image]

Parameters:

  • path (String)
  • max_pixels: (Integer) (defaults to: 16_384 * 16_384)
  • max_frames: (Integer) (defaults to: 10_000)
  • max_total_pixels: (Integer) (defaults to: 100_000_000)

Returns:



6
7
8
# File 'lib/flipbook/gif/reader.rb', line 6

def self.read(path, max_pixels: 16_384 * 16_384, max_frames: 10_000, max_total_pixels: 100_000_000)
  new(File.binread(path), max_pixels:, max_frames:, max_total_pixels:).read
end

Instance Method Details

#read ⇒ Array[Tessel::Image]

Returns:

Raises:



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/flipbook/gif/reader.rb', line 19

def read
  signature = take(6)
  raise Error, "invalid GIF signature" unless %w[GIF87a GIF89a].include?(signature)

  @width, @height, packed, background_index, = take(7).unpack("v2C3")
  raise Error, "invalid GIF dimensions" if @width.zero? || @height.zero? || @width * @height > @max_pixels

  @global_palette = read_palette(1 << ((packed & 7) + 1)) if (packed & 0x80).positive?
  @background_index = background_index
  @background = palette_color(@global_palette, background_index)
  @frames = []
  @canvas = Tessel::Image.new(@width, @height, fill: @background)
  @control = default_control
  @previous_disposal = nil
  @finished = false

  until @finished
    marker = byte
    case marker
    when 0x21 then read_extension
    when 0x2c then read_image
    when 0x3b then @finished = true
    else raise Error, "invalid GIF block marker 0x#{marker.to_s(16)}"
    end
  end
  raise Error, "GIF contains no frames" if @frames.empty?

  @frames
end