123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- #!/usr/bin/python
-
- # Written By Marcio Teixeira 2019 - Aleph Objects, Inc.
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # To view a copy of the GNU General Public License, go to the following
- # location: <http://www.gnu.org/licenses/>.
-
- from __future__ import print_function
- from PIL import Image
- import argparse
- import textwrap
-
- def pack_rle(data):
- """Use run-length encoding to pack the bytes"""
- rle = []
- value = data[0]
- count = 0
- for i in data:
- if i != value or count == 255:
- rle.append(count)
- rle.append(value)
- value = i
- count = 1
- else:
- count += 1
- rle.append(count)
- rle.append(value)
- return rle
-
- class WriteSource:
- def __init__(self, lines_in_blocks):
- self.blocks = []
- self.values = []
- self.block_size = lines_in_blocks
- self.rows = 0
-
- def add_pixel(self, value):
- self.values.append(value)
-
- def convert_to_4bpp(self, data, chunk_size = 0):
- # Invert the image
- data = map(lambda i: 255 - i, data)
- # Quanitize 8-bit values into 4-bits
- data = map(lambda i: i >> 4, data)
- # Make sure there is an even number of elements
- if (len(data) & 1) == 1:
- result.append(0)
- # Combine each two adjacent values into one
- i = iter(data)
- data = map(lambda a, b: a << 4 | b, i ,i)
- # Pack the data
- data = pack_rle(data)
- # Convert values into hex strings
- return map(lambda a: "0x" + format(a, '02x'), data)
-
- def end_row(self, y):
- # Pad each row into even number of values
- if len(self.values) & 1:
- self.values.append(0)
-
- self.rows += 1
- if self.block_size and (self.rows % self.block_size) == 0:
- self.blocks.append(self.values)
- self.values = []
-
- def write(self):
- if len(self.values):
- self.blocks.append(self.values)
-
- block_strs = [];
- for b in self.blocks:
- data = self.convert_to_4bpp(b)
- data = ', '.join(data)
- data = textwrap.fill(data, 75, initial_indent = ' ', subsequent_indent = ' ')
- block_strs.append(data)
-
- print("const unsigned char font[] PROGMEM = {")
- for i, b in enumerate(block_strs):
- if i:
- print(',')
- print('\n /* {} */'.format(i))
- print(b, end='')
- print("\n};")
-
- if __name__ == "__main__":
- parser = argparse.ArgumentParser(description='Converts a grayscale bitmap into a 16-level RLE packed C array for use as font data')
- parser.add_argument("input")
- parser.add_argument('--char_height', help='Adds a separator every so many lines', type=int)
- args = parser.parse_args()
-
- writer = WriteSource(args.char_height)
-
- img = Image.open(args.input).convert('L')
- for y in range(img.height):
- for x in range(img.width):
- writer.add_pixel(img.getpixel((x,y)))
- writer.end_row(y)
- writer.write()
|