img2irc/utils/mkbitmap.py

64 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import argparse
import json
from PIL import Image
def main():
p = argparse.ArgumentParser(
description="Slice a row-image of glyphs into bitmaps and output JSON mapping."
)
p.add_argument('chars_file', help='Space-delimited glyphs text file (UTF-8)')
p.add_argument('image_file', help='Image with glyphs in one row, no gaps')
p.add_argument('--icw', type=int, required=True, help='Input char width (px)')
p.add_argument('--ich', type=int, required=True, help='Input char height (px)')
p.add_argument('--threshold', type=int, required=True, help='B/W threshold (0255)')
p.add_argument('--obw', type=int, required=True, help='Output bitmap width')
p.add_argument('--obh', type=int, required=True, help='Output bitmap height')
p.add_argument('--output', required=True, help='Output JSON filename')
args = p.parse_args()
# 1) Read glyphs
with open(args.chars_file, 'r', encoding='utf-8') as f:
glyphs = f.read().strip().split(' ')
# 2) Load image & sanity-check
im = Image.open(args.image_file).convert('L')
w, h = im.size
if h != args.ich:
raise ValueError(f"Image height {h} ≠ ich {args.ich}")
count = w // args.icw
if count * args.icw != w:
raise ValueError(f"Image width {w} not a multiple of icw {args.icw}")
if len(glyphs) != count:
raise ValueError(f"{len(glyphs)} glyphs but {count} blocks in image")
# 3) Build mapping glyph → grid
mapping = {}
for i, glyph in enumerate(glyphs):
left = i * args.icw
block = im.crop((left, 0, left + args.icw, args.ich))
block = block.resize((args.obw, args.obh), Image.LANCZOS)
data = list(block.getdata())
bits = [1 if pix > args.threshold else 0 for pix in data]
grid = [bits[row*args.obw:(row+1)*args.obw] for row in range(args.obh)]
mapping[glyph] = grid
# 4) Write JSON manually so rows stay inline
with open(args.output, 'w', encoding='utf-8') as out:
out.write('{\n')
total = len(mapping)
for idx, (glyph, grid) in enumerate(mapping.items()):
# properly quote the glyph
key = json.dumps(glyph, ensure_ascii=False)
out.write(f' {key}: [\n')
for ridx, row in enumerate(grid):
row_str = ','.join(str(bit) for bit in row)
comma = ',' if ridx < len(grid) - 1 else ''
out.write(f' [{row_str}]{comma}\n')
out.write(' ]')
out.write(',\n' if idx < total - 1 else '\n')
out.write('}\n')
if __name__ == '__main__':
main()