Created
August 1, 2025 02:09
-
-
Save scruss/b064a667cebecf31e4896f92659505e1 to your computer and use it in GitHub Desktop.
img2blocks - bitmap to Unicode sextants
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
import sys | |
from PIL import Image | |
import PIL.ImageOps | |
import numpy as np | |
# give usage and exit if no arguments | |
if len(sys.argv) == 1: | |
print("Usage:", sys.argv[0], "image") | |
exit(1) | |
# encodes all 64 states in a lookup string | |
# "ย ๐ฌ๐ฌ๐ฌญ๐ฌ๐ฌฆ๐ฌ๐ฌต๐ฌ๐ฌข๐ฌ๐ฌฑ๐ฌ๐ฌฉ๐ฌ๐ฌน๐ฌ๐ฌ ๐ฌ๐ฌฏ๐ฌโ๐ฌ๐ฌท๐ฌ ๐ฌค๐ฌ๐ฌณ๐ฌ๐ฌซ๐ฌ๐ฌป๐ฌ๐ฌ๐ฌ๐ฌฎ๐ฌ๐ฌง๐ฌ๐ฌถ๐ฌ๐ฌฃโ๐ฌฒ๐ฌ๐ฌช๐ฌ๐ฌบ๐ฌ๐ฌก๐ฌ๐ฌฐ๐ฌ๐ฌจ๐ฌ๐ฌธ๐ฌ๐ฌฅ๐ฌ๐ฌด๐ฌ๐ฌฌ๐ฌโ" | |
lookup = ( | |
"\N{NO-BREAK SPACE}" | |
"\N{BLOCK SEXTANT-6}" | |
"\N{BLOCK SEXTANT-5}" | |
"\N{BLOCK SEXTANT-56}" | |
"\N{BLOCK SEXTANT-4}" | |
"\N{BLOCK SEXTANT-46}" | |
"\N{BLOCK SEXTANT-45}" | |
"\N{BLOCK SEXTANT-456}" | |
"\N{BLOCK SEXTANT-3}" | |
"\N{BLOCK SEXTANT-36}" | |
"\N{BLOCK SEXTANT-35}" | |
"\N{BLOCK SEXTANT-356}" | |
"\N{BLOCK SEXTANT-34}" | |
"\N{BLOCK SEXTANT-346}" | |
"\N{BLOCK SEXTANT-345}" | |
"\N{BLOCK SEXTANT-3456}" | |
"\N{BLOCK SEXTANT-2}" | |
"\N{BLOCK SEXTANT-26}" | |
"\N{BLOCK SEXTANT-25}" | |
"\N{BLOCK SEXTANT-256}" | |
"\N{BLOCK SEXTANT-24}" | |
"\N{RIGHT HALF BLOCK}" | |
"\N{BLOCK SEXTANT-245}" | |
"\N{BLOCK SEXTANT-2456}" | |
"\N{BLOCK SEXTANT-23}" | |
"\N{BLOCK SEXTANT-236}" | |
"\N{BLOCK SEXTANT-235}" | |
"\N{BLOCK SEXTANT-2356}" | |
"\N{BLOCK SEXTANT-234}" | |
"\N{BLOCK SEXTANT-2346}" | |
"\N{BLOCK SEXTANT-2345}" | |
"\N{BLOCK SEXTANT-23456}" | |
"\N{BLOCK SEXTANT-1}" | |
"\N{BLOCK SEXTANT-16}" | |
"\N{BLOCK SEXTANT-15}" | |
"\N{BLOCK SEXTANT-156}" | |
"\N{BLOCK SEXTANT-14}" | |
"\N{BLOCK SEXTANT-146}" | |
"\N{BLOCK SEXTANT-145}" | |
"\N{BLOCK SEXTANT-1456}" | |
"\N{BLOCK SEXTANT-13}" | |
"\N{BLOCK SEXTANT-136}" # moved up past LEFT HALF BLOCK | |
"\N{LEFT HALF BLOCK}" | |
"\N{BLOCK SEXTANT-1356}" | |
"\N{BLOCK SEXTANT-134}" | |
"\N{BLOCK SEXTANT-1346}" | |
"\N{BLOCK SEXTANT-1345}" | |
"\N{BLOCK SEXTANT-13456}" | |
"\N{BLOCK SEXTANT-12}" | |
"\N{BLOCK SEXTANT-126}" | |
"\N{BLOCK SEXTANT-125}" | |
"\N{BLOCK SEXTANT-1256}" | |
"\N{BLOCK SEXTANT-124}" | |
"\N{BLOCK SEXTANT-1246}" | |
"\N{BLOCK SEXTANT-1245}" | |
"\N{BLOCK SEXTANT-12456}" | |
"\N{BLOCK SEXTANT-123}" | |
"\N{BLOCK SEXTANT-1236}" | |
"\N{BLOCK SEXTANT-1235}" | |
"\N{BLOCK SEXTANT-12356}" | |
"\N{BLOCK SEXTANT-1234}" | |
"\N{BLOCK SEXTANT-12346}" | |
"\N{BLOCK SEXTANT-12345}" | |
"\N{FULL BLOCK}" | |
) | |
im = Image.open(sys.argv[1]) | |
# if image is not 1-bit, convert it | |
if im.mode != "1": | |
im = im.convert("1") | |
# if image width is not a multiple of 2 pixels, fix that | |
if im.size[0] % 2: | |
im2 = Image.new("1", (im.size[0] + 1, im.size[1]), "white") | |
im2.paste(im, (0, 0)) | |
im = im2 | |
del im2 | |
# if image height is not a multiple of 3 pixels, fix that | |
if im.size[1] % 3: | |
im2 = Image.new( | |
"1", (im.size[0], im.size[1] + 3 - im.size[1] % 3), "white" | |
) | |
im2.paste(im, (0, 0)) | |
im = im2 | |
del im2 | |
# Invert image, via greyscale for compatibility | |
# (no, I don't know why I need to do this) | |
im = PIL.ImageOps.invert(im.convert('L')) | |
# ... and now convert back to single bit | |
im = im.convert('1') | |
for y in range(0, im.size[1], 3): | |
output = "" | |
for x in range(0, im.size[0], 2): | |
data = np.array(im.crop((x, y, x + 2, y + 3))) | |
output += lookup[(np.packbits(data)[0] // 4) & 63] | |
print(output) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment