Local Font Access API 提供機制,可存取使用者在本機安裝的字型資料,包括名稱、樣式和系列等較高層級詳細資料,以及基礎字型檔案的原始位元組。瞭解 SVG 編輯應用程式 Boxy SVG 如何使用這個 API。
簡介
(這篇文章也有影片版本)。
Boxy SVG 是向量圖形編輯器。主要用途是編輯 SVG 檔案格式的繪圖,以便製作插圖、標誌、圖示和其他圖形設計元素。這個擴充功能是由波蘭開發人員 Jarosław Foksa 開發,最初於 2013 年 3 月 15 日發布。Jarosław 經營 Boxy SVG 網誌,在其中宣布應用程式新增的功能。這位開發人員是 Chromium 的 Project Fugu 的忠實支持者,甚至在應用程式的想法追蹤器上有 Fugu 標記。
Boxy SVG 中的 Local Font Access API
Jarosław 在網誌中提到的其中一項新增功能是 Local Font Access API。Local Font Access API 可讓使用者存取已在本機安裝的字型,包括名稱、樣式和系列等較高層級詳細資料,以及基礎字型檔案的原始位元組。在下方螢幕截圖中,您可以看到我如何授予應用程式存取 MacBook 上已安裝的本機字型,並為文字選擇 Marker Felt 字型。
底層程式碼相當簡單。使用者首次開啟字型系列挑選器時,應用程式會先檢查網路瀏覽器是否支援 Local Font Access API。
也會檢查舊版 API 的實驗版本,並在有舊版 API 的情況下使用。自 2023 年起,您可以放心忽略舊版 API,因為這類 API 只會透過實驗性 Chrome 旗標提供一段時間,但部分 Chromium 衍生產品可能仍會使用這類 API。
let isLocalFontsApiEnabled = (
// Local Font Access API, Chrome >= 102
window.queryLocalFonts !== undefined ||
// Experimental Local Font Access API, Chrome < 102
navigator.fonts?.query !== undefined
);
如果無法使用本機字型存取 API,字型系列挑選器會變灰。系統會向使用者顯示預留位置文字,而非字型清單:
if (isLocalFontsApiEnabled === false) {
showPlaceholder("no-local-fonts-api");
return;
}
否則,系統會使用本機字型存取 API 從作業系統擷取所有字型的清單。請注意 try…catch
區塊,這是妥善處理權限錯誤所需的元素。
let localFonts;
if (isLocalFontsApiEnabled === true) {
try {
// Local Font Access API, Chrome >= 102
if (window.queryLocalFonts) {
localFonts = await window.queryLocalFonts();
}
// Experimental Local Font Access API, Chrome < 102
else if (navigator.fonts?.query) {
localFonts = await navigator.fonts.query({
persistentAccess: true,
});
}
} catch (error) {
showError(error.message, error.name);
}
}
擷取本機字型清單後,系統會根據該清單建立簡化且標準化的 fontsIndex
:
let fontsIndex = [];
for (let localFont of localFonts) {
let face = "400";
// Determine the face name
{
let subfamily = localFont.style.toLowerCase();
subfamily = subfamily.replaceAll(" ", "");
subfamily = subfamily.replaceAll("-", "");
subfamily = subfamily.replaceAll("_", "");
if (subfamily.includes("thin")) {
face = "100";
} else if (subfamily.includes("extralight")) {
face = "200";
} else if (subfamily.includes("light")) {
face = "300";
} else if (subfamily.includes("medium")) {
face = "500";
} else if (subfamily.includes("semibold")) {
face = "600";
} else if (subfamily.includes("extrabold")) {
face = "800";
} else if (subfamily.includes("ultrabold")) {
face = "900";
} else if (subfamily.includes("bold")) {
face = "700";
}
if (subfamily.includes("italic")) {
face += "i";
}
}
let descriptor = fontsIndex.find((descriptor) => {
return descriptor.family === localFont.family);
});
if (descriptor) {
if (descriptor.faces.includes(face) === false) {
descriptor.faces.push(face);
}
} else {
let descriptor = {
family: localFont.family,
faces: [face],
};
fontsIndex.push(descriptor);
}
}
for (let descriptor of fontsIndex) {
descriptor.faces.sort();
}
系統會將標準化字型索引儲存在 IndexedDB 資料庫中,方便在應用程式例項之間查詢、共用,並在工作階段之間保留。Boxy SVG 會使用 Dexie.js 管理資料庫:
let database = new Dexie("LocalFontsManager");
database.version(1).stores({cache: "family"}).
await database.cache.clear();
await database.cache.bulkPut(fontsIndex);
資料庫填入資料後,字型選擇器小工具就能查詢資料庫,並在畫面上顯示結果:
值得一提的是,Boxy SVG 會在名為 <bx-fontfamilypicker>
的自訂元素中算繪清單,並為每個字型清單項目設定樣式,以便在特定字型系列中顯示。為了與網頁的其他部分隔離,Boxy SVG 會在這個元素和其他自訂元素中使用 Shadow DOM。
結論
本機字型功能廣受歡迎,使用者可以存取本機字型,用於設計和創作。當 API 形狀發生變更,且功能暫時無法使用時,使用者會立即發現。Jarosław 很快就將程式碼變更為防禦模式,如上方程式碼片段所示,這可與最新版 Chrome 和其他可能未切換至最新版本的 Chromium 衍生產品搭配使用。試試 Boxy SVG 的轉折,請務必檢查本機安裝的字型。您可能會發現一些早已被遺忘的經典字體,例如 Zapf Dingbats 或 Webdings。