#!/usr/bin/env python # bs2conv.py - compiles BML and BLM files into a BS2.BIN file as used by # Blinkenstroem Advanced # (see http://wiki.blinkenarea.org/bin/view/Blinkenarea/BlinkstroemAdvanced ) # # Usage: # python bs2conv.py [filenames] # # (C) 2005 Simon Budig , placed in the public domain. import sys, re, xml.sax # tweak this to adjust the overall speed of the movies. blinkstroem_factor = 1.0 / 20 # The Handler for the XML/Sax parser needed for the BML movies. class BMLHandler (xml.sax.handler.ContentHandler): def __init__ (self, filename, outfile): self.tagnesting = [] self.filename = filename self.outfile = outfile self.bits = None self.width = None self.height = None self.duration = 100 self.rowdata = "" # these functions do some dispatching for the different tags # via introspection. def startElement (self, name, attrs): self.tagnesting.append (name) handler = BMLHandler.__dict__.get ("handle_start_" + name, None) if handler: handler (self, attrs) def characters (self, chars): handler = BMLHandler.__dict__.get ("handle_chars_" + self.tagnesting[-1]) if handler: handler (self, chars) def endElement (self, name): self.tagnesting.pop () handler = BMLHandler.__dict__.get ("handle_end_" + name, None) if handler: handler (self) # actual handlers. Must have the name "handle_start_" def handle_start_blm (self, attrs): print >>sys.stderr, filename + ": BML, %(width)sx%(height)s, %(bits)s bits" % attrs self.bits = int (attrs.get ("bits", 4)) self.width = int (attrs.get ("width", 18)) self.height = int (attrs.get ("height", 8)) self.num_chars = (self.bits + 3) / 4 self.regex = re.compile ("[0-9A-Fa-f]{%d}" % self.num_chars) def handle_start_frame (self, attrs): self.duration = int (attrs.get ("duration", 100)) self.frame = [] def handle_end_frame (self): assert len (self.frame) == self.width * self.height # We have row major pixels, need to transpose them to column major. transp_pixels = [] for i in range (self.width): transp_pixels += (self.frame [i::self.width]) # convert to 3 bit output if self.bits > 3: transp_pixels = [ i >> (self.bits - 3) for i in transp_pixels ] elif self.bits < 3: transp_pixels = [ i << (3 - self.bits) for i in transp_pixels ] ticks = int (round (self.duration * blinkstroem_factor)) text = chr (ticks % 256) + chr (ticks / 256) text += "".join ([chr (i) for i in transp_pixels ]) self.outfile.write (text) # The Sax parser might serve multiple CDATA parts for a single row def handle_start_row (self, attrs): self.rowdata = "" def handle_chars_row (self, chars): self.rowdata += chars def handle_end_row (self): pixels = [int (i, 16) for i in self.regex.findall (self.rowdata)] assert len (pixels) == self.width self.frame += pixels # The function for parsing BLM files. def parse_BLM_file (filename, outfile, width = 18, height = 8): print >>sys.stderr, filename + ": BLM, assuming %dx%d, 1 bit" % (width, height) f = file (filename) duration = 100 frame = [] line = f.readline () while line: line = line.strip () if line: if line[0] == "@": duration = int (line[1:]) frame = [] elif line[0] == "#": line = f.readline () continue else: row = [[0, 7][int(i)] for i in list (line) if i in ['0', '1']] assert len (row) == width frame += row if len (frame) == width * height: # We have row major pixels, need to transpose them to column major. transp_pixels = [] for i in range (width): transp_pixels += (frame [i::width]) ticks = int (round (duration * blinkstroem_factor)) text = chr (ticks % 256) + chr (ticks / 256) text += "".join ([chr (i) for i in transp_pixels ]) outfile.write (text) line = f.readline () # Main routine when invoked from the commandline if __name__=='__main__': if len (sys.argv) == 1: print >>sys.stderr, """Usage: %s [filenames]\n Compiles the BLM and BML files given on the commandline into the "BS2.BIN" File, as used by the BlinkenStroem Advanced""" % sys.argv[0] sys.exit (0) outfile = file ("BS2.BIN", "w") for filename in sys.argv[1:]: if filename[-4:].lower() == ".bml": pars = xml.sax.make_parser () pars.setContentHandler (BMLHandler (filename, outfile)) pars.parse (file (filename)) elif filename[-4:].lower() == ".blm": parse_BLM_file (filename, outfile) else: print >>sys.stderr, filename + ": Unknown file type, ignoring..."