aboutsummaryrefslogtreecommitdiff
path: root/bin/bdftofnt.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/bdftofnt.py')
-rw-r--r--bin/bdftofnt.py148
1 files changed, 71 insertions, 77 deletions
diff --git a/bin/bdftofnt.py b/bin/bdftofnt.py
index e314ddc48a8a..0bfeed80840b 100644
--- a/bin/bdftofnt.py
+++ b/bin/bdftofnt.py
@@ -1,15 +1,19 @@
#
-# Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
+# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
-# 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 2 of
-# the License, or (at your option) any later version.
+# 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 2 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.
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import re
@@ -18,18 +22,19 @@ import fnutil
import fncli
import fnio
import bdf
-import bmpf
-
+import bdfexp
+# -- Params --
class Params(fncli.Params):
def __init__(self):
fncli.Params.__init__(self)
self.char_set = -1
self.min_char = -1
self.fnt_family = 0
- self.output = None
+ self.output_name = None
+# -- Options --
HELP = ('' +
'usage: bdftofnt [-c CHARSET] [-m MINCHAR] [-f FAMILY] [-o OUTPUT] [INPUT]\n' +
'Convert a BDF font to Windows FNT\n' +
@@ -37,14 +42,14 @@ HELP = ('' +
' -c CHARSET fnt character set (default = 0, see wingdi.h ..._CHARSET)\n' +
' -m MINCHAR fnt minimum character code (8-bit CP decimal, not unicode)\n' +
' -f FAMILY fnt family: DontCare, Roman, Swiss, Modern or Decorative\n' +
- ' -o OUTPUT output file (default = stdout, must not be a terminal)\n' +
+ ' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
- 'The input must be a BDF font encoded in the unicode range.\n')
+ 'The input must be a BDF 2.1 font with unicode encoding.\n')
-VERSION = 'bdftofnt 1.55, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
+VERSION = 'bdftofnt 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
FNT_FAMILIES = ['DontCare', 'Roman', 'Swiss', 'Modern', 'Decorative']
@@ -55,21 +60,22 @@ class Options(fncli.Options):
def parse(self, name, value, params):
if name == '-c':
- params.char_set = fnutil.parse_dec('charset', value, 0, 255)
+ params.char_set = fnutil.parse_dec('CHARSET', value, 0, 255)
elif name == '-m':
- params.min_char = fnutil.parse_dec('minchar', value, 0, 255)
+ params.min_char = fnutil.parse_dec('MINCHAR', value, 0, 255)
elif name == '-f':
if value in FNT_FAMILIES:
params.fnt_family = FNT_FAMILIES.index(value)
else:
- raise Exception('invalid fnt family')
+ raise Exception('invalid FAMILY')
elif name == '-o':
- params.output = value
+ params.output_name = value
else:
self.fallback(name, params)
-WIN_FONTHEADERSIZE = 118
+# -- Main --
+FNT_HEADER_SIZE = 118
FNT_CHARSETS = [238, 204, 0, 161, 162, 177, 178, 186, 163]
def main_program(nonopt, parsed):
@@ -80,13 +86,8 @@ def main_program(nonopt, parsed):
min_char = parsed.min_char
# READ INPUT
- ifs = fnio.InputStream(nonopt[0] if nonopt else None)
-
- try:
- font = bmpf.Font.read(ifs)
- ifs.close()
- except Exception as ex:
- raise Exception(ifs.location() + str(ex))
+ ifs = fnio.InputFileStream(nonopt[0] if nonopt else None)
+ font = ifs.process(bdfexp.Font.read)
# COMPUTE
if char_set == -1:
@@ -115,15 +116,15 @@ def main_program(nonopt, parsed):
raise Exception('the maximum character code is too big, (re)specify -m')
# HEADER
- vtell = WIN_FONTHEADERSIZE + (num_chars + 1) * 4
+ vtell = FNT_HEADER_SIZE + (num_chars + 1) * 4
bits_offset = vtell
ctable = []
width_bytes = 0
# CTABLE/GLYPHS
for char in font.chars:
- row_size = char.row_size()
- ctable.append(char.width)
+ row_size = char.bbx.row_size()
+ ctable.append(char.bbx.width)
ctable.append(vtell)
vtell += row_size * font.bbx.height
width_bytes += row_size
@@ -142,43 +143,38 @@ def main_program(nonopt, parsed):
raise Exception('the total character width is too big')
except Exception as ex:
- raise Exception(ifs.location() + str(ex))
+ ex.message = ifs.location() + getattr(ex, 'message', str(ex))
+ raise
# WRITE
- ofs = fnio.OutputStream(parsed.output)
-
- if ofs.file.isatty():
- raise Exception('binary output may not be send to a terminal, use -o or redirect/pipe it')
-
- try:
+ def write_fnt(output):
# HEADER
family = font.xlfd[bdf.XLFD.FAMILY_NAME]
copyright = font.props.get('COPYRIGHT')
copyright = fnutil.unquote(copyright)[:60] if copyright is not None else b''
- proportional = font.get_proportional()
-
- ofs.write16(0x0200) # font version
- ofs.write32(vtell + len(family) + 1) # total size
- ofs.write_zstr(copyright, 60 - len(copyright))
- ofs.write16(0) # gdi, device type
- ofs.write16(round(font.bbx.height * 72 / 96))
- ofs.write16(96) # vertical resolution
- ofs.write16(96) # horizontal resolution
- ofs.write16(font.get_ascent()) # base line
- ofs.write16(0) # internal leading
- ofs.write16(0) # external leading
- ofs.write8(font.get_italic())
- ofs.write8(0) # underline
- ofs.write8(0) # strikeout
- ofs.write16(400 + 300 * font.get_bold())
- ofs.write8(char_set)
- ofs.write16(0 if proportional else font.bbx.width)
- ofs.write16(font.bbx.height)
- ofs.write8((parsed.fnt_family << 4) + proportional)
- ofs.write16(font.avg_width)
- ofs.write16(font.bbx.width)
- ofs.write8(min_char)
- ofs.write8(max_char)
+
+ output.write16(0x0200) # font version
+ output.write32(vtell + len(family) + 1) # total size
+ output.write_zstr(copyright, 60 - len(copyright))
+ output.write16(0) # gdi, device type
+ output.write16(round(font.bbx.height * 72 / 96))
+ output.write16(96) # vertical resolution
+ output.write16(96) # horizontal resolution
+ output.write16(font.px_ascender) # base line
+ output.write16(0) # internal leading
+ output.write16(0) # external leading
+ output.write8(int(font.italic))
+ output.write8(0) # underline
+ output.write8(0) # strikeout
+ output.write16(700 if font.bold else 400)
+ output.write8(char_set)
+ output.write16(0 if font.proportional else font.bbx.width)
+ output.write16(font.bbx.height)
+ output.write8((parsed.fnt_family << 4) + int(font.proportional))
+ output.write16(font.avg_width)
+ output.write16(font.bbx.width)
+ output.write8(min_char)
+ output.write8(max_char)
default_index = max_char - min_char
break_index = 0
@@ -189,39 +185,37 @@ def main_program(nonopt, parsed):
if min_char <= 0x20 <= max_char:
break_index = 0x20 - min_char
- ofs.write8(default_index)
- ofs.write8(break_index)
- ofs.write16(width_bytes)
- ofs.write32(0) # device name
- ofs.write32(vtell)
- ofs.write32(0) # gdi bits pointer
- ofs.write32(bits_offset)
- ofs.write8(0) # reserved
+ output.write8(default_index)
+ output.write8(break_index)
+ output.write16(width_bytes)
+ output.write32(0) # device name
+ output.write32(vtell)
+ output.write32(0) # gdi bits pointer
+ output.write32(bits_offset)
+ output.write8(0) # reserved
# CTABLE
for value in ctable:
- ofs.write16(value)
+ output.write16(value)
# GLYPHS
data = bytearray(font.bbx.height * font.bbx.row_size())
for char in font.chars:
- row_size = char.row_size()
+ row_size = char.bbx.row_size()
counter = 0
# MS coordinates
for n in range(0, row_size):
for y in range(0, font.bbx.height):
data[counter] = char.data[row_size * y + n]
counter += 1
- ofs.write(data[:counter])
- ofs.write(bytes(sentinel * font.bbx.height))
+ output.write(data[:counter])
+ output.write(bytes(sentinel * font.bbx.height))
# FAMILY
- ofs.write_zstr(family, 1)
- ofs.close()
+ output.write_zstr(family, 1)
- except Exception as ex:
- raise Exception(ofs.location() + str(ex) + ofs.destroy())
+ fnio.write_file(parsed.output_name, write_fnt, encoding=None)
if __name__ == '__main__':