mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-11-12 17:44:01 +01:00
feat: add fallback font loading and handling for various languages
This commit is contained in:
1 parent
9ae5c93886
commit
5a7927572f
28 files changed
+375
-4
No files matched your search
@@ -3,6 +3,7 @@ import {
|
||||
getFontUrlForFamily,
|
||||
languageToFontFamily,
|
||||
} from '../config/font-mappings.js';
|
||||
import { needsFontEmbedding } from './freetext-script.js';
|
||||
|
||||
const fontCache: Map<string, ArrayBuffer> = new Map();
|
||||
|
||||
@@ -134,6 +135,56 @@ export async function getFontForLanguage(lang: string): Promise<ArrayBuffer> {
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackFontLoads = new Map<string, Promise<boolean>>();
|
||||
|
||||
const fallbackFontFamily = (lang: string): string =>
|
||||
languageToFontFamily[lang] || 'Noto Sans';
|
||||
|
||||
export function fallbackFontLanguages(text: string): Set<string> {
|
||||
const langs = new Set<string>();
|
||||
for (const ch of text) {
|
||||
if (needsFontEmbedding(ch)) langs.add(getLanguageForChar(ch));
|
||||
}
|
||||
return langs;
|
||||
}
|
||||
|
||||
export function hasFallbackFonts(
|
||||
loaded: Map<string, Uint8Array>,
|
||||
langs: Iterable<string>
|
||||
): boolean {
|
||||
return [...langs].every((lang) => loaded.has(fallbackFontFamily(lang)));
|
||||
}
|
||||
|
||||
export async function loadFallbackFonts(
|
||||
into: Map<string, Uint8Array>,
|
||||
langs: Iterable<string>
|
||||
): Promise<boolean> {
|
||||
const results = await Promise.all(
|
||||
[...langs].map((lang) => {
|
||||
const family = fallbackFontFamily(lang);
|
||||
let load = fallbackFontLoads.get(family);
|
||||
if (!load) {
|
||||
load = getFontForLanguage(lang)
|
||||
.then((buffer) => {
|
||||
if (!fontCache.has(family)) {
|
||||
throw new Error('Only a substitute font was available');
|
||||
}
|
||||
into.set(family, new Uint8Array(buffer));
|
||||
return true;
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
fallbackFontLoads.delete(family);
|
||||
console.warn(`Fallback font unavailable for ${family}`, error);
|
||||
return false;
|
||||
});
|
||||
fallbackFontLoads.set(family, load);
|
||||
}
|
||||
return load;
|
||||
})
|
||||
);
|
||||
return results.every(Boolean);
|
||||
}
|
||||
|
||||
export function detectScripts(text: string): string[] {
|
||||
const scripts = new Set<string>();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { FreeTextSystemFontAnnotation } from '@/types';
|
||||
import { needsFontEmbedding } from './freetext-script.js';
|
||||
import { fallbackFontLanguages, loadFallbackFonts } from './font-loader.js';
|
||||
|
||||
export const FPDF_ANNOT_FREETEXT = 3;
|
||||
|
||||
@@ -153,7 +154,7 @@ function buildRuns(
|
||||
return [
|
||||
{
|
||||
text: contents,
|
||||
family: 'Helvetica',
|
||||
family: needsFontEmbedding(contents) ? 'Noto Sans' : 'Helvetica',
|
||||
size,
|
||||
rgba: hexToRgba(style?.fontColor ?? '#000000'),
|
||||
bold: false,
|
||||
@@ -196,6 +197,7 @@ export async function flattenFreeTextToPageText(
|
||||
PdfEngine: {
|
||||
create: () => Promise<EngineLike>;
|
||||
localFonts: Map<string, Uint8Array>;
|
||||
fallbackFonts: Map<string, Uint8Array>;
|
||||
};
|
||||
scriptFallbackFamilies: (cps: number[]) => string[];
|
||||
};
|
||||
@@ -245,6 +247,10 @@ export async function flattenFreeTextToPageText(
|
||||
return { bytes, flattened: 0 };
|
||||
}
|
||||
await primeScriptFonts(mod, found);
|
||||
await loadFallbackFonts(
|
||||
mod.PdfEngine.fallbackFonts,
|
||||
fallbackFontLanguages(found.join('\n'))
|
||||
);
|
||||
|
||||
for (const pageIndex of [...pages].sort((x, y) => x - y)) {
|
||||
if (pageIndex < 0 || pageIndex >= eng.pageCount) continue;
|
||||
|
||||
Reference in new issue
Block a user