initial public commit master
authorgit <redacted>
Tue, 17 Feb 2026 17:38:43 +0000 (12:38 -0500)
committergit <redacted>
Tue, 17 Feb 2026 17:38:43 +0000 (12:38 -0500)
README.md [new file with mode: 0644]
font.png [new file with mode: 0644]
fontgen.py [new file with mode: 0644]
requirements.txt [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..cd6ff36
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+This script produces a ROM image that can be used to turn any parallel ROM into a character generator for 6845-style CRTCs and similar video output systems.
+
+It works by going over one character cell at a time, starting at the top left corner of an image and processing through each row (if there are multiple), turning every pixel with a value of `#000` (black) into a `1` (every other value is a `0`).
+
+An example font is provided.
diff --git a/font.png b/font.png
new file mode 100644 (file)
index 0000000..7019ef7
Binary files /dev/null and b/font.png differ
diff --git a/fontgen.py b/fontgen.py
new file mode 100644 (file)
index 0000000..740ae1d
--- /dev/null
@@ -0,0 +1,66 @@
+from bitarray import bitarray
+from PIL import Image
+import numpy as np
+import os, sys, glob
+
+os.chdir(sys.path[0]) # look for png files in the script directory
+
+pxs = int(input('Character width (in pxs): '))
+lns = int(input('Character height (in pxs): '))
+romwrd = int(input('Parallel ROM Word size (in bits): '))
+romcpt = int(input('ROM size (in KWords): '))
+
+actualromsz = romwrd * romcpt * 1024
+
+if romwrd < pxs:
+    raise ValueError("Character width should be less than or equal to the ROM word size")
+
+png = sorted(glob.glob("*.png"))
+if len(png) == 0:
+    raise ValueError("No PNG files found in the current directory.")
+
+print('\nFound images:')
+for i, filename in enumerate(png, 1):
+    print(f'{i}. {filename}')
+
+while 1:
+    try:
+        selection = int(input('\nSelect image by number: '))
+        if 1 <= selection <= len(png):
+            selected = png[selection - 1]
+            print(f'Selected: {selected}')
+            break
+        else:
+            print(f'Please enter a number between 1 and {len(png)}.')
+    except ValueError:
+        print('Invalid input. Please enter a number.')
+
+im = Image.open(png[0]).convert('RGB')
+if im.size[0] % pxs != 0 or im.size[1] % lns != 0:
+    raise ValueError("Image resolution should be in multiples of character width and height specified.")
+
+imgarr = np.array(im)
+
+outarr = bitarray()
+paddbits = romwrd - pxs if pxs < romwrd else 0
+
+for y in range(im.size[1] // lns):
+    for x in range(im.size[0] // pxs):
+        for y1 in range(lns):
+            if paddbits > 0:
+                outarr.extend([0] * paddbits)
+            
+            ystart = y1 + lns * y
+            xstart = pxs * x
+            char_block = imgarr[ystart, xstart:xstart + pxs]
+            
+            isblack = np.all(char_block == 0, axis=1)
+            outarr.extend(isblack.astype(int).tolist())
+
+if outarr[actualromsz:].count(1) > 0:
+    print("Couldn't fit all the data: insufficient ROM size.")
+
+with open("a.out", "wb") as f:
+    outarr[0:actualromsz].tofile(f)
+
+print('\nDone!')
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..1682c30
--- /dev/null
@@ -0,0 +1,3 @@
+numpy\r
+pillow\r
+bitarray\r