fenrir/play-zone/vcsa.py

93 lines
2.1 KiB
Python
Raw Normal View History

2016-11-07 18:07:08 -05:00
#!/usr/bin/python
from cairo import *
from fcntl import ioctl
from array import array
import struct
import errno
import sys
GIO_UNIMAP = 0x4B66
VT_GETHIFONTMASK = 0x560D
if len(sys.argv) != 3:
print "Usage: %s <tty-number> <output-png>" % sys.argv[0]
exit()
ttyno = int(sys.argv[1])
png = sys.argv[2]
tty = open('/dev/tty%d' % ttyno, 'rb')
himask = array("H", (0,))
ioctl(tty, VT_GETHIFONTMASK, himask)
hichar, = struct.unpack_from("@H", himask)
sz = 512
while True:
try:
unipairs = array("H", [0]*(2*sz))
unimapdesc = array("B", struct.pack("@HP", sz, unipairs.buffer_info()[0]))
ioctl(tty.fileno(), GIO_UNIMAP, unimapdesc)
break
except IOError as e:
if e.errno != errno.ENOMEM:
raise
sz *= 2
tty.close()
ncodes, = struct.unpack_from("@H", unimapdesc)
utable = struct.unpack_from("@%dH" % (2*ncodes), unipairs)
charmap = {}
for u, b in zip(utable[::2], utable[1::2]):
if charmap.get(b) is None:
charmap[b] = unichr(u)
vcs = open('/dev/vcsa%d' % ttyno, 'rb')
head = vcs.read(4)
rows = ord(head[0])
cols = ord(head[1])
caretX = ord(head[2])
caretY = ord(head[3])
surf = ImageSurface(FORMAT_RGB24, cols * 8, rows * 16)
cr = Context(surf)
cr.set_source_rgb(1,1,1)
cr.set_font_face(ToyFontFace("Mono", FONT_SLANT_NORMAL, FONT_WEIGHT_NORMAL));
m = Matrix()
m.scale(10.0, 12.0)
cr.set_font_matrix(m)
def CairoColor(b, a):
return (b if a & 4 else 0, b if a & 2 else 0, b if a & 1 else 0)
for y in range(rows):
for x in range(cols):
data = vcs.read(2)
(sh,) = struct.unpack("=H", data)
attr = (sh >> 8) & 0xFF
ch = sh & 0xFF
if hichar == 0x100:
attr >>= 1
ink = attr & 0x0F
paper = (attr>>4) & 0x0F
b = 1.0 if attr & 0x80 else 0.75
if sh & hichar:
ch |= 0x100
cr.set_source_rgb(*CairoColor(b, paper))
cr.rectangle(x*8, y*16, 8, 16)
cr.fill()
cr.set_source_rgb(*CairoColor(b, ink))
cr.move_to(x*8, 12 + y*16)
cr.show_text(charmap.get(ch, u'?'))
cr.stroke()
vcs.close()
surf.write_to_png(png)