You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/pitfall/pdfkit/lib/font/afm.coffee

195 lines
6.5 KiB
CoffeeScript

fs = require 'fs'
class AFMFont
@open: (filename) ->
new AFMFont fs.readFileSync filename, 'utf8'
constructor: (@contents) ->
@attributes = {}
@glyphWidths = {}
@boundingBoxes = {}
@kernPairs = {}
@parse()
@charWidths = (@glyphWidths[characters[i]] for i in [0..255])
@bbox = (+e for e in @attributes['FontBBox'].split /\s+/)
@ascender = +(@attributes['Ascender'] or 0)
@descender = +(@attributes['Descender'] or 0)
@lineGap = (@bbox[3] - @bbox[1]) - (@ascender - @descender)
parse: ->
section = ''
for line in @contents.split '\n'
if match = line.match /^Start(\w+)/
section = match[1]
continue
else if match = line.match /^End(\w+)/
section = ''
continue
switch section
when 'FontMetrics'
match = line.match /(^\w+)\s+(.*)/
key = match[1]
value = match[2]
if a = @attributes[key]
a = @attributes[key] = [a] if !Array.isArray(a)
a.push(value)
else
@attributes[key] = value
when 'CharMetrics'
continue unless /^CH?\s/.test(line)
name = line.match(/\bN\s+(\.?\w+)\s*;/)[1]
@glyphWidths[name] = +line.match(/\bWX\s+(\d+)\s*;/)[1]
when 'KernPairs'
match = line.match /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
if match
@kernPairs[match[1] + '\0' + match[2]] = parseInt match[3]
return
WIN_ANSI_MAP =
402: 131
8211: 150
8212: 151
8216: 145
8217: 146
8218: 130
8220: 147
8221: 148
8222: 132
8224: 134
8225: 135
8226: 149
8230: 133
8364: 128
8240: 137
8249: 139
8250: 155
710: 136
8482: 153
338: 140
339: 156
732: 152
352: 138
353: 154
376: 159
381: 142
382: 158
encodeText: (text) ->
res = []
for i in [0...text.length]
char = text.charCodeAt(i)
char = WIN_ANSI_MAP[char] or char
res.push char.toString(16)
return res
glyphsForString: (string) ->
glyphs = []
for i in [0...string.length]
charCode = string.charCodeAt(i)
glyphs.push @characterToGlyph charCode
return glyphs
characterToGlyph: (character) ->
return characters[WIN_ANSI_MAP[character] or character] or '.notdef'
widthOfGlyph: (glyph) ->
return @glyphWidths[glyph] or 0
getKernPair: (left, right) ->
return @kernPairs[left + '\0' + right] or 0
advancesForGlyphs: (glyphs) ->
advances = []
for left, index in glyphs
right = glyphs[index + 1]
advances.push @widthOfGlyph(left) + @getKernPair(left, right)
return advances
characters = '''
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
space exclam quotedbl numbersign
dollar percent ampersand quotesingle
parenleft parenright asterisk plus
comma hyphen period slash
zero one two three
four five six seven
eight nine colon semicolon
less equal greater question
at A B C
D E F G
H I J K
L M N O
P Q R S
T U V W
X Y Z bracketleft
backslash bracketright asciicircum underscore
grave a b c
d e f g
h i j k
l m n o
p q r s
t u v w
x y z braceleft
bar braceright asciitilde .notdef
Euro .notdef quotesinglbase florin
quotedblbase ellipsis dagger daggerdbl
circumflex perthousand Scaron guilsinglleft
OE .notdef Zcaron .notdef
.notdef quoteleft quoteright quotedblleft
quotedblright bullet endash emdash
tilde trademark scaron guilsinglright
oe .notdef zcaron ydieresis
space exclamdown cent sterling
currency yen brokenbar section
dieresis copyright ordfeminine guillemotleft
logicalnot hyphen registered macron
degree plusminus twosuperior threesuperior
acute mu paragraph periodcentered
cedilla onesuperior ordmasculine guillemotright
onequarter onehalf threequarters questiondown
Agrave Aacute Acircumflex Atilde
Adieresis Aring AE Ccedilla
Egrave Eacute Ecircumflex Edieresis
Igrave Iacute Icircumflex Idieresis
Eth Ntilde Ograve Oacute
Ocircumflex Otilde Odieresis multiply
Oslash Ugrave Uacute Ucircumflex
Udieresis Yacute Thorn germandbls
agrave aacute acircumflex atilde
adieresis aring ae ccedilla
egrave eacute ecircumflex edieresis
igrave iacute icircumflex idieresis
eth ntilde ograve oacute
ocircumflex otilde odieresis divide
oslash ugrave uacute ucircumflex
udieresis yacute thorn ydieresis
'''.split(/\s+/)
module.exports = AFMFont