mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 16:59:27 +08:00
This commit is contained in:
1 parent
e5e07f92cd
commit
853ffc6327
9 files changed
+70
-183
No files matched your search
+7
-108
@@ -1,21 +1,4 @@
|
|||||||
const MM_TO_PX = 96 / 25.4;
|
const MM_TO_PX = 96 / 25.4;
|
||||||
const COMMON_FONT_NAMES = [
|
|
||||||
"SimSun",
|
|
||||||
"NSimSun",
|
|
||||||
"SimHei",
|
|
||||||
"KaiTi",
|
|
||||||
"FangSong",
|
|
||||||
"Microsoft YaHei",
|
|
||||||
"PingFang SC",
|
|
||||||
"Noto Sans CJK SC",
|
|
||||||
"Source Han Sans SC",
|
|
||||||
"FZXiaoBiaoSong-B05",
|
|
||||||
"Arial",
|
|
||||||
"Arial Black",
|
|
||||||
"Helvetica",
|
|
||||||
"Courier New",
|
|
||||||
"Times New Roman",
|
|
||||||
];
|
|
||||||
const LOCAL_FONT_LOAD_LIMIT = 16;
|
const LOCAL_FONT_LOAD_LIMIT = 16;
|
||||||
const FONT_DATABASE = "ofdgo";
|
const FONT_DATABASE = "ofdgo";
|
||||||
const fontChannel = typeof BroadcastChannel === "function" ? new BroadcastChannel(FONT_DATABASE) : null;
|
const fontChannel = typeof BroadcastChannel === "function" ? new BroadcastChannel(FONT_DATABASE) : null;
|
||||||
@@ -38,7 +21,7 @@ const WASM_CALLBACKS = [
|
|||||||
"ofdgoExportFormats",
|
"ofdgoExportFormats",
|
||||||
"ofdgoExportPage",
|
"ofdgoExportPage",
|
||||||
"ofdgoExportPDF",
|
"ofdgoExportPDF",
|
||||||
"ofdgoFontSystemNames",
|
"ofdgoFontFileMatches",
|
||||||
];
|
];
|
||||||
|
|
||||||
let wasmPromise = null;
|
let wasmPromise = null;
|
||||||
@@ -807,12 +790,10 @@ async function loadDocumentLocalFonts(available, openSeq = state.openSeq) {
|
|||||||
renderFontList();
|
renderFontList();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const docWanted = fontNameKeys(docNames);
|
|
||||||
const docLoadLimit = Math.min(LOCAL_FONT_LOAD_LIMIT, Math.max(4, docNames.length * 3));
|
const docLoadLimit = Math.min(LOCAL_FONT_LOAD_LIMIT, Math.max(4, docNames.length * 3));
|
||||||
let selected = selectLocalFonts(available, docWanted, docLoadLimit);
|
let selected = selectLocalFonts(available, docNames, docLoadLimit);
|
||||||
if (!selected.length) {
|
if (!selected.length) {
|
||||||
const fallbackWanted = fontNameKeys(COMMON_FONT_NAMES);
|
selected = selectLocalFonts(available, [], 6);
|
||||||
selected = selectLocalFonts(available, fallbackWanted, 6);
|
|
||||||
}
|
}
|
||||||
const emptyStatus = available.length === 0 ? "未读取到系统字体" : "未匹配到文档所需字体";
|
const emptyStatus = available.length === 0 ? "未读取到系统字体" : "未匹配到文档所需字体";
|
||||||
const fonts = [];
|
const fonts = [];
|
||||||
@@ -852,26 +833,10 @@ function uniqueLocalFonts(fonts) {
|
|||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLocalFonts(fonts, wanted, limit) {
|
function selectLocalFonts(fonts, names, limit) {
|
||||||
const ranked = [];
|
const available = new Map(uniqueLocalFonts(fonts).map((font) => [localFontName(font), font]));
|
||||||
for (const font of fonts) {
|
const matched = callWASM("ofdgoFontFileMatches", [...available.keys()], names);
|
||||||
const rank = localFontMatchRank(font, wanted);
|
return matched.slice(0, limit).map((name) => available.get(name));
|
||||||
if (!rank) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ranked.push({
|
|
||||||
font,
|
|
||||||
rank,
|
|
||||||
styleRank: localFontStyleRank(font),
|
|
||||||
name: normalizeFontName(localFontName(font)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ranked.sort((a, b) => (
|
|
||||||
a.rank - b.rank ||
|
|
||||||
a.styleRank - b.styleRank ||
|
|
||||||
a.name.localeCompare(b.name)
|
|
||||||
));
|
|
||||||
return uniqueLocalFonts(ranked.map((item) => item.font)).slice(0, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fontData(fonts) {
|
async function fontData(fonts) {
|
||||||
@@ -967,72 +932,6 @@ function externalDocumentFontNames() {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fontNameKeys(names) {
|
|
||||||
const keys = new Set();
|
|
||||||
for (const name of fontSystemNames(names)) {
|
|
||||||
const key = normalizeFontName(name);
|
|
||||||
if (key) {
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fontSystemNames(names) {
|
|
||||||
const source = (Array.isArray(names) ? names : [])
|
|
||||||
.map((name) => String(name || "").trim())
|
|
||||||
.filter((name) => name !== "");
|
|
||||||
if (!source.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (state.ready && !state.wasmExited && typeof globalThis.ofdgoFontSystemNames === "function") {
|
|
||||||
try {
|
|
||||||
const names = callWASM("ofdgoFontSystemNames", source);
|
|
||||||
if (Array.isArray(names)) {
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
function localFontMatchRank(font, wanted) {
|
|
||||||
let best = 0;
|
|
||||||
for (const name of [font.family, font.fullName, font.postscriptName, font.style]) {
|
|
||||||
const key = normalizeFontName(name);
|
|
||||||
if (!key) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (const wantedKey of wanted) {
|
|
||||||
let rank = 0;
|
|
||||||
if (key === wantedKey) {
|
|
||||||
rank = 1;
|
|
||||||
} else if (key.startsWith(wantedKey) || wantedKey.startsWith(key)) {
|
|
||||||
rank = 2;
|
|
||||||
} else if (key.includes(wantedKey) || wantedKey.includes(key)) {
|
|
||||||
rank = 3;
|
|
||||||
}
|
|
||||||
if (rank && (!best || rank < best)) {
|
|
||||||
best = rank;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
|
|
||||||
function localFontStyleRank(font) {
|
|
||||||
const key = normalizeFontName(font.style);
|
|
||||||
if (!key || key === "regular" || key === "normal") {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (key.includes("bold") || key.includes("italic")) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function localFontName(font) {
|
function localFontName(font) {
|
||||||
const name = font.fullName || font.family || font.postscriptName || "local-font";
|
const name = font.fullName || font.family || font.postscriptName || "local-font";
|
||||||
return `${name}.ttf`;
|
return `${name}.ttf`;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ go 1.26.0
|
|||||||
require (
|
require (
|
||||||
github.com/tdewolff/canvas v0.0.0-20260901160717-dae8cd8e19a7
|
github.com/tdewolff/canvas v0.0.0-20260901160717-dae8cd8e19a7
|
||||||
github.com/tdewolff/font v0.0.0-20260822205238-d0d2f004b117
|
github.com/tdewolff/font v0.0.0-20260822205238-d0d2f004b117
|
||||||
github.com/xiaoqidun/jbig2 v0.0.0-20260909060133-14ddd3628846
|
github.com/xiaoqidun/jbig2 v0.0.0-20260909105725-e4eceed095da
|
||||||
golang.org/x/image v0.46.0
|
golang.org/x/image v0.46.0
|
||||||
golang.org/x/text v0.42.0
|
golang.org/x/text v0.42.0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
|
|||||||
github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E=
|
github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E=
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ=
|
github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ=
|
||||||
github.com/xiaoqidun/jbig2 v0.0.0-20260909060133-14ddd3628846 h1:xbfsQuNR/xaZiopLQE6EQ98hvkISg6OknH4CkeGwh7I=
|
github.com/xiaoqidun/jbig2 v0.0.0-20260909105725-e4eceed095da h1:qvwltcRzcntuKMFH/qlABdat9PsCsAjq7dcwKINVijA=
|
||||||
github.com/xiaoqidun/jbig2 v0.0.0-20260909060133-14ddd3628846/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
github.com/xiaoqidun/jbig2 v0.0.0-20260909105725-e4eceed095da/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func RunWASM() {
|
|||||||
registerCallback("ofdgoExportFormats", exportFormats)
|
registerCallback("ofdgoExportFormats", exportFormats)
|
||||||
registerCallback("ofdgoExportPage", exportPage)
|
registerCallback("ofdgoExportPage", exportPage)
|
||||||
registerCallback("ofdgoExportPDF", exportPDF)
|
registerCallback("ofdgoExportPDF", exportPDF)
|
||||||
registerCallback("ofdgoFontSystemNames", fontSystemNames)
|
registerCallback("ofdgoFontFileMatches", fontFileMatches)
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,12 +224,13 @@ func bytesToJS(data []byte) js.Value {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// fontSystemNames 获取系统字体名称
|
// fontFileMatches 匹配浏览器字体文件名称
|
||||||
// 入参: args 浏览器参数
|
// 入参: args 浏览器参数
|
||||||
// 返回: any 系统字体名称, error 错误信息
|
// 返回: any 匹配的字体文件名称, error 错误信息
|
||||||
func fontSystemNames(args []js.Value) (any, error) {
|
func fontFileMatches(args []js.Value) (any, error) {
|
||||||
names := stringsFromJS(jsArg(args, 0))
|
files := stringsFromJS(jsArg(args, 0))
|
||||||
return ofdgo.FontSystemNames(names...), nil
|
names := stringsFromJS(jsArg(args, 1))
|
||||||
|
return ofdgo.FontFileMatches(files, false, false, names...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// bytesFromJS 从浏览器值读取二进制数据
|
// bytesFromJS 从浏览器值读取二进制数据
|
||||||
|
|||||||
+23
-21
@@ -129,34 +129,37 @@ func (fsys *FontFS) MatchStyle(bold, italic bool, names ...string) (string, bool
|
|||||||
if matches := fsys.matchPatternsStyle(fontFilePatterns(names...), bold, italic); len(matches) > 0 {
|
if matches := fsys.matchPatternsStyle(fontFilePatterns(names...), bold, italic); len(matches) > 0 {
|
||||||
return matches[0], true
|
return matches[0], true
|
||||||
}
|
}
|
||||||
if matches := fsys.fallbackFonts(); len(matches) > 0 {
|
if matches := fsys.fallbackFonts(bold, italic); len(matches) > 0 {
|
||||||
return matches[0], false
|
return matches[0], false
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
// match 匹配字体文件模式
|
// FontFileMatches 匹配指定样式的字体文件名称
|
||||||
// 入参: pattern 匹配模式
|
// 入参: files 可用字体文件名, bold 是否粗体, italic 是否斜体, names 字体名称,留空匹配默认回退字体
|
||||||
// 返回: []string 字体文件列表
|
// 返回: []string 按优先级排列的匹配文件名
|
||||||
func (fsys *FontFS) match(pattern string) []string {
|
func FontFileMatches(files []string, bold, italic bool, names ...string) []string {
|
||||||
return fsys.matchStyle(pattern, false, false)
|
if len(names) == 0 {
|
||||||
}
|
names = fontDefaultSystemNames()
|
||||||
|
}
|
||||||
// matchStyle 匹配指定样式的字体文件模式
|
return fontFileMatches(fontFileCandidates(files, path.Base), fontFilePatterns(names...), bold, italic)
|
||||||
// 入参: pattern 匹配模式, bold 是否粗体, italic 是否斜体
|
|
||||||
// 返回: []string 字体文件列表
|
|
||||||
func (fsys *FontFS) matchStyle(pattern string, bold, italic bool) []string {
|
|
||||||
return fsys.matchPatternsStyle([]string{pattern}, bold, italic)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchPatternsStyle 匹配指定样式的字体文件模式
|
// matchPatternsStyle 匹配指定样式的字体文件模式
|
||||||
// 入参: patterns 匹配模式列表, bold 是否粗体, italic 是否斜体
|
// 入参: patterns 匹配模式列表, bold 是否粗体, italic 是否斜体
|
||||||
// 返回: []string 字体文件列表
|
// 返回: []string 字体文件列表
|
||||||
func (fsys *FontFS) matchPatternsStyle(patterns []string, bold, italic bool) []string {
|
func (fsys *FontFS) matchPatternsStyle(patterns []string, bold, italic bool) []string {
|
||||||
matches := make([]fontFileMatch, 0, len(fsys.candidates))
|
return fontFileMatches(fsys.candidates, patterns, bold, italic)
|
||||||
seen := make(map[string]int, len(fsys.candidates))
|
}
|
||||||
|
|
||||||
|
// fontFileMatches 匹配字体文件候选
|
||||||
|
// 入参: candidates 字体候选, patterns 匹配模式, bold 是否粗体, italic 是否斜体
|
||||||
|
// 返回: []string 按优先级排列的匹配文件名
|
||||||
|
func fontFileMatches(candidates []fontFileCandidate, patterns []string, bold, italic bool) []string {
|
||||||
|
matches := make([]fontFileMatch, 0, len(candidates))
|
||||||
|
seen := make(map[string]int, len(candidates))
|
||||||
for _, matcher := range newFontPatternMatchers(patterns) {
|
for _, matcher := range newFontPatternMatchers(patterns) {
|
||||||
for _, file := range fsys.candidates {
|
for _, file := range candidates {
|
||||||
rank := matcher.rankCandidate(file)
|
rank := matcher.rankCandidate(file)
|
||||||
appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic)
|
appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic)
|
||||||
}
|
}
|
||||||
@@ -166,12 +169,11 @@ func (fsys *FontFS) matchPatternsStyle(patterns []string, bold, italic bool) []s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fallbackFonts 获取回退字体文件
|
// fallbackFonts 获取回退字体文件
|
||||||
|
// 入参: bold 是否粗体, italic 是否斜体
|
||||||
// 返回: []string 字体文件列表
|
// 返回: []string 字体文件列表
|
||||||
func (fsys *FontFS) fallbackFonts() []string {
|
func (fsys *FontFS) fallbackFonts(bold, italic bool) []string {
|
||||||
for _, item := range fontFallbackFiles {
|
if matches := fsys.matchPatternsStyle(fontFilePatterns(fontDefaultSystemNames()...), bold, italic); len(matches) > 0 {
|
||||||
if matches := fsys.match(item); len(matches) > 0 {
|
return matches
|
||||||
return []string{matches[0]}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(fsys.names) > 0 {
|
if len(fsys.names) > 0 {
|
||||||
return []string{fsys.names[0]}
|
return []string{fsys.names[0]}
|
||||||
|
|||||||
+1
-11
@@ -189,17 +189,7 @@ func (r *Renderer) fontInfo(font Font) FontInfo {
|
|||||||
// 返回: []string 字体文件列表
|
// 返回: []string 字体文件列表
|
||||||
func fontFSMatchesStyle(fsys fs.FS, patterns []string, bold, italic bool) []string {
|
func fontFSMatchesStyle(fsys fs.FS, patterns []string, bold, italic bool) []string {
|
||||||
names, _ := fs.Glob(fsys, "*")
|
names, _ := fs.Glob(fsys, "*")
|
||||||
candidates := fontFileCandidates(names, path.Base)
|
return fontFileMatches(fontFileCandidates(names, path.Base), patterns, bold, italic)
|
||||||
matches := make([]fontFileMatch, 0, len(candidates))
|
|
||||||
seen := make(map[string]int, len(candidates))
|
|
||||||
for _, matcher := range newFontPatternMatchers(patterns) {
|
|
||||||
for _, file := range candidates {
|
|
||||||
rank := matcher.rankCandidate(file)
|
|
||||||
appendFontFileMatch(&matches, seen, matcher, file, rank, bold, italic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortFontFileMatches(matches)
|
|
||||||
return fontFileMatchNames(matches)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fontUsage 统计文档字体使用次数
|
// fontUsage 统计文档字体使用次数
|
||||||
|
|||||||
+21
-27
@@ -152,26 +152,29 @@ func (r *Renderer) fontSources(fontID string, font *Font, style canvas.FontStyle
|
|||||||
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFS, index: index, name: name, exact: true})
|
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFS, index: index, name: name, exact: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !canLoadSystemFonts() {
|
if canLoadSystemFonts() {
|
||||||
for index, fsys := range r.fontFS {
|
systemDirs := systemFontDirs()
|
||||||
names, _ := fs.Glob(fsys, "*")
|
for _, name := range []string{font.FamilyName, font.FontName} {
|
||||||
for _, name := range names {
|
for _, systemName := range fontSystemNames(name) {
|
||||||
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFS, index: index, name: name})
|
systemPatterns := fontFilePatterns(systemName)
|
||||||
|
for _, dir := range systemDirs {
|
||||||
|
for _, match := range r.matchFontFiles(dir, systemPatterns, bold, italic) {
|
||||||
|
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFile, name: match, exact: true})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceSystem, name: systemName, exact: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.fontSourceCache[fontID] = sources
|
|
||||||
return sources
|
|
||||||
}
|
}
|
||||||
systemDirs := systemFontDirs()
|
for index, fsys := range r.fontFS {
|
||||||
for _, name := range []string{font.FamilyName, font.FontName} {
|
for _, name := range fontFSMatchesStyle(fsys, fontFilePatterns(fontDefaultSystemNames()...), bold, italic) {
|
||||||
for _, systemName := range fontSystemNames(name) {
|
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFS, index: index, name: name})
|
||||||
systemPatterns := fontFilePatterns(systemName)
|
}
|
||||||
for _, dir := range systemDirs {
|
}
|
||||||
for _, match := range r.matchFontFiles(dir, systemPatterns, bold, italic) {
|
for index, fsys := range r.fontFS {
|
||||||
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFile, name: match, exact: true})
|
names, _ := fs.Glob(fsys, "*")
|
||||||
}
|
for _, name := range names {
|
||||||
}
|
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceFS, index: index, name: name})
|
||||||
sources = appendFontSource(sources, seen, fontSource{kind: fontSourceSystem, name: systemName, exact: true})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.fontSourceCache[fontID] = sources
|
r.fontSourceCache[fontID] = sources
|
||||||
@@ -256,16 +259,7 @@ func (r *Renderer) matchFontFiles(dir string, patterns []string, bold, italic bo
|
|||||||
candidates = fontFileCandidates(files, filepath.Base)
|
candidates = fontFileCandidates(files, filepath.Base)
|
||||||
r.fontDirCandidates[dir] = candidates
|
r.fontDirCandidates[dir] = candidates
|
||||||
}
|
}
|
||||||
matches := make([]fontFileMatch, 0, len(candidates))
|
return fontFileMatches(candidates, patterns, bold, italic)
|
||||||
index := make(map[string]int, len(candidates))
|
|
||||||
for _, matcher := range newFontPatternMatchers(patterns) {
|
|
||||||
for _, file := range candidates {
|
|
||||||
rank := matcher.rankCandidate(file)
|
|
||||||
appendFontFileMatch(&matches, index, matcher, file, rank, bold, italic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortFontFileMatches(matches)
|
|
||||||
return fontFileMatchNames(matches)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// systemFontDirs 获取系统字体目录
|
// systemFontDirs 获取系统字体目录
|
||||||
|
|||||||
@@ -110,13 +110,6 @@ var fontMatchRules = []fontMatchRule{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var fontFallbackFiles = []string{
|
|
||||||
"simsun.ttc", "simsun.ttf", "nsimsun.ttf",
|
|
||||||
"msyh.ttc", "msyh.ttf", "simhei.ttf",
|
|
||||||
"NotoSansCJK*.ttc", "NotoSansSC*.otf", "SourceHanSansSC*.otf",
|
|
||||||
"arial.ttf",
|
|
||||||
}
|
|
||||||
|
|
||||||
var fontNameReplacer = strings.NewReplacer(" ", "", "-", "", "_", "", "(", "", ")", "", "(", "", ")", "")
|
var fontNameReplacer = strings.NewReplacer(" ", "", "-", "", "_", "", "(", "", ")", "", "(", "", ")", "")
|
||||||
|
|
||||||
// FontNormalizeName 规范化字体名称
|
// FontNormalizeName 规范化字体名称
|
||||||
|
|||||||
@@ -196,6 +196,14 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
for i, glyph := range glyphs {
|
for i, glyph := range glyphs {
|
||||||
str := glyph.Text
|
str := glyph.Text
|
||||||
drawAsGlyphPath := drawAsPath || glyph.GlyphID >= 0
|
drawAsGlyphPath := drawAsPath || glyph.GlyphID >= 0
|
||||||
|
if !drawAsGlyphPath {
|
||||||
|
for _, char := range str {
|
||||||
|
if face.Font.GlyphIndex(char) == 0 {
|
||||||
|
drawAsGlyphPath = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
var glyphPath *canvas.Path
|
var glyphPath *canvas.Path
|
||||||
var glyphWidth float64
|
var glyphWidth float64
|
||||||
if drawAsGlyphPath {
|
if drawAsGlyphPath {
|
||||||
|
|||||||
Reference in new issue
Block a user