Skip to content

Commit 03d2283

Browse files
committed
textkit support
1 parent b9fc5b0 commit 03d2283

File tree

3 files changed

+36
-44
lines changed

3 files changed

+36
-44
lines changed

lib/font.coffee

+18-15
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,54 @@ fontkit = require 'fontkit'
22

33
class PDFFont
44
@open: (document, src, family, id) ->
5-
if typeof src is 'string'
5+
if src.constructor.name is 'TTFFont'
6+
font = src
7+
8+
else if typeof src is 'string'
69
if StandardFont.isStandardFont src
710
return new StandardFont document, src, id
8-
11+
912
font = fontkit.openSync src, family
10-
13+
1114
else if Buffer.isBuffer(src)
1215
font = fontkit.create src, family
13-
16+
1417
else if src instanceof Uint8Array
1518
font = fontkit.create new Buffer(src), family
16-
19+
1720
else if src instanceof ArrayBuffer
1821
font = fontkit.create new Buffer(new Uint8Array(src)), family
19-
22+
2023
if not font?
2124
throw new Error 'Not a supported font format or standard PDF font.'
22-
25+
2326
return new EmbeddedFont document, font, id
24-
27+
2528
constructor: ->
2629
throw new Error 'Cannot construct a PDFFont directly.'
27-
30+
2831
encode: (text) ->
2932
throw new Error 'Must be implemented by subclasses'
30-
33+
3134
widthOfString: (text) ->
3235
throw new Error 'Must be implemented by subclasses'
33-
36+
3437
ref: ->
3538
@dictionary ?= @document.ref()
36-
39+
3740
finalize: ->
3841
return if @embedded or not @dictionary?
3942

4043
@embed()
4144
@embedded = true
42-
45+
4346
embed: ->
4447
throw new Error 'Must be implemented by subclasses'
45-
48+
4649
lineHeight: (size, includeGap = false) ->
4750
gap = if includeGap then @lineGap else 0
4851
(@ascender + gap - @descender) / 1000 * size
49-
52+
5053
module.exports = PDFFont
5154

5255
StandardFont = require './font/standard'

lib/font/embedded.coffee

+11
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ class EmbeddedFont extends PDFFont
7676

7777
return [res, positions]
7878

79+
encode2: (glyphs) ->
80+
res = []
81+
for glyph, i in glyphs
82+
gid = @subset.includeGlyph glyph.id
83+
res.push ('0000' + gid.toString(16)).slice(-4)
84+
85+
@widths[gid] ?= glyph.advanceWidth * @scale
86+
# @unicode[gid] ?= glyph.codePoints
87+
88+
return res
89+
7990
widthOfString: (string, size, features) ->
8091
width = @layout(string, features, true).advanceWidth
8192
scale = size / 1000

lib/mixins/text.coffee

+7-29
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,11 @@ module.exports =
211211
@stroke()
212212
@restore()
213213

214+
_addGlyphs: (glyphs, positions, x, y, options = {}) ->
214215
# flip coordinate system
215216
@save()
216217
@transform 1, 0, 0, -1, 0, @page.height
217-
y = @page.height - y - (@_font.ascender / 1000 * @_fontSize)
218+
y = @page.height - y# - (@_font.ascender / 1000 * @_fontSize)
218219

219220
# add current font to page if necessary
220221
@page.fonts[@_font.id] ?= @_font.ref()
@@ -233,33 +234,10 @@ module.exports =
233234
@addContent "#{mode} Tr" if mode
234235

235236
# Character spacing
236-
@addContent "#{number(characterSpacing)} Tc" if characterSpacing
237+
# @addContent "#{number(characterSpacing)} Tc" if characterSpacing
237238

238239
# Add the actual text
239-
# If we have a word spacing value, we need to encode each word separately
240-
# since the normal Tw operator only works on character code 32, which isn't
241-
# used for embedded fonts.
242-
if wordSpacing
243-
words = text.trim().split(/\s+/)
244-
wordSpacing += @widthOfString(' ') + characterSpacing
245-
wordSpacing *= 1000 / @_fontSize
246-
247-
encoded = []
248-
positions = []
249-
for word in words
250-
[encodedWord, positionsWord] = @_font.encode(word, options.features)
251-
encoded.push encodedWord...
252-
positions.push positionsWord...
253-
254-
# add the word spacing to the end of the word
255-
# clone object because of cache
256-
space = {}
257-
space[key] = val for key, val of positions[positions.length - 1]
258-
space.xAdvance += wordSpacing
259-
positions[positions.length - 1] = space
260-
else
261-
[encoded, positions] = @_font.encode(text, options.features)
262-
240+
encoded = @_font.encode2(glyphs)
263241
scale = @_fontSize / 1000
264242
commands = []
265243
last = 0
@@ -269,7 +247,7 @@ module.exports =
269247
addSegment = (cur) =>
270248
if last < cur
271249
hex = encoded.slice(last, cur).join ''
272-
advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth
250+
advance = positions[cur - 1].xAdvance * (1000 / @_fontSize) - glyphs[cur - 1].advanceWidth * (1000 / @_font.font.unitsPerEm)
273251
commands.push "<#{hex}> #{number(-advance)}"
274252
275253
last = cur
@@ -301,10 +279,10 @@ module.exports =
301279
hadOffset = no
302280
303281
# Group segments that don't have any advance adjustments
304-
unless pos.xAdvance - pos.advanceWidth is 0
282+
unless pos.xAdvance - glyphs[i].advanceWidth * (@_fontSize / @_font.font.unitsPerEm) is 0
305283
addSegment i + 1
306284
307-
x += pos.xAdvance * scale
285+
x += pos.xAdvance
308286
309287
# Flush any remaining commands
310288
flush i

0 commit comments

Comments
 (0)