Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
__pycache__/
*.pyc

out/
21 changes: 19 additions & 2 deletions generate_pbff.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def generate_pbff_file(data, out):
(top, left, advance, width, height, codepoint) = \
(glyph[x] for x in
('top', 'left', 'advance', 'width', 'height', 'codepoint'))
try:
glyph_bitmap_bits = glyph['bits']
except KeyError:
glyph_bitmap_bits = []

print('glyph %d%s' % (
codepoint,
Expand All @@ -56,10 +60,23 @@ def generate_pbff_file(data, out):
print('.')
print(' %d' % top, file=out)

for x in range(height):
glyph_bitmap_bits_offset = 0
for y in range(height):
if left > 0:
print(' ' * left, end='', file=out)
print('#' * width, file=out)
if glyph_bitmap_bits:
for x in range(width):
letter = ' '
try:
if glyph_bitmap_bits[glyph_bitmap_bits_offset] >= 1:
letter = '#'
except IndexError:
pass
glyph_bitmap_bits_offset += 1
print(letter, end='', file=out)
print(end='\n', file=out)
else:
print('#' * width, file=out)

print('-', file=out)

Expand Down
77 changes: 59 additions & 18 deletions metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
###############################################################################
# #
# Reads font files and outputs metrics json data #
# file based on the font metrics. #
# file based on the font metrics. Can include bitmaps bits. #
# #
###############################################################################

import argparse
import json
import math
import os.path
import struct
import sys
Expand Down Expand Up @@ -62,6 +63,24 @@ def read_all(self):


class FontReader:
def __init__(self, include_bitmaps):
if include_bitmaps:
print('Bitmaps inclusion enabled')
self.include_bitmaps = True
else:
print('Bitmaps inclusion disabled')
self.include_bitmaps = False

def get_bits_no_padding(self, bytes_iter: bytes, original_length: int) -> list[int]:
bits: list[int] = []
for byte in bytes_iter:
byte_bits: list[int] = []
byte_str = format(byte, '08b')
for bit_str in byte_str:
byte_bits.append(int(bit_str))
bits.extend(reversed(byte_bits))
return bits[:original_length]

# The actual font reader.
def read(self, fh):
fh = FileReader(fh)
Expand All @@ -80,10 +99,13 @@ def read(self, fh):
size = None
features = 0

if version >= 2:
(hash_table_size, # B
codepoint_bytes # B
) = struct.unpack('<BB', fh.read(2))
if version <= 1:
raise Exception(f'font version {version} not supported')

# if version >= 2:
(hash_table_size, # B
codepoint_bytes # B
) = struct.unpack('<BB', fh.read(2))

if version >= 3:
(size, # B
Expand Down Expand Up @@ -119,9 +141,10 @@ def read(self, fh):
glyph_table_data = []

for offset_list in offset_table_data:
# This check can be commented out if a font file raises this exception
if (offset_list['offset'] !=
fh.bytes_read - first_offset_item_offset):
raise Exception('Offset item at incorrect offset')
fh.bytes_read - first_offset_item_offset):
raise Exception('Offset item at incorrect offset')
for codepoint_index in range(offset_list['size']):
(codepoint, # B or H, depending on codepoint_bytes
offset # B or H, depending on features
Expand Down Expand Up @@ -149,14 +172,23 @@ def read(self, fh):
left,
top,
advance) = struct.unpack(
'<BBbbbxxx', glyph_data[glyph['offset']:glyph['offset'] + 8])
'<BBbbb', glyph_data[glyph['offset']:glyph['offset'] + 5]) # 5 is header size
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very sure about this. For fonts from this repo and here -- https://github.com/MarSoft/pebble-firmware-utils/wiki/Language-Packs -- it only works if we assume the glyph header size is 5 bytes.


if self.include_bitmaps:
glyph_bitmap_data_size: int = math.ceil((width * height) / 8)
glyph_bitmap_data = glyph_data[glyph['offset'] + 5:glyph['offset'] + 5 + glyph_bitmap_data_size]
glyph_bitmap_bits = self.get_bits_no_padding(glyph_bitmap_data, width * height)
else:
glyph_bitmap_bits = []

glyph_list += [{'character': chr(glyph['codepoint']),
'codepoint': glyph['codepoint'],
'width': width,
'height': height,
'left': left,
'top': top,
'advance': advance}]
'advance': advance,
'bits': glyph_bitmap_bits}]

# ----------------------------------------------------------------------

Expand All @@ -170,15 +202,24 @@ def read(self, fh):

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='+',
parser.add_argument('files',
nargs='+',
help='files to be parsed')
parser.add_argument('-ib', '--include-bitmaps',
action='store_true',
help='add to include glyphs bitmap bits in output json')
a = parser.parse_args()
data = {}

if not os.path.isdir('out'):
os.mkdir('out')

for f in a.files:
with open(f, 'rb') as fh:
r = FontReader()
if (os.path.split(f)[-1]) in data:
print('file named', os.path.split(f)[-1],
'already processed; skipping')
data[os.path.split(f)[-1]] = r.read(fh)
json.dump(data, sys.stdout, indent=2)
data = {}
with open(f, 'rb') as fh,\
open(os.path.join('out', f'{f}.metrics.json'), 'w', encoding='utf-8') as out:
r = FontReader(a.include_bitmaps)
if (os.path.split(f)[-1]) in data:
print('file named', os.path.split(f)[-1],
'already processed; skipping')
data[os.path.split(f)[-1]] = r.read(fh)
json.dump(data, out, indent=2, ensure_ascii=False)