mirror of
https://github.com/ssb22/bits-and-bobs.git
synced 2023-06-08 10:22:44 +00:00
89 lines
3.1 KiB
Python
Executable File
89 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# (should work in either Python 2 or Python 3)
|
|
|
|
# Convert ASCII Portable Bitmap (.pbm) files to BBC Micro VDU 23 sequences
|
|
# Silas S. Brown - Version 1.2 - public domain - no warranty
|
|
|
|
# Where to find history:
|
|
# on GitHub at https://github.com/ssb22/bits-and-bobs
|
|
# and on GitLab at https://gitlab.com/ssb22/bits-and-bobs
|
|
# and on BitBucket https://bitbucket.org/ssb22/bits-and-bobs
|
|
# and at https://gitlab.developers.cam.ac.uk/ssb22/bits-and-bobs
|
|
# and in China: https://gitee.com/ssb22/bits-and-bobs
|
|
|
|
screenWidth = 40 # text columns (e.g. Mode 4)
|
|
# (If using 20 or 80, might want to account for non-square pixels)
|
|
|
|
mode = "raw" # "basic" for VDU commands to paste into AUTO; "raw" to send bytes over link
|
|
|
|
import sys
|
|
if len(sys.argv)>1: pbmDat=open(sys.argv[1])
|
|
else:
|
|
sys.stderr.write("pbmtobbc: reading from standard input\n")
|
|
pbmDat=sys.stdin
|
|
if hasattr(pbmDat,"buffer"): _,pbmDat = pbmDat,pbmDat.buffer # Python 3
|
|
pbmDat = pbmDat.read()
|
|
|
|
newline = u"\n".encode('utf-8') # Python 2 or Python 3
|
|
def pullLine():
|
|
global pbmDat
|
|
ret,pbmDat = pbmDat[:pbmDat.index(newline)],pbmDat[pbmDat.index(newline)+1:]
|
|
return ret
|
|
|
|
def B(s):
|
|
"""string to byte-string in
|
|
Python 2 (including old versions that don't support b"")
|
|
and Python 3"""
|
|
if type(s)==type(u""): return s.encode('utf-8') # Python 3
|
|
return s
|
|
def C(c):
|
|
"chr(c) to byte-string in Python 2 or Python 3"
|
|
c = chr(c)
|
|
if type(c)==type(u""): return c.encode('latin1') # Python 3
|
|
else: return c # Python 2
|
|
def O(c): # ord(c) in Python2/3
|
|
if type(c)==str: return ord(c)
|
|
else: return c
|
|
|
|
assert pullLine()==B("P1")
|
|
l = B("#")
|
|
while l.startswith(B("#")): l = pullLine()
|
|
width,height = l.split()
|
|
width,height = int(width),int(height)
|
|
pbmDat = pbmDat.replace(newline,B("")).replace(B("0"),B("w")).replace(B("1"),B("0")).replace(B("w"),B("1")) # collapse and invert
|
|
rows = []
|
|
while pbmDat:
|
|
rows.append(pbmDat[:width])
|
|
pbmDat = pbmDat[width:]
|
|
assert len(rows)==height
|
|
defs = [None]*32 ; nextDef = 0
|
|
for yStart in range(0,height,8):
|
|
out = []
|
|
for x in range(0,min(width,screenWidth*8),8):
|
|
charDef = []
|
|
for y in range(yStart,yStart+8):
|
|
if y < height: charDef.append(int((rows[y][x:x+8]+B("000000"))[:8],2))
|
|
else: charDef.append(0)
|
|
if not any(charDef): # all 0 bits: just add a space
|
|
out.append(B(' ')) ; continue
|
|
charDef = B("").join(C(x) for x in charDef)
|
|
if not charDef in defs:
|
|
out.append(C(23)+C(nextDef+224)+charDef)
|
|
defs[nextDef] = charDef
|
|
nextDef += 1
|
|
if nextDef>=len(defs): nextDef = 0
|
|
out.append(C(224+defs.index(charDef)))
|
|
out = B('').join(out)
|
|
if not out.replace(B(' '),B('')): out = newline
|
|
elif len(out)<screenWidth or out[-2:]==B(' '):
|
|
out = out.rstrip()+B('\r\n')
|
|
# else exact fit for screenWidth
|
|
if mode=="basic":
|
|
o = []
|
|
while out:
|
|
o.append(B("V."+",".join(str(O(c)) for c in out[:59])+"\n"))
|
|
out = out[59:]
|
|
out = B("").join(o)
|
|
if hasattr(sys.stdout,"buffer"): sys.stdout.buffer.write(out) # Python 3
|
|
else: sys.stdout.write(out) # Python 2
|