Skip to content

Instantly share code, notes, and snippets.

@scruss
Created August 1, 2025 02:09
Show Gist options
  • Save scruss/b064a667cebecf31e4896f92659505e1 to your computer and use it in GitHub Desktop.
Save scruss/b064a667cebecf31e4896f92659505e1 to your computer and use it in GitHub Desktop.
img2blocks - bitmap to Unicode sextants
#!/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