Class: BitmapWindow
- Inherits:
-
Object
- Object
- BitmapWindow
- 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")
Defined Under Namespace
Classes: ColourDelegate
Constant Summary collapse
- DEFAULT_FONT =
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"- DEFAULT_EMOJI =
"/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf"
Instance Attribute Summary collapse
-
#height ⇒ Object
readonly
Returns the value of attribute height.
-
#pixels ⇒ Object
readonly
Returns the value of attribute pixels.
-
#width ⇒ Object
readonly
Returns the value of attribute width.
Instance Method Summary collapse
- #char_h ⇒ Object
- #char_w ⇒ Object
- #clear(x, y, w, h) ⇒ Object
- #copy_buffer ⇒ Object
-
#dirty! ⇒ Object
Live-loop hooks: a bitmap has no separate front buffer / event channel.
-
#draw(x, y, str, fg, bg, _lineattrs = nil) ⇒ Object
x,y are pixel coordinates (WindowAdapter has already multiplied by the cell size).
- #draw_line(x, y, w, col) ⇒ Object
- #fillrect(x, y, w, h, col) ⇒ Object
- #flush ⇒ Object
-
#initialize(cols, rows, font: DEFAULT_FONT, size: 16, fg: 0xcccccc, bg: 0x000000, emoji: DEFAULT_EMOJI) ⇒ BitmapWindow
constructor
A new instance of BitmapWindow.
- #map_window ⇒ Object
- #resize(w, h) ⇒ Object
-
#save_png(path) ⇒ Object
# Output.
- #scroll_down(srcy, w, h, step) ⇒ Object
-
#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).
- #scrollback_count ⇒ Object
- #scrollback_mode ⇒ Object
- #set_buffer(_) ⇒ Object
Constructor Details
#initialize(cols, rows, font: DEFAULT_FONT, size: 16, fg: 0xcccccc, bg: 0x000000, emoji: DEFAULT_EMOJI) ⇒ BitmapWindow
Returns a new instance of BitmapWindow.
36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/bitmapwindow.rb', line 36 def initialize(cols, rows, font: DEFAULT_FONT, size: 16, fg: 0xcccccc, bg: 0x000000, emoji: DEFAULT_EMOJI) # The glyph pipeline (rasterise + cache + metrics) lives in skrift's # GlyphCache; colour emoji come from an optional colour delegate. @cache = Skrift::GlyphCache.new(font, x_scale: size, y_scale: size, color: colour_delegate(emoji, size)) @char_w = @cache.cell_width @char_h = @cache.cell_height @baseline = @cache.baseline @cols, @rows = cols, rows @fg, @bg = fg, bg resize(cols * @char_w, rows * @char_h) end |
Instance Attribute Details
#height ⇒ Object (readonly)
Returns the value of attribute height.
24 25 26 |
# File 'lib/bitmapwindow.rb', line 24 def height @height end |
#pixels ⇒ Object (readonly)
Returns the value of attribute pixels.
24 25 26 |
# File 'lib/bitmapwindow.rb', line 24 def pixels @pixels end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
24 25 26 |
# File 'lib/bitmapwindow.rb', line 24 def width @width end |
Instance Method Details
#char_h ⇒ Object
51 |
# File 'lib/bitmapwindow.rb', line 51 def char_h = @char_h |
#char_w ⇒ Object
50 |
# File 'lib/bitmapwindow.rb', line 50 def char_w = @char_w |
#clear(x, y, w, h) ⇒ Object
78 |
# File 'lib/bitmapwindow.rb', line 78 def clear(x, y, w, h) = fillrect(x, y, w, h, @bg) |
#copy_buffer ⇒ Object
63 |
# File 'lib/bitmapwindow.rb', line 63 def copy_buffer = nil |
#dirty! ⇒ Object
Live-loop hooks: a bitmap has no separate front buffer / event channel.
61 |
# File 'lib/bitmapwindow.rb', line 61 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.
84 85 86 87 88 89 90 91 |
# File 'lib/bitmapwindow.rb', line 84 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| cp = ch.ord next if cp == 32 || cp == CharWidth::WIDE_SPACER # space / wide-glyph tail blit_glyph(cp, x + i * @char_w, y, fg) end end |
#draw_line(x, y, w, col) ⇒ Object
79 |
# File 'lib/bitmapwindow.rb', line 79 def draw_line(x, y, w, col) = fillrect(x, y, w, 1, col) |
#fillrect(x, y, w, h, col) ⇒ Object
69 70 71 72 73 74 75 76 |
# File 'lib/bitmapwindow.rb', line 69 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 |
#flush ⇒ Object
62 |
# File 'lib/bitmapwindow.rb', line 62 def flush = nil |
#map_window ⇒ Object
64 |
# File 'lib/bitmapwindow.rb', line 64 def map_window = nil |
#resize(w, h) ⇒ Object
53 54 55 56 |
# File 'lib/bitmapwindow.rb', line 53 def resize(w, h) @width, @height = w, h @pixels = Array.new(@width * @height, @bg) end |
#save_png(path) ⇒ Object
# Output
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/bitmapwindow.rb', line 107 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
100 101 102 103 |
# File 'lib/bitmapwindow.rb', line 100 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).
95 96 97 98 |
# File 'lib/bitmapwindow.rb', line 95 def scroll_up(srcy, w, h, step) move_rows(srcy, srcy - step, h) clear(0, srcy + h - step, @width, step + 1) end |
#scrollback_count ⇒ Object
67 |
# File 'lib/bitmapwindow.rb', line 67 def scrollback_count = 0 |
#scrollback_mode ⇒ Object
66 |
# File 'lib/bitmapwindow.rb', line 66 def scrollback_mode = false |
#set_buffer(_) ⇒ Object
65 |
# File 'lib/bitmapwindow.rb', line 65 def set_buffer(_) = nil |