Skip to content

Instantly share code, notes, and snippets.

@BillyDoesDev
Last active June 5, 2022 17:55
Show Gist options
  • Save BillyDoesDev/674bf416ba32d297334dacd57dea1849 to your computer and use it in GitHub Desktop.
Save BillyDoesDev/674bf416ba32d297334dacd57dea1849 to your computer and use it in GitHub Desktop.
A tool to convert images to Braille text art, written in Python3
"""
A tool to convert images into Braille art
Depends on: Pillow - Python Imaging Library
To install, do:
$ pip install Pillow
Usage:
$ python imgToBraille.py --help
"""
from PIL import Image
# Codepoint refrence: https://www.ssec.wisc.edu/~tomw/java/unicode.html#x2800
def pixels_to_character(spam: list):
## Braille code is
## represented like so: ** # So, we index them like:
## 1 4 ** 0 3
## 2 5 ** 1 4
## 3 6 ** 2 5
## 7 8 ** 6 7
## So, for example, if we have a code- ⠳,
## We can represent it like [0, 0, 1, 1, 0, 0, 1, 1],
## where the 0 represents a dot (if invert mode is not selected that is...)
## Coincidentally, the base 10 (decimal) representation of the above binary sequence
## is the offset which we need to get the corresponding Braille Code
# codepoint_offset = sum([i << shift_value for shift_value, i in enumerate(spam)])
codepoint_offset = int(
"".join(str(_) for _ in spam), base=2
) # idk, easier to understand maybe?
return chr(10240 + codepoint_offset)
def img_to_braille(path_:str, width_=0, invert=False) -> str:
with Image.open(path_).convert("L") as im: # opening the image in BnW mode
width_ = im.width if not width_ else width_ # default img width if no args are passed
im = im.resize((width_, ((im.height * width_) // im.width)))
output = ""
## parse pixels in a 4 by 2 pattern, cuz one full braille character is of type -> ⣿
for y in range(0, im.height - 4, 4): # looping till 4 pixels less
for x in range(0, im.width - 2, 2): # looping till 2 pixels less
braille_info = list([0] * 8)
dot_index = 0
brightness = 0
for y_ in range(4):
for x_ in range(2):
brightness += im.getpixel((x + x_, y + y_))
if invert: # output will be inverted
if im.getpixel((x + x_, y + y_)) <= 128: # pixel is dark
braille_info[dot_index] = 1
else:
if im.getpixel((x + x_, y + y_)) >= 128: # pixel is light
braille_info[dot_index] = 1
dot_index += 1
brightness //= 8
output += pixels_to_character(braille_info)
## uncomment to use spaces for completely dark pixels instaed
# output = output.replace("⠀", " ")
output += "\n"
return output
def img_to_character(path_:str, width_=0, invert=False, outline=False) -> str:
density = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
density = density[::-1] if invert else density
with Image.open(path_).convert("L") as im: # opening the image in BnW mode
width_ = im.width if not width_ else width_ # default img width if no args are passed
im = im.resize((width_, ((im.height * width_) // im.width)))
output = ""
# Looping by 4 pixels at a time.. just because...
for y in range(0, im.height - 4, 4):
for x in range(0, im.width - 4, 4):
brightness = 0
for y_ in range(4):
for x_ in range(4):
brightness += im.getpixel((x + x_, y + y_))
brightness //= 16
output += density[len(density)*brightness//255-1] if outline else density[::-1][min(len(density)-1, len(density)*brightness//255)]
output += "\n"
return output
if __name__ == "__main__":
import argparse
import os
import sys
parser = argparse.ArgumentParser(
description="A tool to convert images into Braille art"
)
parser.version = "1.0 [beta]"
parser.add_argument("-v", "--version", action="version")
parser.add_argument("path", type=str, help="path to the desired image")
parser.add_argument(
"-w", metavar="width", type=int, help="specify the ouput width [in px]"
)
parser.add_argument("-i", action="store_true", help="invert output")
parser.add_argument("-o", action="store_true", help="just get the ouline if printing using characters")
args = parser.parse_args()
# BAD CODE. DO NOT TOUCH!
# well, in my defence, I was pretty shit at using argparse at the time
# and I'm super lazy now to go ahead and refactor it
# so yeah, deal with it. fuck you
if not os.path.isfile(args.path):
print("Invalid file path!")
sys.exit()
else:
path = os.path.join(args.path)
if args.w:
width = args.w
else:
width = 0
print(img_to_braille(path, width, args.i if args.i else False))
# print(img_to_character(path, width, args.i if args.i else False, outline=args.o if args.o else False))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment