font-subseter
Advanced tools
Comparing version 1.3.4 to 1.3.5
@@ -166,3 +166,4 @@ /** | ||
width = 300, | ||
lang = 'zh' | ||
lang = 'zh', | ||
defaultFont | ||
} = {}) { | ||
@@ -195,10 +196,20 @@ const font = this.parseFont(buffer); | ||
text = text.trim() || 'Unknow font name'; | ||
// 将文本内容拆分,单独计算字形路径 | ||
const chars = [...text]; | ||
const x = Math.floor(fontSize / 4); | ||
const y = Math.floor((font.ascender / font.unitsPerEm) * fontSize); | ||
const path = font.getPath(text, x, y, fontSize); | ||
const pathDataStr = String(path.toPathData()).trim(); | ||
// const y = Math.floor((font.ascender / font.unitsPerEm) * fontSize); | ||
const glyphs = chars.map(char => { | ||
let glyph = font.charToGlyph(char); | ||
glyph.unitsPerEm = font.unitsPerEm; | ||
if(glyph.name === '.notdef' && defaultFont) { | ||
glyph = defaultFont.charToGlyph(char); | ||
glyph.unitsPerEm = defaultFont.unitsPerEm; | ||
} | ||
return glyph; | ||
}).filter(glyph => glyph.name !== '.notdef'); | ||
// 某些情况下无法创建路径 (eg. 新蒂金钟体, 新蒂雪山体) | ||
if(!pathDataStr) { | ||
if(glyphs.length === 0) { | ||
throw new Error('Parse path error'); | ||
@@ -208,39 +219,54 @@ } | ||
/** | ||
* 计算缩略图偏移高度 | ||
* step1. 上面先随便拿个 y 来生成缩略图。 | ||
* 计算缩略图偏移高度,以第一个字符作为基准 | ||
* step1. 上面先拿个 y 来生成缩略图。 | ||
* step2. 生成完图以后,可以根据 bbox 计算出缩略图所占的高度(contentHeight) 和 目前距离顶部的高度(bbox.y1)。 | ||
* step3. 上下的 gap 高度 = (总高度(height) - 缩略图所占的高度(contentHeight))/ 2。 | ||
* step4. 最后需要修正高度 = gap - 目前距离顶部的高度(bbox.y1)。 | ||
* step4. 最后需要修正高度 offsetY = gap - 目前距离顶部的高度(bbox.y1)。 | ||
* step5. 后续的字符使用相同的偏移高度 offsetY | ||
*/ | ||
const bbox = path.getBoundingBox(); | ||
const contentHeight = bbox.y2 - bbox.y1; | ||
let bboxWidth = 0; | ||
const firstPath = glyphs[0].getPath(0, 0, fontSize); | ||
const firstBbox = firstPath.getBoundingBox(); | ||
const contentHeight = firstBbox.y2 - firstBbox.y1; | ||
const gap = (height - contentHeight) / 2; | ||
const offsetY = -Math.floor(gap - firstBbox.y1); | ||
// Fit viewbox width | ||
width = Math.ceil(Math.max(width, bbox.x2 + x)); | ||
const pathDatas = glyphs.map((glyph, i) => { | ||
const fontScale = 1 / glyph.unitsPerEm * fontSize | ||
const path = glyph.getPath(0, 0, fontSize); | ||
const bbox = path.getBoundingBox(); | ||
const leftSideBearing = glyph.leftSideBearing * fontScale; | ||
const offsets = [ | ||
Math.floor(bbox.x1 - leftSideBearing - bboxWidth), | ||
offsetY | ||
]; | ||
const viewBox = `0 0 ${width} ${height}`; | ||
const pathData = new PathData(pathDataStr); | ||
const offsets = [ | ||
Math.floor(bbox.x1 - x), | ||
-Math.floor(gap - bbox.y1) | ||
]; | ||
const pathDataStr = String(path.toPathData()).trim(); | ||
const pathData = new PathData(pathDataStr); | ||
// shim: opentype.js 导出时路径时有一定偏移值,此处修正 | ||
pathData.paths.forEach(path => { | ||
path.actions.forEach(({ args }) => { | ||
for(let len = args.length, i = 0; i < len; i += 2) { | ||
let j = i % 2; | ||
args[i] -= offsets[j]; | ||
args[i + 1] -= offsets[j + 1]; | ||
// 优化小数显示 | ||
args[i] = fitFloat(args[i]); | ||
args[i + 1] = fitFloat(args[i + 1]); | ||
} | ||
// shim: opentype.js 导出时路径时有一定偏移值,此处修正 | ||
pathData.paths.forEach(path => { | ||
path.actions.forEach(({ args }) => { | ||
for(let len = args.length, i = 0; i < len; i += 2) { | ||
let j = i % 2; | ||
args[i] -= offsets[j]; | ||
args[i + 1] -= offsets[j + 1]; | ||
// 优化小数显示 | ||
args[i] = fitFloat(args[i]); | ||
args[i + 1] = fitFloat(args[i + 1]); | ||
} | ||
}); | ||
}); | ||
// 计算新的 bbox 宽度 | ||
bboxWidth += glyph.advanceWidth * fontScale; | ||
return pathData; | ||
}); | ||
// Fit viewbox width | ||
width = Math.ceil(Math.max(width, bboxWidth + x)); | ||
const viewBox = `0 0 ${width} ${height}`; | ||
const svgPaths = pathData.toString(); | ||
const svgPaths = pathDatas.map(pathData => pathData.toString()).join('\n'); | ||
const xmlns = 'http://www.w3.org/2000/svg'; | ||
@@ -247,0 +273,0 @@ const svg = `<svg viewBox="${viewBox}" xmlns="${xmlns}">${svgPaths}</svg>`; |
{ | ||
"name": "font-subseter", | ||
"version": "1.3.4", | ||
"version": "1.3.5", | ||
"description": "A font subsetting tool based on opentype.js", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
647
25904
14