Skip to content

Instantly share code, notes, and snippets.

@jujumo
Created February 1, 2021 08:31
Show Gist options
  • Save jujumo/d38ad713ddb878b02d5c3d17c125035b to your computer and use it in GitHub Desktop.
Save jujumo/d38ad713ddb878b02d5c3d17c125035b to your computer and use it in GitHub Desktop.
Convert image to monochrome c bitmaps array.
import argparse
import logging
import os.path as path
from PIL import Image
import numpy as np
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(name)s::%(levelname)-8s: %(message)s')
class VerbosityParsor(argparse.Action):
""" accept debug, info, ... or theirs corresponding integer value formatted as string."""
def __call__(self, parser, namespace, values, option_string=None):
assert isinstance(values, str)
try: # in case it represent an int, directly get it
values = int(values)
except ValueError: # else ask logging to sort it out
values = logging.getLevelName(values.upper())
setattr(namespace, self.dest, values)
def convert(input_filepath, output_filepath, rotation=0):
filename = path.basename(path.splitext(input_filepath)[0])
image = Image.open(input_filepath) # open colour image
image = image.convert('1') # convert image to black and white
rotation_angles = {1: 90, 2: 180, 3: 270}
if rotation in rotation_angles:
image = image.rotate(rotation_angles[rotation], expand=False)
width, height = image.size
# check dimensions are multiple of 8 bits
if any((s % 8) != 0 for s in image.size):
logger.warning(f'dimensions not multiple of 8 may cause problems')
bitmap = np.array(image).flatten()
if not (len(bitmap) % 8 == 0):
raise ValueError('')
# repack 8 bits as chars
bitmap = bitmap.reshape((-1, 8))
bitmap = np.packbits(bitmap, axis=1).flatten()
# make pack of 12 chars for a nice formatting
bits = bitmap.tolist()
nb_bits = len(bits)
nb_cols = int(12)
nb_tail = nb_cols - (nb_bits % nb_cols) if nb_bits % nb_cols != 0 else 0
bits = bits + [None] * nb_tail
bitmap = np.array(bits).reshape((-1, nb_cols))
with open(output_filepath, 'wt') as fout:
fout.write(f'static const size_t bitmap_{filename}_width = {width};\n')
fout.write(f'static const size_t bitmap_{filename}_height = {height};\n')
fout.write(f'static const uint8_t bitmap_{filename}_data[{nb_bits}] = ')
fout.write('{\n')
fout.write(',\n'.join((', '.join(f'0x{value:02x}' for value in line if value is not None)
for line in bitmap)))
fout.write('\n};\n')
def main():
parser = argparse.ArgumentParser(description='Convert image to monochrome c bitmaps array.')
parser_verbosity = parser.add_mutually_exclusive_group()
parser_verbosity.add_argument(
'-v', '--verbose', nargs='?', default=logging.INFO, const=logging.DEBUG, action=VerbosityParsor,
help='verbosity level (debug, info, warning, critical, ... or int value) [warning]')
parser_verbosity.add_argument(
'-q', '--silent', '--quiet', action='store_const', dest='verbose', const=logging.CRITICAL)
parser.add_argument('-i', '--input', required=True, help='input')
parser.add_argument('-o', '--output', help='output [input.h]')
parser.add_argument('-r', '--rotation', type=int, choices=range(4), default=0, help='output [input.h]')
args = parser.parse_args()
logger.setLevel(args.verbose)
try:
args.input = path.abspath(args.input)
if not args.output:
args.output = path.splitext(args.input)[0] + '.h'
convert(args.input, args.output, rotation=args.rotation)
except Exception as e:
logger.critical(e)
if args.verbose <= logging.DEBUG:
raise
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment