feat: 完成 DOCX 视觉门禁与字体兼容映射
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import type { SfntFontMetadata } from "./font-embedding.js";
|
||||
|
||||
export type WordFontFamily =
|
||||
| "auto"
|
||||
| "decorative"
|
||||
| "modern"
|
||||
| "roman"
|
||||
| "script"
|
||||
| "swiss";
|
||||
|
||||
export interface WordFontMetadata {
|
||||
panose1: string;
|
||||
charset: string;
|
||||
family: WordFontFamily;
|
||||
pitch: "fixed" | "variable";
|
||||
signature: {
|
||||
usb0: string;
|
||||
usb1: string;
|
||||
usb2: string;
|
||||
usb3: string;
|
||||
csb0: string;
|
||||
csb1: string;
|
||||
};
|
||||
}
|
||||
|
||||
const codePageCharsets = [
|
||||
{ bit: 18, charset: "86" },
|
||||
{ bit: 20, charset: "88" },
|
||||
{ bit: 17, charset: "80" },
|
||||
{ bit: 19, charset: "81" },
|
||||
{ bit: 21, charset: "82" },
|
||||
{ bit: 16, charset: "DE" },
|
||||
{ bit: 6, charset: "B2" },
|
||||
{ bit: 5, charset: "B1" },
|
||||
{ bit: 7, charset: "BA" },
|
||||
{ bit: 2, charset: "CC" },
|
||||
{ bit: 3, charset: "A1" },
|
||||
{ bit: 4, charset: "A2" },
|
||||
{ bit: 31, charset: "02" }
|
||||
] as const;
|
||||
|
||||
function uint32Hex(value: number) {
|
||||
return value.toString(16).toUpperCase().padStart(8, "0");
|
||||
}
|
||||
|
||||
function byteHex(value: number) {
|
||||
return value.toString(16).toUpperCase().padStart(2, "0");
|
||||
}
|
||||
|
||||
function hasCodePageBit(
|
||||
ranges: SfntFontMetadata["codePageRanges"],
|
||||
bit: number
|
||||
) {
|
||||
const range = ranges[Math.floor(bit / 32)] ?? 0;
|
||||
return ((range >>> (bit % 32)) & 1) === 1;
|
||||
}
|
||||
|
||||
function resolveCharset(metadata: SfntFontMetadata) {
|
||||
return (
|
||||
codePageCharsets.find(({ bit }) =>
|
||||
hasCodePageBit(metadata.codePageRanges, bit)
|
||||
)?.charset ?? "00"
|
||||
);
|
||||
}
|
||||
|
||||
function resolveFamily(metadata: SfntFontMetadata): WordFontFamily {
|
||||
if (metadata.fixedPitch) {
|
||||
return "modern";
|
||||
}
|
||||
const [familyType, serifStyle] = metadata.panose;
|
||||
if (familyType === 3) {
|
||||
return "script";
|
||||
}
|
||||
if (familyType === 4) {
|
||||
return "decorative";
|
||||
}
|
||||
if (familyType !== 2) {
|
||||
return "auto";
|
||||
}
|
||||
if (serifStyle >= 11 && serifStyle <= 13) {
|
||||
return "swiss";
|
||||
}
|
||||
if (
|
||||
(serifStyle >= 2 && serifStyle <= 10) ||
|
||||
serifStyle === 14 ||
|
||||
serifStyle === 15
|
||||
) {
|
||||
return "roman";
|
||||
}
|
||||
return "auto";
|
||||
}
|
||||
|
||||
export function createWordFontMetadata(
|
||||
metadata: SfntFontMetadata
|
||||
): WordFontMetadata {
|
||||
const [usb0, usb1, usb2, usb3] = metadata.unicodeRanges;
|
||||
const [csb0, csb1] = metadata.codePageRanges;
|
||||
return {
|
||||
panose1: metadata.panose.map(byteHex).join(""),
|
||||
charset: resolveCharset(metadata),
|
||||
family: resolveFamily(metadata),
|
||||
pitch: metadata.fixedPitch ? "fixed" : "variable",
|
||||
signature: {
|
||||
usb0: uint32Hex(usb0),
|
||||
usb1: uint32Hex(usb1),
|
||||
usb2: uint32Hex(usb2),
|
||||
usb3: uint32Hex(usb3),
|
||||
csb0: uint32Hex(csb0),
|
||||
csb1: uint32Hex(csb1)
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user