Files
shields/lib/text-measurer.js
Paul Melnikow 7a664ca3e8 Run prettier (#1866)
Merging this separately so the commit with the tooling change is readable. This is a follow-on to #1167 which turned prettier on.
2018-08-08 17:57:14 -04:00

95 lines
2.5 KiB
JavaScript

'use strict'
const PDFDocument = require('pdfkit')
class PDFKitTextMeasurer {
constructor(fontPath, fallbackFontPath) {
this.document = new PDFDocument({
size: 'A4',
layout: 'landscape',
}).fontSize(11)
try {
this.document.font(fontPath)
} catch (e) {
if (fallbackFontPath) {
console.error(
`Text-width computation may be incorrect. Unable to load font at ${fontPath}. Using fallback font ${fallbackFontPath} instead.`
)
this.document.font(fallbackFontPath)
} else {
console.error('No fallback font set.')
throw e
}
}
}
widthOf(str) {
return this.document.widthOfString(str)
}
}
class QuickTextMeasurer {
constructor(fontPath, fallbackFontPath) {
this.baseMeasurer = new PDFKitTextMeasurer(fontPath, fallbackFontPath)
// This will be a Map of characters -> numbers.
this.characterWidths = new Map()
// This will be Map of Maps of characters -> numbers.
this.kerningPairs = new Map()
this._prepare()
}
static printableAsciiCharacters() {
const printableRange = [32, 126]
const length = printableRange[1] - printableRange[0] + 1
return Array.from({ length }, (value, i) => printableRange[0] + i).map(
charCode => String.fromCharCode(charCode)
)
}
_prepare() {
const charactersToCache = this.constructor.printableAsciiCharacters()
charactersToCache.forEach(char => {
this.characterWidths.set(char, this.baseMeasurer.widthOf(char))
this.kerningPairs.set(char, new Map())
})
charactersToCache.forEach(first => {
charactersToCache.forEach(second => {
const individually =
this.characterWidths.get(first) + this.characterWidths.get(second)
const asPair = this.baseMeasurer.widthOf(`${first}${second}`)
const kerningAdjustment = asPair - individually
this.kerningPairs.get(first).set(second, kerningAdjustment)
})
})
}
widthOf(str) {
const { characterWidths, kerningPairs } = this
let result = 0
let previous = null
for (const character of str) {
if (!characterWidths.has(character)) {
// Bail.
return this.baseMeasurer.widthOf(str)
}
result += characterWidths.get(character)
if (previous !== null) {
result += kerningPairs.get(previous).get(character)
}
previous = character
}
return result
}
}
module.exports = {
PDFKitTextMeasurer,
QuickTextMeasurer,
}