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/embedded.coffee

157 lines
4.2 KiB
CoffeeScript

PDFFont = require '../font'
PDFObject = require '../object'
class EmbeddedFont extends PDFFont
constructor: (@document, @font, @id) ->
@subset = @font.createSubset()
@unicode = [[0]]
@widths = [@font.getGlyph(0).advanceWidth]
@name = @font.postscriptName
@scale = 1000 / @font.unitsPerEm
@ascender = @font.ascent * @scale
@descender = @font.descent * @scale
@lineGap = @font.lineGap * @scale
@bbox = @font.bbox
encode: (text, features) ->
{glyphs, positions} = @font.layout text, features
res = []
for glyph, i in glyphs
gid = @subset.includeGlyph glyph.id
res.push ('0000' + gid.toString(16)).slice(-4)
@widths[gid] ?= glyph.advanceWidth * @scale
@unicode[gid] ?= glyph.codePoints
for key of positions[i]
positions[i][key] *= @scale
positions[i].advanceWidth = glyph.advanceWidth * @scale
return [res, positions]
widthOfString: (string, size, features) ->
width = @font.layout(string, features).advanceWidth
scale = size / @font.unitsPerEm
return width * scale
embed: ->
isCFF = @subset.cff?
fontFile = @document.ref()
if isCFF
fontFile.data.Subtype = 'CIDFontType0C'
@subset.encodeStream().pipe(fontFile)
familyClass = (@font['OS/2']?.sFamilyClass or 0) >> 8
flags = 0
flags |= 1 << 0 if @font.post.isFixedPitch
flags |= 1 << 1 if 1 <= familyClass <= 7
flags |= 1 << 2 # assume the font uses non-latin characters
flags |= 1 << 3 if familyClass is 10
flags |= 1 << 6 if @font.head.macStyle.italic
# generate a random tag (6 uppercase letters. 65 is the char code for 'A')
tag = (String.fromCharCode Math.random() * 26 + 65 for i in [0...6]).join ''
name = tag + '+' + @font.postscriptName
bbox = @font.bbox
descriptor = @document.ref
Type: 'FontDescriptor'
FontName: name
Flags: flags
FontBBox: [bbox.minX * @scale, bbox.minY * @scale, bbox.maxX * @scale, bbox.maxY * @scale]
ItalicAngle: @font.italicAngle
Ascent: @ascender
Descent: @descender
CapHeight: (@font.capHeight or @font.ascent) * @scale
XHeight: (@font.xHeight or 0) * @scale
StemV: 0 # not sure how to calculate this
if isCFF
descriptor.data.FontFile3 = fontFile
else
descriptor.data.FontFile2 = fontFile
descriptor.end()
descendantFont = @document.ref
Type: 'Font'
Subtype: if isCFF then 'CIDFontType0' else 'CIDFontType2'
BaseFont: name
CIDSystemInfo:
Registry: new String 'Adobe'
Ordering: new String 'Identity'
Supplement: 0
FontDescriptor: descriptor
W: [0, @widths]
descendantFont.end()
@dictionary.data =
Type: 'Font'
Subtype: 'Type0'
BaseFont: name
Encoding: 'Identity-H'
DescendantFonts: [descendantFont]
ToUnicode: @toUnicodeCmap()
@dictionary.end()
toHex = (codePoints...) ->
codes = for code in codePoints
('0000' + code.toString(16)).slice(-4)
return codes.join ''
# Maps the glyph ids encoded in the PDF back to unicode strings
# Because of ligature substitutions and the like, there may be one or more
# unicode characters represented by each glyph.
toUnicodeCmap: ->
cmap = @document.ref()
entries = []
for codePoints in @unicode
encoded = []
# encode codePoints to utf16
for value in codePoints
if value > 0xffff
value -= 0x10000
encoded.push toHex value >>> 10 & 0x3ff | 0xd800
value = 0xdc00 | value & 0x3ff
encoded.push toHex value
entries.push "<#{encoded.join ' '}>"
cmap.end """
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo <<
/Registry (Adobe)
/Ordering (UCS)
/Supplement 0
>> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000><ffff>
endcodespacerange
1 beginbfrange
<0000> <#{toHex entries.length - 1}> [#{entries.join ' '}]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end
"""
return cmap
module.exports = EmbeddedFont