Class: BitmapWindow

Inherits:
Object
  • Object
show all
Defined in:
lib/bitmapwindow.rb

Overview

A third implementation of the drawing interface WindowAdapter targets (alongside the X11 Window and the harness’s VirtualWindow): it rasterises real glyphs with skrift and composites them into an in-memory RGB buffer. Wrapped by WindowAdapter it is a full “bitmap backend” - the same Term core, rendered to a pixel buffer with no X server - useful for headless visual testing and for embedding the terminal anywhere a bitmap can go.

win = BitmapWindow.new(80, 24)
adapter = WindowAdapter.new(win, host)   # host: term_width/blink_state...
... feed the terminal ...
win.save_png("screen.png")

Constant Summary collapse

DEFAULT_FONT =
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cols, rows, font: DEFAULT_FONT, size: 16, fg: 0xcccccc, bg: 0x000000) ⇒ BitmapWindow

Returns a new instance of BitmapWindow.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/bitmapwindow.rb', line 20

def initialize(cols, rows, font: DEFAULT_FONT, size: 16,
               fg: 0xcccccc, bg: 0x000000)
  @font = Font.load(font)
  @sft = SFT.new(@font)
  @sft.x_scale = size
  @sft.y_scale = size
  lm = @sft.lmetrics
  @char_h   = (lm.ascender - lm.descender + lm.line_gap).ceil
  @baseline = lm.ascender.round
  @char_w   = @sft.gmetrics(@sft.lookup("M".ord)).advance_width.round
  @cols, @rows = cols, rows
  @fg, @bg = fg, bg
  @glyphs = {}
  resize(cols * @char_w, rows * @char_h)
end

Instance Attribute Details

#heightObject (readonly)

Returns the value of attribute height.



16
17
18
# File 'lib/bitmapwindow.rb', line 16

def height
  @height
end

#pixelsObject (readonly)

Returns the value of attribute pixels.



16
17
18
# File 'lib/bitmapwindow.rb', line 16

def pixels
  @pixels
end

#widthObject (readonly)

Returns the value of attribute width.



16
17
18
# File 'lib/bitmapwindow.rb', line 16

def width
  @width
end

Instance Method Details

#char_hObject



37
# File 'lib/bitmapwindow.rb', line 37

def char_h = @char_h

#char_wObject



36
# File 'lib/bitmapwindow.rb', line 36

def char_w = @char_w

#clear(x, y, w, h) ⇒ Object



64
# File 'lib/bitmapwindow.rb', line 64

def clear(x, y, w, h)  = fillrect(x, y, w, h, @bg)

#copy_bufferObject



49
# File 'lib/bitmapwindow.rb', line 49

def copy_buffer   = nil

#dirty!Object

Live-loop hooks: a bitmap has no separate front buffer / event channel.



47
# File 'lib/bitmapwindow.rb', line 47

def dirty!        = nil

#draw(x, y, str, fg, bg, _lineattrs = nil) ⇒ Object

x,y are pixel coordinates (WindowAdapter has already multiplied by the cell size). lineattrs (double width/height) is rendered as normal width for now - it does not affect correctness of the text, only its scale.



70
71
72
73
74
75
76
# File 'lib/bitmapwindow.rb', line 70

def draw(x, y, str, fg, bg, _lineattrs = nil)
  fillrect(x, y, str.length * @char_w, @char_h, bg)
  str.each_char.with_index do |ch, i|
    next if ch == " "
    blit_glyph(ch.ord, x + i * @char_w, y, fg)
  end
end

#draw_line(x, y, w, col) ⇒ Object



65
# File 'lib/bitmapwindow.rb', line 65

def draw_line(x, y, w, col) = fillrect(x, y, w, 1, col)

#fillrect(x, y, w, h, col) ⇒ Object



55
56
57
58
59
60
61
62
# File 'lib/bitmapwindow.rb', line 55

def fillrect(x, y, w, h, col)
  x0 = x.clamp(0, @width); x1 = (x + w).clamp(0, @width)
  y0 = y.clamp(0, @height); y1 = (y + h).clamp(0, @height)
  (y0...y1).each do |py|
    base = py * @width
    (x0...x1).each { |px| @pixels[base + px] = col }
  end
end

#flushObject



48
# File 'lib/bitmapwindow.rb', line 48

def flush         = nil

#map_windowObject



50
# File 'lib/bitmapwindow.rb', line 50

def map_window    = nil

#resize(w, h) ⇒ Object



39
40
41
42
# File 'lib/bitmapwindow.rb', line 39

def resize(w, h)
  @width, @height = w, h
  @pixels = Array.new(@width * @height, @bg)
end

#save_png(path) ⇒ Object

# Output



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/bitmapwindow.rb', line 92

def save_png(path)
  raw = +"".b
  @height.times do |y|
    raw << "\0"               # filter: none
    base = y * @width
    @width.times do |x|
      p = @pixels[base + x]
      raw << ((p >> 16) & 0xff).chr << ((p >> 8) & 0xff).chr << (p & 0xff).chr
    end
  end
  png = +"\x89PNG\r\n\x1a\n".b
  png << png_chunk("IHDR", [@width, @height, 8, 2, 0, 0, 0].pack("NNC5"))
  png << png_chunk("IDAT", Zlib::Deflate.deflate(raw))
  png << png_chunk("IEND", "")
  File.binwrite(path, png)
  path
end

#scroll_down(srcy, w, h, step) ⇒ Object



85
86
87
88
# File 'lib/bitmapwindow.rb', line 85

def scroll_down(srcy, w, h, step)
  move_rows(srcy, srcy + step, h)
  clear(0, srcy, @width, step)
end

#scroll_up(srcy, w, h, step) ⇒ Object

Mirror Window#scroll_up / #scroll_down: move a block of pixel rows and clear the vacated strip (geometry comes from WindowAdapter).



80
81
82
83
# File 'lib/bitmapwindow.rb', line 80

def scroll_up(srcy, w, h, step)
  move_rows(srcy, srcy - step, h)
  clear(0, srcy + h - step, @width, step + 1)
end

#scrollback_countObject



53
# File 'lib/bitmapwindow.rb', line 53

def scrollback_count = 0

#scrollback_modeObject



52
# File 'lib/bitmapwindow.rb', line 52

def scrollback_mode  = false

#set_buffer(_) ⇒ Object



51
# File 'lib/bitmapwindow.rb', line 51

def set_buffer(_) = nil