Initial commit
Version 1.0 of the code with a short README.
This commit is contained in:
commit
47168bb385
2 changed files with 1058 additions and 0 deletions
66
README
Normal file
66
README
Normal file
|
@ -0,0 +1,66 @@
|
|||
C64 Character Set to TrueType Converter
|
||||
=======================================
|
||||
|
||||
C64TTF.py is a script for converting partial C64 memory dumps, in the form of
|
||||
64c-files, into TrueType font files for use on modern operating systems.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
Python 2
|
||||
FontTools/TTX
|
||||
Numpy
|
||||
|
||||
Syntax
|
||||
------
|
||||
usage: c64ttf.py [-h] [-l LOWERCASE] [-u UPPERCASE] [-o OUTPUT] [-x] [-m]
|
||||
[-p PIXELSIZE] [-d DESCENT] [-a] [-n NAME] [-y COPYRIGHTYEAR]
|
||||
[-c CREATOR] [-v VERSION]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-l LOWERCASE, --lowercase LOWERCASE
|
||||
Input 64C file with lowercase and uppercase
|
||||
characters.
|
||||
-u UPPERCASE, --uppercase UPPERCASE
|
||||
Input 64C file with uppercase and graphics characters.
|
||||
-o OUTPUT, --output OUTPUT
|
||||
Output filename (default is font name + '.TTF' or
|
||||
'.TTX')
|
||||
-x, --xml Enable XML output (for debugging purposes)
|
||||
-m, --add-missing-ascii
|
||||
Add non-PETSCII characters for ASCII compatibility
|
||||
(ie. grave accent, curly braces, vertical bar, tilde,
|
||||
caret, backslash, and underscore)
|
||||
-p PIXELSIZE, --pixelsize PIXELSIZE
|
||||
Pixel size in the resulting TTF file (default is 256)
|
||||
-d DESCENT, --descent DESCENT
|
||||
The descent below baseline in pixels (default is 1)
|
||||
-a, --add-all Inserts the uppercase character set (if any) at
|
||||
0xEE00...0xEEFF and the lowercase character set (if
|
||||
any) at 0xEF00...0xEFFF
|
||||
-n NAME, --name NAME Font name
|
||||
-y COPYRIGHTYEAR, --copyrightyear COPYRIGHTYEAR
|
||||
Sets copyright year
|
||||
-c CREATOR, --creator CREATOR
|
||||
Font creator
|
||||
-v VERSION, --version VERSION
|
||||
Sets font version number
|
||||
|
||||
NOTE:
|
||||
Both -l and -u are listed as "optional arguments", but obviously at least one
|
||||
of them has to be specified.
|
||||
|
||||
Example
|
||||
-------
|
||||
Usable files can be found in the "Character Sets"-section at this page (which
|
||||
is not mine by the way):
|
||||
http://kofler.dot.at/c64/
|
||||
|
||||
Given the input files c64_lower.64c and c64_upper.64c:
|
||||
|
||||
./c64ttf.py -l c64_lower.64c -u c64_upper.64c -o c64.ttf -m -a \
|
||||
-n "Commodore 64 2" -y 1982 -c Commodore -v "1.00"
|
||||
|
||||
This will create a font called "Commodore 64" with all lowercase, uppercase,
|
||||
and graphics characters included. Additionally, the missing ASCII characters
|
||||
are included as well.
|
992
c64ttf.py
Executable file
992
c64ttf.py
Executable file
|
@ -0,0 +1,992 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
C64 Character Set to TrueType Converter
|
||||
Version 1.0
|
||||
|
||||
Copyright (c) 2013, A.T.Brask (atbrask[at]gmail[dot]com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from datetime import date
|
||||
import getpass
|
||||
import math
|
||||
import time
|
||||
import numpy
|
||||
import os
|
||||
|
||||
from fontTools.ttLib import TTFont, newTable
|
||||
from fontTools.ttLib.tables import ttProgram
|
||||
from fontTools.ttLib.tables._c_m_a_p import cmap_format_4
|
||||
from fontTools.ttLib.tables._h_e_a_d import mac_epoch_diff
|
||||
from fontTools.ttLib.tables._g_l_y_f import Glyph
|
||||
from fontTools.ttLib.tables.O_S_2f_2 import Panose
|
||||
from fontTools.ttLib.tables._n_a_m_e import NameRecord
|
||||
|
||||
# DATA SECTION
|
||||
|
||||
# Map from a subset of C64 PETSCII to ASCII as well as a few Unicode points.
|
||||
# Not all PETSCII characters can be mapped into Unicode.
|
||||
# Each tuple is [C64 character generator index, AGL name, [unicode codes]]
|
||||
# The rest of the C64 glyphs can be included at 0xEE00...0xEFFF by using the
|
||||
# command line argument --add-all
|
||||
# The chars are in the C64 character generator order.
|
||||
|
||||
CHAR_HI = [[0, "at", [0x40]],
|
||||
[1, "A", [0x41]],
|
||||
[2, "B", [0x42]],
|
||||
[3, "C", [0x43]],
|
||||
[4, "D", [0x44]],
|
||||
[5, "E", [0x45]],
|
||||
[6, "F", [0x46]],
|
||||
[7, "G", [0x47]],
|
||||
[8, "H", [0x48]],
|
||||
[9, "I", [0x49]],
|
||||
[10, "J", [0x4a]],
|
||||
[11, "K", [0x4b]],
|
||||
[12, "L", [0x4c]],
|
||||
[13, "M", [0x4d]],
|
||||
[14, "N", [0x4e]],
|
||||
[15, "O", [0x4f]],
|
||||
[16, "P", [0x50]],
|
||||
[17, "Q", [0x51]],
|
||||
[18, "R", [0x52]],
|
||||
[19, "S", [0x53]],
|
||||
[20, "T", [0x54]],
|
||||
[21, "U", [0x55]],
|
||||
[22, "V", [0x56]],
|
||||
[23, "W", [0x57]],
|
||||
[24, "X", [0x58]],
|
||||
[25, "Y", [0x59]],
|
||||
[26, "Z", [0x5a]],
|
||||
[27, "bracketleft", [0x5b]],
|
||||
[28, "sterling", [0xa3]],
|
||||
[29, "bracketright", [0x5d]],
|
||||
[30, "arrowup", [0x2191]],
|
||||
[31, "arrowleft", [0x2190]],
|
||||
[32, "space", [0x20, 0xa0]],
|
||||
[33, "exclam", [0x21]],
|
||||
[34, "quotedblright", [0x22, 0x201c, 0x201d]],
|
||||
[35, "numbersign", [0x23]],
|
||||
[36, "dollar", [0x24]],
|
||||
[37, "percent", [0x25]],
|
||||
[38, "ampersand", [0x26]],
|
||||
[39, "quoteright", [0x27, 0x92, 0x2019]],
|
||||
[40, "parenleft", [0x28]],
|
||||
[41, "parenright", [0x29]],
|
||||
[42, "asterisk", [0x2a]],
|
||||
[43, "plus", [0x2b]],
|
||||
[44, "comma", [0x2c]],
|
||||
[45, "hyphen", [0x2d]],
|
||||
[46, "period", [0x2e]],
|
||||
[47, "slash", [0x2f]],
|
||||
[48, "zero", [0x30]],
|
||||
[49, "one", [0x31]],
|
||||
[50, "two", [0x32]],
|
||||
[51, "three", [0x33]],
|
||||
[52, "four", [0x34]],
|
||||
[53, "five", [0x35]],
|
||||
[54, "six", [0x36]],
|
||||
[55, "seven", [0x37]],
|
||||
[56, "eight", [0x38]],
|
||||
[57, "nine", [0x39]],
|
||||
[58, "colon", [0x3a]],
|
||||
[59, "semicolon", [0x3b]],
|
||||
[60, "less", [0x3c]],
|
||||
[61, "equal", [0x3d]],
|
||||
[62, "greater", [0x3e]],
|
||||
[63, "question", [0x3f]],
|
||||
[64, "SF100000", [0x2500, 0x2501]],
|
||||
[65, "spade", [0x2660]],
|
||||
[66, "SF110000", [0x2502, 0x2503]],
|
||||
[73, "uni256e", [0x256e]],
|
||||
[74, "uni2570", [0x2570]],
|
||||
[75, "uni256F", [0x256f]],
|
||||
[77, "uni2572", [0x2572]],
|
||||
[78, "uni2571", [0x2571]],
|
||||
[81, "periodcentered", [0xb7, 0x2022, 0x2219, 0x25cf]],
|
||||
[83, "heart", [0x2665]],
|
||||
[85, "uni256D", [0x256d]],
|
||||
[86, "uni2573", [0x2573]],
|
||||
[87, "circle", [0x25cb]],
|
||||
[88, "club", [0x2663]],
|
||||
[90, "diamond", [0x25c6, 0x2666]],
|
||||
[91, "SF050000", [0x253c, 0x254b]],
|
||||
[94, "pi", [0x3c0]],
|
||||
[95, "uni25e5", [0x25e5]],
|
||||
[97, "lfblock", [0x258c]],
|
||||
[98, "dnblock", [0x2584]],
|
||||
[99, "uni2594", [0x2594]],
|
||||
[100, "uni2581", [0x2581]],
|
||||
[101, "uni258E", [0x258e]],
|
||||
[102, "shade", [0x2592]],
|
||||
[105, "uni25E4", [0x25e4]],
|
||||
[107, "SF080000", [0x251c, 0x2523]],
|
||||
[108, "uni2597", [0x2597]],
|
||||
[109, "SF020000", [0x2514, 0x2517]],
|
||||
[110, "SF030000", [0x2510, 0x2513]],
|
||||
[111, "uni2582", [0x2582]],
|
||||
[112, "SF010000", [0x250c, 0x250f]],
|
||||
[113, "SF070000", [0x2534, 0x253b]],
|
||||
[114, "SF060000", [0x252c, 0x2533]],
|
||||
[115, "SF090000", [0x2524, 0x252b]],
|
||||
[117, "uni258D", [0x258d]],
|
||||
[121, "uni2583", [0x2583]],
|
||||
[123, "uni2596", [0x2596]],
|
||||
[124, "uni259D", [0x259d]],
|
||||
[125, "SF040000", [0x2518, 0x251b]],
|
||||
[126, "uni2598", [0x2598]],
|
||||
[127, "uni259A", [0x259a]],
|
||||
[160, "uni2588", [0x2588]],
|
||||
[223, "uni25E3", [0x25e3]],
|
||||
[225, "uni2590", [0x2590]],
|
||||
[226, "uni2580", [0x2580]],
|
||||
[227, "uni2587", [0x2587]],
|
||||
[231, "uni258A", [0x258a]],
|
||||
[233, "uni25E2", [0x25e2]],
|
||||
[236, "uni259B", [0x259b]],
|
||||
[246, "uni258B", [0x258b]],
|
||||
[247, "uni2586", [0x2586]],
|
||||
[248, "uni2585", [0x2585]],
|
||||
[251, "uni259C", [0x259c]],
|
||||
[252, "uni2599", [0x2599]],
|
||||
[254, "uni259F", [0x259f]],
|
||||
[255, "uni259E", [0x259e]]]
|
||||
|
||||
CHAR_LO = [[0, "at", [0x40]],
|
||||
[1, "a", [0x61]],
|
||||
[2, "b", [0x62]],
|
||||
[3, "c", [0x63]],
|
||||
[4, "d", [0x64]],
|
||||
[5, "e", [0x65]],
|
||||
[6, "f", [0x66]],
|
||||
[7, "g", [0x67]],
|
||||
[8, "h", [0x68]],
|
||||
[9, "i", [0x69]],
|
||||
[10, "j", [0x6a]],
|
||||
[11, "k", [0x6b]],
|
||||
[12, "l", [0x6c]],
|
||||
[13, "m", [0x6d]],
|
||||
[14, "n", [0x6e]],
|
||||
[15, "o", [0x6f]],
|
||||
[16, "p", [0x70]],
|
||||
[17, "q", [0x71]],
|
||||
[18, "r", [0x72]],
|
||||
[19, "s", [0x73]],
|
||||
[20, "t", [0x74]],
|
||||
[21, "u", [0x75]],
|
||||
[22, "v", [0x76]],
|
||||
[23, "w", [0x77]],
|
||||
[24, "x", [0x78]],
|
||||
[25, "y", [0x79]],
|
||||
[26, "z", [0x7a]],
|
||||
[27, "bracketleft", [0x5b]],
|
||||
[28, "sterling", [0xa3]],
|
||||
[29, "bracketright", [0x5d]],
|
||||
[30, "arrowup", [0x2191]],
|
||||
[31, "arrowleft", [0x2190]],
|
||||
[32, "space", [0x20, 0xa0]],
|
||||
[33, "exclam", [0x21]],
|
||||
[34, "quotedblright", [0x22, 0x201c, 0x201d]],
|
||||
[35, "numbersign", [0x23]],
|
||||
[36, "dollar", [0x24]],
|
||||
[37, "percent", [0x25]],
|
||||
[38, "ampersand", [0x26]],
|
||||
[39, "quoteright", [0x27, 0x92, 0x2019]],
|
||||
[40, "parenleft", [0x28]],
|
||||
[41, "parenright", [0x29]],
|
||||
[42, "asterisk", [0x2a]],
|
||||
[43, "plus", [0x2b]],
|
||||
[44, "comma", [0x2c]],
|
||||
[45, "hyphen", [0x2d]],
|
||||
[46, "period", [0x2e]],
|
||||
[47, "slash", [0x2f]],
|
||||
[48, "zero", [0x30]],
|
||||
[49, "one", [0x31]],
|
||||
[50, "two", [0x32]],
|
||||
[51, "three", [0x33]],
|
||||
[52, "four", [0x34]],
|
||||
[53, "five", [0x35]],
|
||||
[54, "six", [0x36]],
|
||||
[55, "seven", [0x37]],
|
||||
[56, "eight", [0x38]],
|
||||
[57, "nine", [0x39]],
|
||||
[58, "colon", [0x3a]],
|
||||
[59, "semicolon", [0x3b]],
|
||||
[60, "less", [0x3c]],
|
||||
[61, "equal", [0x3d]],
|
||||
[62, "greater", [0x3e]],
|
||||
[63, "question", [0x3f]],
|
||||
[64, "SF100000", [0x2500, 0x2501]],
|
||||
[65, "A", [0x41]],
|
||||
[66, "B", [0x42]],
|
||||
[67, "C", [0x43]],
|
||||
[68, "D", [0x44]],
|
||||
[69, "E", [0x45]],
|
||||
[70, "F", [0x46]],
|
||||
[71, "G", [0x47]],
|
||||
[72, "H", [0x48]],
|
||||
[73, "I", [0x49]],
|
||||
[74, "J", [0x4a]],
|
||||
[75, "K", [0x4b]],
|
||||
[76, "L", [0x4c]],
|
||||
[77, "M", [0x4d]],
|
||||
[78, "N", [0x4e]],
|
||||
[79, "O", [0x4f]],
|
||||
[80, "P", [0x50]],
|
||||
[81, "Q", [0x51]],
|
||||
[82, "R", [0x52]],
|
||||
[83, "S", [0x53]],
|
||||
[84, "T", [0x54]],
|
||||
[85, "U", [0x55]],
|
||||
[86, "V", [0x56]],
|
||||
[87, "W", [0x57]],
|
||||
[88, "X", [0x58]],
|
||||
[89, "Y", [0x59]],
|
||||
[90, "Z", [0x5a]],
|
||||
[91, "SF050000", [0x253c, 0x254b]],
|
||||
[93, "SF110000", [0x2502, 0x2503]],
|
||||
[97, "lfblock", [0x258c]],
|
||||
[98, "dnblock", [0x2584]],
|
||||
[99, "uni2594", [0x2594]],
|
||||
[100, "uni2581", [0x2581]],
|
||||
[101, "uni258E", [0x258e]],
|
||||
[102, "shade", [0x2592]],
|
||||
[107, "SF080000", [0x251c, 0x2523]],
|
||||
[108, "uni2597", [0x2597]],
|
||||
[109, "SF020000", [0x2514, 0x2517]],
|
||||
[110, "SF030000", [0x2510, 0x2513]],
|
||||
[111, "uni2582", [0x2582]],
|
||||
[112, "SF010000", [0x250c, 0x250f]],
|
||||
[113, "SF070000", [0x2534, 0x253b]],
|
||||
[114, "SF060000", [0x252c, 0x2533]],
|
||||
[115, "SF090000", [0x2524, 0x252b]],
|
||||
[117, "uni258D", [0x258d]],
|
||||
[121, "uni2583", [0x2583]],
|
||||
[122, "uni2713", [0x2713]],
|
||||
[123, "uni2596", [0x2596]],
|
||||
[124, "uni259D", [0x259d]],
|
||||
[125, "SF040000", [0x2518, 0x251b]],
|
||||
[126, "uni2598", [0x2598]],
|
||||
[127, "uni259A", [0x259a]],
|
||||
[160, "uni2588", [0x2588]],
|
||||
[225, "uni2590", [0x2590]],
|
||||
[226, "uni2580", [0x2580]],
|
||||
[227, "uni2587", [0x2587]],
|
||||
[231, "uni258A", [0x258a]],
|
||||
[236, "uni259B", [0x259b]],
|
||||
[246, "uni258B", [0x258b]],
|
||||
[247, "uni2586", [0x2586]],
|
||||
[248, "uni2585", [0x2585]],
|
||||
[251, "uni259C", [0x259c]],
|
||||
[252, "uni2599", [0x2599]],
|
||||
[254, "uni259F", [0x259f]],
|
||||
[255, "uni259E", [0x259e]]]
|
||||
|
||||
# The Mac OS Roman mapping is an 8-bit encoding including 7-bit ASCII and a few
|
||||
# bits and pieces. The format is [mac roman code, glyph name]
|
||||
# Indices not in this table will be mapped to ".notdef"
|
||||
|
||||
CMAP_MACROMAN = [[0x0, ".null"],
|
||||
[0x8, ".null"],
|
||||
[0x9, "nonmarkingreturn"],
|
||||
[0xd, "nonmarkingreturn"],
|
||||
[0x1d, ".null"],
|
||||
[0x20, "space"],
|
||||
[0x21, "exclam"],
|
||||
[0x23, "numbersign"],
|
||||
[0x24, "dollar"],
|
||||
[0x25, "percent"],
|
||||
[0x26, "ampersand"],
|
||||
[0x28, "parenleft"],
|
||||
[0x29, "parenright"],
|
||||
[0x2a, "asterisk"],
|
||||
[0x2b, "plus"],
|
||||
[0x2c, "comma"],
|
||||
[0x2d, "hyphen"],
|
||||
[0x2e, "period"],
|
||||
[0x2f, "slash"],
|
||||
[0x30, "zero"],
|
||||
[0x31, "one"],
|
||||
[0x32, "two"],
|
||||
[0x33, "three"],
|
||||
[0x34, "four"],
|
||||
[0x35, "five"],
|
||||
[0x36, "six"],
|
||||
[0x37, "seven"],
|
||||
[0x38, "eight"],
|
||||
[0x39, "nine"],
|
||||
[0x3a, "colon"],
|
||||
[0x3b, "semicolon"],
|
||||
[0x3c, "less"],
|
||||
[0x3d, "equal"],
|
||||
[0x3e, "greater"],
|
||||
[0x3f, "question"],
|
||||
[0x40, "at"],
|
||||
[0x41, "A"],
|
||||
[0x42, "B"],
|
||||
[0x43, "C"],
|
||||
[0x44, "D"],
|
||||
[0x45, "E"],
|
||||
[0x46, "F"],
|
||||
[0x47, "G"],
|
||||
[0x48, "H"],
|
||||
[0x49, "I"],
|
||||
[0x4a, "J"],
|
||||
[0x4b, "K"],
|
||||
[0x4c, "L"],
|
||||
[0x4d, "M"],
|
||||
[0x4e, "N"],
|
||||
[0x4f, "O"],
|
||||
[0x50, "P"],
|
||||
[0x51, "Q"],
|
||||
[0x52, "R"],
|
||||
[0x53, "S"],
|
||||
[0x54, "T"],
|
||||
[0x55, "U"],
|
||||
[0x56, "V"],
|
||||
[0x57, "W"],
|
||||
[0x58, "X"],
|
||||
[0x59, "Y"],
|
||||
[0x5a, "Z"],
|
||||
[0x5b, "bracketleft"],
|
||||
[0x5c, "backslash"],
|
||||
[0x5d, "bracketright"],
|
||||
[0x5e, "asciicircum"],
|
||||
[0x5f, "underscore"],
|
||||
[0x60, "grave"],
|
||||
[0x61, "a"],
|
||||
[0x62, "b"],
|
||||
[0x63, "c"],
|
||||
[0x64, "d"],
|
||||
[0x65, "e"],
|
||||
[0x66, "f"],
|
||||
[0x67, "g"],
|
||||
[0x68, "h"],
|
||||
[0x69, "i"],
|
||||
[0x6a, "j"],
|
||||
[0x6b, "k"],
|
||||
[0x6c, "l"],
|
||||
[0x6d, "m"],
|
||||
[0x6e, "n"],
|
||||
[0x6f, "o"],
|
||||
[0x70, "p"],
|
||||
[0x71, "q"],
|
||||
[0x72, "r"],
|
||||
[0x73, "s"],
|
||||
[0x74, "t"],
|
||||
[0x75, "u"],
|
||||
[0x76, "v"],
|
||||
[0x77, "w"],
|
||||
[0x78, "x"],
|
||||
[0x79, "y"],
|
||||
[0x7a, "z"],
|
||||
[0x7b, "braceleft"],
|
||||
[0x7c, "bar"],
|
||||
[0x7d, "braceright"],
|
||||
[0x7e, "asciitilde"],
|
||||
[0xa3, "sterling"],
|
||||
[0xb9, "pi"],
|
||||
[0xca, "space"],
|
||||
[0xd3, "quotedblright"],
|
||||
[0xd5, "quoteright"]]
|
||||
|
||||
def makeEmptyGlyphs():
|
||||
bitmap = dict()
|
||||
|
||||
bitmap[".notdef"] = [[0b00000000,
|
||||
0b01111110,
|
||||
0b01000010,
|
||||
0b01000010,
|
||||
0b01000010,
|
||||
0b01000010,
|
||||
0b01111110,
|
||||
0b00000000], []]
|
||||
|
||||
bitmap[".null"] = [[],[]]
|
||||
|
||||
bitmap["nonmarkingreturn"] = [[],[]]
|
||||
|
||||
return bitmap
|
||||
|
||||
def makeMissingASCII():
|
||||
print "Adding the 8 missing ASCII characters in C64 PETSCII..."
|
||||
bitmap = dict()
|
||||
|
||||
# Grave accent
|
||||
bitmap["grave"] = [[0b00100000,
|
||||
0b00010000,
|
||||
0b00001000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000], [0x60]]
|
||||
|
||||
# Curly left brace
|
||||
bitmap["braceleft"] = [[0b00001100,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00110000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00001100,
|
||||
0b00000000], [0x7b]]
|
||||
|
||||
# Curly right brace
|
||||
bitmap["braceright"] = [[0b00110000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00001100,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00110000,
|
||||
0b00000000], [0x7d]]
|
||||
|
||||
# Vertical bar
|
||||
bitmap["bar"] = [[0b00011000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00011000], [0x7c]]
|
||||
|
||||
# Tilde
|
||||
bitmap["asciitilde"] = [[0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00111001,
|
||||
0b01001110,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000], [0x7e]]
|
||||
|
||||
# Caret
|
||||
bitmap["asciicircum"] = [[0b00001000,
|
||||
0b00011100,
|
||||
0b00110110,
|
||||
0b01100011,
|
||||
0b01000001,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000], [0x5e]]
|
||||
|
||||
# Backslash
|
||||
bitmap["backslash"] = [[0b00000000,
|
||||
0b01100000,
|
||||
0b00110000,
|
||||
0b00011000,
|
||||
0b00001100,
|
||||
0b00000110,
|
||||
0b00000011,
|
||||
0b00000000], [0x5c]]
|
||||
|
||||
# Underscore
|
||||
bitmap["underscore"] = [[0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b11111111], [0x5f]]
|
||||
|
||||
return bitmap
|
||||
|
||||
# THE VECTORIZATION ALGORITHM
|
||||
|
||||
def vectorizeGlyph(glyphData, pixelSize, descent):
|
||||
if glyphData is None or len(glyphData) == 0:
|
||||
return []
|
||||
|
||||
bitmap = unpackChar(glyphData)
|
||||
edges = generateEdges(bitmap)
|
||||
scaledEdges = scaleEdges(edges, pixelSize, descent)
|
||||
return mergeContours(scaledEdges)
|
||||
|
||||
# 1) First, we need to unpack the bits in the bitmap and reverse the order so
|
||||
# that [0,0] is the lower left corner. This will make the next step easier
|
||||
# to understand.
|
||||
def unpackChar(glyphData):
|
||||
return [[((row >> bit) & 1) == 1 for bit in range(7, -1, -1)] for row in reversed(glyphData)]
|
||||
|
||||
# 2) A simple way of vectorizing a b/w bitmap is to simply generate (up to)
|
||||
# four edges going clockwise around each opaque pixel.
|
||||
def generateEdges(bitmap):
|
||||
edges = []
|
||||
height = len(bitmap)
|
||||
width = len(bitmap[0])
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if bitmap[y][x]:
|
||||
# Insert edge to the left of the pixel?
|
||||
if x == 0 or not bitmap[y][x - 1]:
|
||||
edges.append([[x, y], [x, y + 1]])
|
||||
|
||||
# Insert edge above the pixel?
|
||||
if y == height - 1 or not bitmap[y + 1][x]:
|
||||
edges.append([[x, y + 1], [x + 1, y + 1]])
|
||||
|
||||
# Insert edge to the right of the pixel?
|
||||
if x == width - 1 or not bitmap[y][x + 1]:
|
||||
edges.append([[x + 1, y + 1], [x + 1, y]])
|
||||
|
||||
# Insert edge below the pixel?
|
||||
if y == 0 or not bitmap[y - 1][x]:
|
||||
edges.append([[x + 1, y], [x, y]])
|
||||
return edges
|
||||
|
||||
# 3) Scaling and translation of the vectorized pixels.
|
||||
def scaleEdges(edges, pixelSize, descent):
|
||||
return [[[point[0] * pixelSize, (point[1] - descent) * pixelSize] for point in edge] for edge in edges]
|
||||
|
||||
# 4) In a TTF file we have to provide contours rather than just a bunch of
|
||||
# unordered edges. If possible, consecutive edges are merged.
|
||||
def mergeContours(edges):
|
||||
edgeList = sorted(edges)
|
||||
contours = []
|
||||
|
||||
while len(edgeList) > 1:
|
||||
start = edgeList[0]
|
||||
edgeList.remove(start)
|
||||
current = start
|
||||
contour = [start[0], start[1]]
|
||||
|
||||
while current[1] != start[0]:
|
||||
next = [edge for edge in edgeList if edge[0] == current[1]][0]
|
||||
if next[1][0] == current[0][0] or next[1][1] == current[0][1]:
|
||||
contour[-1] = next[1]
|
||||
else:
|
||||
contour.append(next[1])
|
||||
current = next
|
||||
edgeList.remove(current)
|
||||
|
||||
# We don't need to include the last edge as it's implicit.
|
||||
contours.append(contour[:-1])
|
||||
|
||||
return contours
|
||||
|
||||
# TRUETYPE FONT HANDLING
|
||||
|
||||
def saveFont(glyphs, outputFileName, asXML, pixelSize, descent, fontName, copyrightYear, creator, version):
|
||||
f = TTFont()
|
||||
|
||||
vectorizedGlyphs = {glyph : [vectorizeGlyph(glyphs[glyph][0], pixelSize, descent), glyphs[glyph][1]] for glyph in glyphs}
|
||||
unicodes = [code for glyph in glyphs for code in glyphs[glyph][1]]
|
||||
|
||||
# Populate basic tables (there are a few dependencies so order matters)
|
||||
makeTable_glyf(f, vectorizedGlyphs)
|
||||
makeTable_maxp(f)
|
||||
makeTable_loca(f)
|
||||
makeTable_head(f)
|
||||
makeTable_hmtx(f)
|
||||
makeTable_hhea(f, pixelSize, descent)
|
||||
makeTable_OS2(f, pixelSize, descent, min(unicodes), max(unicodes))
|
||||
makeTable_cmap(f, glyphs)
|
||||
makeTable_name(f, fontName, "Regular", copyrightYear, creator, version)
|
||||
makeTable_post(f, pixelSize, descent)
|
||||
|
||||
if asXML:
|
||||
# We have to compile the TTFont manually when saving as TTX
|
||||
# (to auto-calculate stuff here and there)
|
||||
f["glyf"].compile(f)
|
||||
f["maxp"].compile(f)
|
||||
f["loca"].compile(f)
|
||||
f["head"].compile(f)
|
||||
f["hmtx"].compile(f)
|
||||
f["hhea"].compile(f)
|
||||
f["OS/2"].compile(f)
|
||||
f["cmap"].compile(f)
|
||||
f["name"].compile(f)
|
||||
f["post"].compile(f)
|
||||
print "PLEASE NOTE: When exporting directly to XML, the checkSumAdjustment value in the head table will be 0."
|
||||
f.saveXML(outputFileName)
|
||||
else:
|
||||
f.save(outputFileName)
|
||||
|
||||
# glyf - Glyph Data
|
||||
def makeTable_glyf(ttf, glyphs):
|
||||
|
||||
glyf = newTable("glyf")
|
||||
|
||||
glyf.glyphs = {glyph: makeTTFGlyph(glyphs[glyph][0]) for glyph in glyphs}
|
||||
glyf.glyphOrder = sorted(glyf.glyphs.keys())
|
||||
ttf["glyf"] = glyf
|
||||
ttf.glyphOrder = glyf.glyphOrder
|
||||
|
||||
def makeTTFGlyph(polygons):
|
||||
result = Glyph()
|
||||
result.numberOfContours = len(polygons)
|
||||
result.coordinates = numpy.array([coordinate for polygon in polygons for coordinate in polygon])
|
||||
result.flags = numpy.array([1] * len(result.coordinates), numpy.int8)
|
||||
result.endPtsOfContours = [sum(len(polygon) for polygon in polygons[:idx + 1]) - 1 for idx in range(len(polygons))]
|
||||
result.program = ttProgram.Program()
|
||||
result.program.assembly = []
|
||||
return result
|
||||
|
||||
# maxp - Maximum Profile
|
||||
def makeTable_maxp(ttf):
|
||||
maxp = newTable("maxp")
|
||||
|
||||
maxp.tableVersion = 0x00010000
|
||||
maxp.numGlyphs = 0 # Auto-calculated by maxp.compile()
|
||||
maxp.maxPoints = 0 # Auto-calculated by maxp.compile()
|
||||
maxp.maxContours = 0 # Auto-calculated by maxp.compile()
|
||||
maxp.maxCompositePoints = 0 # Auto-calculated by maxp.compile()
|
||||
maxp.maxCompositeContours = 0 # Auto-calculated by maxp.compile()
|
||||
maxp.maxZones = 2
|
||||
maxp.maxTwilightPoints = 0
|
||||
maxp.maxStorage = 0
|
||||
maxp.maxFunctionDefs = 0
|
||||
maxp.maxInstructionDefs = 0
|
||||
maxp.maxStackElements = 0
|
||||
maxp.maxSizeOfInstructions = 0
|
||||
maxp.maxComponentElements = 0
|
||||
maxp.maxComponentDepth = 0 # Auto-calculated by maxp.compile()
|
||||
|
||||
ttf["maxp"] = maxp
|
||||
|
||||
# loca - Index to Location
|
||||
def makeTable_loca(ttf):
|
||||
# Nothing to do here... Locations are auto-calculated by glyf.compile()
|
||||
ttf["loca"] = newTable("loca")
|
||||
|
||||
# head - Font Header
|
||||
def makeTable_head(ttf):
|
||||
head = newTable("head")
|
||||
|
||||
head.tableVersion = 1.0
|
||||
head.fontRevision = 1.0
|
||||
head.checkSumAdjustment = 0 # Auto-calculated when writing the TTF.
|
||||
head.magicNumber = 0x5F0F3CF5
|
||||
head.flags = 11 # bits 0, 1, and 3 = 1 + 2 + 8 = 11
|
||||
head.unitsPerEm = 2048
|
||||
head.created = long(time.time() - mac_epoch_diff)
|
||||
head.modified = long(time.time() - mac_epoch_diff)
|
||||
head.xMin = 0 # Auto-calculated by maxp.compile()
|
||||
head.xMax = 0 # Auto-calculated by maxp.compile()
|
||||
head.yMin = 0 # Auto-calculated by maxp.compile()
|
||||
head.yMax = 0 # Auto-calculated by maxp.compile()
|
||||
head.macStyle = 0
|
||||
head.lowestRecPPEM = 8
|
||||
head.fontDirectionHint = 0
|
||||
head.indexToLocFormat = 0
|
||||
head.glyphDataFormat = 0
|
||||
|
||||
ttf["head"] = head
|
||||
|
||||
# hmtx - Horizontal Metrics
|
||||
def makeTable_hmtx(ttf):
|
||||
hmtx = newTable("hmtx")
|
||||
hmtx.metrics = dict()
|
||||
|
||||
for glyphName in ttf["glyf"].keys():
|
||||
if glyphName == ".null":
|
||||
hmtx[".null"] = (0, 0)
|
||||
else:
|
||||
glyph = ttf["glyf"].glyphs[glyphName]
|
||||
lsb = 0
|
||||
if hasattr(glyph, "coordinates") and len(glyph.coordinates) > 0:
|
||||
lsb = min([coord[0] for coord in glyph.coordinates])
|
||||
hmtx[glyphName] = (2048, lsb)
|
||||
|
||||
ttf["hmtx"] = hmtx
|
||||
|
||||
# hhea - Horizontal Header
|
||||
def makeTable_hhea(ttf, pixelSize, descent):
|
||||
hhea = newTable("hhea")
|
||||
|
||||
hhea.tableVersion = 1.0
|
||||
hhea.ascent = (8 - descent) * pixelSize
|
||||
hhea.descent = -descent * pixelSize
|
||||
hhea.lineGap = 0
|
||||
hhea.advanceWidthMax = 0 # Auto-calculated by hhea.compile()
|
||||
hhea.minLeftSideBearing = 0 # Auto-calculated by hhea.compile()
|
||||
hhea.minRightSideBearing = 0 # Auto-calculated by hhea.compile()
|
||||
hhea.xMaxExtent = 0 # Auto-calculated by hhea.compile()
|
||||
hhea.caretSlopeRise = 1
|
||||
hhea.caretSlopeRun = 0
|
||||
hhea.caretOffset = 0
|
||||
hhea.reserved0 = 0
|
||||
hhea.reserved1 = 0
|
||||
hhea.reserved2 = 0
|
||||
hhea.reserved3 = 0
|
||||
hhea.metricDataFormat = 0
|
||||
hhea.numOfLongHorMetrics = 0 # Auto-calculated by hmtx.compile()
|
||||
|
||||
ttf["hhea"] = hhea
|
||||
|
||||
# OS/2 - OS/2 and Windows Specific Metrics
|
||||
def makeTable_OS2(ttf, pixelSize, descentPixels, minUnicode, maxUnicode):
|
||||
size = 8 * pixelSize
|
||||
descent = pixelSize * descentPixels
|
||||
|
||||
os_2 = newTable("OS/2")
|
||||
|
||||
os_2.version = 4
|
||||
os_2.xAvgCharWidth = size
|
||||
os_2.usWeightClass = 400 # Meaning "Normal (Regular)"
|
||||
os_2.usWidthClass = 5 # Meaing "Medium (normal)"
|
||||
os_2.fsType = 0 # Windows-only licensing bits...
|
||||
os_2.ySubscriptXSize = size
|
||||
os_2.ySubscriptYSize = size / 2
|
||||
os_2.ySubscriptXOffset = 0
|
||||
os_2.ySubscriptYOffset = descent
|
||||
os_2.ySuperscriptXSize = size / 2
|
||||
os_2.ySuperscriptYSize = size / 2
|
||||
os_2.ySuperscriptXOffset = 0
|
||||
os_2.ySuperscriptYOffset = size / 2
|
||||
os_2.yStrikeoutSize = pixelSize
|
||||
os_2.yStrikeoutPosition = size / 2 - descent
|
||||
os_2.sFamilyClass = 0x080a # Class ID = 8 (Sans Serif), Subclass ID = 10 (Matrix)
|
||||
panose = Panose()
|
||||
panose.bFamilyType = 2 # Text and Display
|
||||
panose.bSerifStyle = 1 # No Fit
|
||||
panose.bWeight = 6 # Medium
|
||||
panose.bProportion = 9 # Monospaced
|
||||
panose.bContrast = 6 # Medium
|
||||
panose.bStrokeVariation = 2 # Gradual/Diagonal
|
||||
panose.bArmStyle = 2 # Straight Arms/Horizontal
|
||||
panose.bLetterForm = 8 # Normal/Square
|
||||
panose.bMidline = 1 # No Fit
|
||||
panose.bXHeight = 1 # No Fit
|
||||
os_2.panose = panose
|
||||
os_2.ulUnicodeRange1 = 0b10000000000000000000000010000011 # Basic Latin + Latin-1 supplement + Greek and Coptic + General punctuation
|
||||
os_2.ulUnicodeRange2 = 0b00010000000000001111100001100000 # Arrows + Mathematical operators + Box drawing + Block elements + Geometric shapes + Misc. symbols + Dingbats + Private use area
|
||||
os_2.ulUnicodeRange3 = 0b00000000000000000000000000000000 # n/a
|
||||
os_2.ulUnicodeRange4 = 0b00000000000000000000000000000000 # n/a
|
||||
os_2.achVendID = "C=64" # :-)
|
||||
os_2.fsSelection = 64 # Regular
|
||||
os_2.fsFirstCharIndex = minUnicode
|
||||
os_2.fsLastCharIndex = maxUnicode
|
||||
os_2.sTypoAscender = size - descent
|
||||
os_2.sTypoDescender = 0 - descent
|
||||
os_2.sTypoLineGap = 0
|
||||
os_2.usWinAscent = size - descent
|
||||
os_2.usWinDescent = descent
|
||||
os_2.ulCodePageRange1 = 0b00000000000000000000000000000001 # Latin 1 (Code page 1252)
|
||||
os_2.ulCodePageRange2 = 0b11000000000000000000000000000000 # WE/Latin 1 (Code page 850) + US (Code page 437)
|
||||
os_2.sxHeight = 6 * pixelSize - descent # Guess (we don't always have a lower-case "x" at 0x78 to measure (as the standard suggests))
|
||||
os_2.sCapHeight = size - descent
|
||||
os_2.usDefaultChar = 0
|
||||
os_2.usBreakChar = 32
|
||||
os_2.usMaxContex = 0
|
||||
|
||||
ttf["OS/2"] = os_2
|
||||
|
||||
# cmap - Character to Glyph Mapping
|
||||
def makeTable_cmap(ttf, glyphs):
|
||||
unicodeCMAP = {index: glyph for glyph in glyphs if glyph in ttf["glyf"].glyphs for index in glyphs[glyph][1]}
|
||||
macRomanCMAP = {index: CMAP_MACROMAN[index] if index in CMAP_MACROMAN and CMAP_MACROMAN[index] in ttf["glyf"].glyphs else '.notdef' for index in range(256)}
|
||||
|
||||
# Unicode
|
||||
cmap4_0_3 = cmap_format_4(4)
|
||||
cmap4_0_3.platformID = 0
|
||||
cmap4_0_3.platEncID = 3
|
||||
cmap4_0_3.language = 0
|
||||
cmap4_0_3.cmap = unicodeCMAP
|
||||
|
||||
# Mac Roman
|
||||
cmap4_1_0 = cmap_format_4(4)
|
||||
cmap4_1_0.platformID = 1
|
||||
cmap4_1_0.platEncID = 0
|
||||
cmap4_1_0.language = 0
|
||||
cmap4_1_0.cmap = macRomanCMAP
|
||||
|
||||
# Windows
|
||||
cmap4_3_1 = cmap_format_4(4)
|
||||
cmap4_3_1.platformID = 3
|
||||
cmap4_3_1.platEncID = 1
|
||||
cmap4_3_1.language = 0
|
||||
cmap4_3_1.cmap = unicodeCMAP
|
||||
|
||||
cmap = newTable("cmap")
|
||||
cmap.tableVersion = 0
|
||||
cmap.tables = [cmap4_0_3, cmap4_1_0, cmap4_3_1]
|
||||
ttf["cmap"] = cmap
|
||||
|
||||
# name - Naming Table
|
||||
def makeTable_name(ttf, fontName, subFamily, copyrightYear, creator, version):
|
||||
copyright = "Copyright {0} {1}".format(copyrightYear, creator)
|
||||
fullName = "{0} {1}".format(fontName, subFamily)
|
||||
uniqueID = "{0} {1}".format(creator, fullName)
|
||||
versionText = "Version {0}".format(version)
|
||||
psFontName = "{0}-{1}".format("".join([b for b in fontName if 32 < ord(b) < 127]), creator)
|
||||
nameEntries = [copyright, fontName, subFamily, uniqueID, fullName, versionText, psFontName]
|
||||
|
||||
unicodeEnc = [0, 3, 0, "utf_16_be"]
|
||||
macintoshEnc = [1, 0, 0, "latin1"]
|
||||
microsoftEnc = [3, 1, 0x409, "utf_16_be"]
|
||||
encodings = [unicodeEnc, macintoshEnc, microsoftEnc]
|
||||
|
||||
name = newTable("name")
|
||||
name.names = [makeNameRecord(idx, entry, *conf) for idx, entry in enumerate(nameEntries) for conf in encodings]
|
||||
|
||||
ttf["name"] = name
|
||||
|
||||
def makeNameRecord(nameID, string, platformID, platEncID, langID, encoding):
|
||||
rec = NameRecord()
|
||||
rec.nameID = nameID
|
||||
rec.platformID = platformID
|
||||
rec.platEncID = platEncID
|
||||
rec.langID = langID
|
||||
rec.string = unicode(string, "utf8").encode(encoding)
|
||||
return rec
|
||||
|
||||
# post - Postscript Information
|
||||
def makeTable_post(ttf, pixelSize, descent):
|
||||
post = newTable("post")
|
||||
|
||||
post.glyphOrder = []
|
||||
post.extraNames = []
|
||||
post.mapping = dict()
|
||||
|
||||
post.formatType = 2
|
||||
post.italicAngle = 0
|
||||
post.underlinePosition = descent
|
||||
post.underlineThickness = pixelSize
|
||||
post.isFixedPitch = 1
|
||||
post.minMemType42 = 0
|
||||
post.maxMemType42 = 0
|
||||
post.minMemType1 = 0
|
||||
post.maxMemType1 = 0
|
||||
|
||||
ttf["post"] = post
|
||||
|
||||
# MAIN METHODS
|
||||
|
||||
def readCharBitmaps(fileName):
|
||||
if fileName is None:
|
||||
return []
|
||||
|
||||
print "Processing input file {0}...".format(fileName)
|
||||
data = [ord(b) for b in open(fileName).read()]
|
||||
|
||||
# Shave off magic bytes and append zeroes so the length of the remaining
|
||||
# data is an integer multiple of 8.
|
||||
data = data[2:]
|
||||
while len(data) % 8 != 0:
|
||||
data.append(0)
|
||||
|
||||
if len(data) == 0:
|
||||
print "No data found. "
|
||||
return []
|
||||
elif len(data) > 2048:
|
||||
print "More than 256 chars detected. Are you sure this is a C64 character set???"
|
||||
return []
|
||||
else:
|
||||
print "{0} glyphs loaded...".format(len(data) / 8)
|
||||
return [data[idx:idx + 8] for idx in range(0, len(data), 8)]
|
||||
|
||||
def mapGlyphs(glyphData, charset):
|
||||
return {char[1] : [glyphData[char[0]], char[2]] for char in charset if char[0] < len(glyphData)}
|
||||
|
||||
def mapAllGlyphs(existingGlyphs, newGlyphBitmaps, unicodeOffset):
|
||||
newGlyphs = {"uni{0}".format(hex(unicodeOffset + index).upper()[2:]) : [data, [unicodeOffset + index]] for index, data in enumerate(newGlyphBitmaps)}
|
||||
updates = {}
|
||||
|
||||
for newGlyph in newGlyphs:
|
||||
newBitmap = newGlyphs[newGlyph][0]
|
||||
newUnicodes = newGlyphs[newGlyph][1]
|
||||
foundGlyph = False
|
||||
for oldGlyph in existingGlyphs:
|
||||
oldBitmap = existingGlyphs[oldGlyph][0]
|
||||
oldUnicodes = existingGlyphs[oldGlyph][1]
|
||||
if oldBitmap == newBitmap:
|
||||
if oldGlyph in updates:
|
||||
updates[oldGlyph] = [oldBitmap, list(set(updates[oldGlyph][1] + newUnicodes))]
|
||||
else:
|
||||
updates[oldGlyph] = [oldBitmap, list(set(oldUnicodes + newUnicodes))]
|
||||
foundGlyph = True
|
||||
break
|
||||
if not foundGlyph:
|
||||
updates[newGlyph] = newGlyphs[newGlyph]
|
||||
|
||||
return updates
|
||||
|
||||
def processCharFiles(lowercaseInputFileName, uppercaseInputFileName, outputFileName, asXML, addMissingASCII, pixelSize, descent, addAll, fontName, copyrightYear, creator, version):
|
||||
glyphs = makeEmptyGlyphs()
|
||||
lowercaseBitmaps = []
|
||||
uppercaseBitmaps = []
|
||||
|
||||
if uppercaseInputFileName is not None:
|
||||
uppercaseBitmaps = readCharBitmaps(uppercaseInputFileName)
|
||||
glyphs.update(mapGlyphs(uppercaseBitmaps, CHAR_HI))
|
||||
|
||||
if lowercaseInputFileName is not None:
|
||||
lowercaseBitmaps = readCharBitmaps(lowercaseInputFileName)
|
||||
glyphs.update(mapGlyphs(lowercaseBitmaps, CHAR_LO))
|
||||
|
||||
if addMissingASCII:
|
||||
glyphs.update(makeMissingASCII())
|
||||
|
||||
if addAll:
|
||||
glyphs.update(mapAllGlyphs(glyphs, uppercaseBitmaps, 0xee00))
|
||||
glyphs.update(mapAllGlyphs(glyphs, lowercaseBitmaps, 0xef00))
|
||||
|
||||
saveFont(glyphs, outputFileName, asXML, pixelSize, descent, fontName, copyrightYear, creator, version)
|
||||
|
||||
# "static void main()"
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="c64ttf.py v1.0 - C64 Character Set to TrueType Converter (c) 2013 atbrask")
|
||||
|
||||
# Files
|
||||
parser.add_argument("-l", "--lowercase", help="Input 64C file with lowercase and uppercase characters.")
|
||||
parser.add_argument("-u", "--uppercase", help="Input 64C file with uppercase and graphics characters.")
|
||||
parser.add_argument("-o", "--output", help="Output filename (default is font name + '.TTF' or '.TTX')")
|
||||
parser.add_argument("-x", "--xml", help="Enable XML output (for debugging purposes)", action="store_true")
|
||||
parser.add_argument("-m", "--add-missing-ascii", help="Add non-PETSCII characters for ASCII compatibility (ie. grave accent, curly braces, vertical bar, tilde, caret, backslash, and underscore)", action="store_true")
|
||||
|
||||
# Vectorization
|
||||
parser.add_argument("-p", "--pixelsize", help="Pixel size in the resulting TTF file (default is 256)", default=256)
|
||||
parser.add_argument("-d", "--descent", help="The descent below baseline in pixels (default is 1)", default=1)
|
||||
|
||||
# Font stuff
|
||||
parser.add_argument("-a", "--add-all", help="Inserts the uppercase character set (if any) at 0xEE00...0xEEFF and the lowercase character set (if any) at 0xEF00...0xEFFF", action="store_true")
|
||||
parser.add_argument("-n", "--name", help="Font name (default is C64)")
|
||||
parser.add_argument("-y", "--copyrightyear", help="Sets copyright year (default is {0})".format(date.today().year), default=date.today().year)
|
||||
parser.add_argument("-c", "--creator", help="Font creator (default is '{0}')".format(getpass.getuser()), default=getpass.getuser())
|
||||
parser.add_argument("-v", "--version", help="Sets font version number (default is '1.00')", default="1.00")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.lowercase is None and args.uppercase is None:
|
||||
parser.print_help()
|
||||
print ""
|
||||
print "No input files! Aborting..."
|
||||
exit(1)
|
||||
|
||||
fontName = args.name
|
||||
if fontName is None:
|
||||
fontName = "C64"
|
||||
|
||||
outputFileName = args.output
|
||||
if outputFileName is None:
|
||||
if args.xml:
|
||||
outputFileName = fontName + ".ttx"
|
||||
else:
|
||||
outputFileName = fontName + ".ttf"
|
||||
|
||||
processCharFiles(args.lowercase, args.uppercase, outputFileName, args.xml, args.add_missing_ascii, int(args.pixelsize), int(args.descent), args.add_all, fontName, int(args.copyrightyear), args.creator, args.version)
|
Loading…
Add table
Reference in a new issue