Class: Btape::GifEncoder

Inherits:
Object
  • Object
show all
Defined in:
lib/btape/gif_encoder.rb,
lib/btape/lzw_compressor.rb

Overview

A deliberately small GIF89a encoder, so that recording needs no native image or video dependency.

Defined Under Namespace

Classes: LzwCompressor

Constant Summary collapse

MAX_DELAY =

A GIF frame delay is two bytes of hundredths of a second.

0xffff
MIN_CODE_SIZE =

Eight bits per pixel: one index into a 256-colour table.

"\x08"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(delay: 10, loop_count: 0, quantizer: :adaptive, scale: 1.0, width: nil, dedupe: true) ⇒ GifEncoder

Returns a new instance of GifEncoder.



26
27
28
29
30
31
32
33
34
# File 'lib/btape/gif_encoder.rb', line 26

def initialize(delay: 10, loop_count: 0, quantizer: :adaptive, scale: 1.0, width: nil, dedupe: true)
  @delay = delay.clamp(1, MAX_DELAY)
  @loop_count = loop_count
  @quantizer = quantizer
  @scale = scale
  @width = width
  @dedupe = dedupe
  @compressor = LzwCompressor.new
end

Class Method Details

.for(settings) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/btape/gif_encoder.rb', line 16

def self.for(settings)
  new(
    delay: (settings.frame_delay * 100).round,
    loop_count: settings.loop_count,
    quantizer: settings.quantizer,
    scale: settings.scale,
    width: settings.output_width
  )
end

Instance Method Details

#encode(frames) ⇒ Object

Returns the GIF as a binary String. Frames are PNG paths or ChunkyPNG canvases. Callers that are not writing to the filesystem — attaching the GIF to a record, say — want this rather than a file to read back.

Raises:



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/btape/gif_encoder.rb', line 39

def encode(frames)
  raise Error, 'no screenshots were captured' if frames.empty?

  images = frames.map { |frame| resize(image(frame)) }
  width, height = images.first.dimension.to_a
  raise Error, 'captured screenshots have different dimensions' unless images.all? do |image|
    image.dimension.to_a == [width, height]
  end

  palette = Palette.build(@quantizer, images)
  gif(collapse(images.map { |image| index(image, palette) }), width, height, palette)
end

#write(frames, output) ⇒ Object

Writes to a path, or to anything that responds to write.



53
54
55
56
57
58
# File 'lib/btape/gif_encoder.rb', line 53

def write(frames, output)
  data = encode(frames)
  return output.write(data) if output.respond_to?(:write)

  File.binwrite(output, data)
end