Source code for bdflib.reader
# bdflib, a library for working with BDF font files
# Copyright (C) 2009, Timothy Alle
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from bdflib import model
def _read_glyph(iterable, font):
glyphName = ""
codepoint = -1
bbX = 0
bbY = 0
bbW = 0
bbH = 0
advance = 0
data = []
for line in iterable:
parts = line.strip().split(b' ')
key = parts[0]
values = parts[1:]
if key == b"STARTCHAR":
glyphName = b" ".join(values)
elif key == b"ENCODING":
codepoint = int(values[0])
elif key == b"DWIDTH":
advance = int(values[0])
elif key == b"BBX":
bbW, bbH, bbX, bbY = [int(val) for val in values]
elif key == b"BITMAP":
# The next bbH lines describe the font bitmap.
data = [next(iterable).strip() for i in range(bbH)]
assert next(iterable).strip() == b"ENDCHAR"
break
font.new_glyph_from_data(glyphName, data, bbX, bbY, bbW, bbH, advance,
codepoint)
def _unquote_property_value(value):
# Python 2.x compat: we can't predict whether indexing into a bytestring
# will give a one-char string or an integer.
if value[0] == b'"'[0]:
# Must be a string. Remove the outer quotes and un-escape embedded
# quotes.
return value[1:-1].replace(b'""', b'"')
else:
# No quotes, must be an integer.
return int(value)
def _read_property(iterable, font):
key, value = next(iterable).strip().split(b' ', 1)
font[key] = _unquote_property_value(value)
def _skip_blank_lines(iterable):
"""
Yields only lines from iterable that contain non-whitespace characters.
"""
for line in iterable:
line = line.strip()
if line != b"":
yield line
[docs]def read_bdf(raw_iterable):
"""
Read a BDF-format font from the given source.
:param raw_iterable: Each item should be a single line of the BDF file,
ASCII encoded.
:type raw_iterable: iterable of :class:`bytes`
:returns: the resulting font object
:rtype: :class:`.Font`
If you want to read an actual file, make sure you use the 'b' flag so
you get bytes instead of text::
font = bdflib.reader.read_bdf(open(path, 'rb'))
"""
name = b""
pointSize = 0.0
resX = 0
resY = 0
comments = []
font = None
iterable = _skip_blank_lines(raw_iterable)
for line in iterable:
parts = line.strip().split(b' ')
key = parts[0]
values = parts[1:]
if key == b"COMMENT":
comments.append(b" ".join(values))
elif key == b"FONT":
name = b" ".join(values)
elif key == b"SIZE":
pointSize = float(values[0])
resX = int(values[1])
resY = int(values[2])
elif key == b"FONTBOUNDINGBOX":
# We don't care about the font bounding box, but it's the last
# header to come before the variable-length fields for which we
# need a font object around.
font = model.Font(name, pointSize, resX, resY)
for c in comments:
font.add_comment(c)
elif key == b"STARTPROPERTIES":
propertyCount = int(values[0])
[_read_property(iterable, font) for i in range(propertyCount)]
assert next(iterable).strip() == b"ENDPROPERTIES"
elif key == b"CHARS":
glyphCount = int(values[0])
[_read_glyph(iterable, font) for i in range(glyphCount)]
break
assert next(iterable).strip() == b"ENDFONT"
return font