向量圖片編輯應用程式 Boxy SVG 如何使用 Local Font Access API 挑選他們喜愛的本機字型

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 應用程式編輯 Project Fugu 圖示 SVG。

Boxy SVG 中的 Local Font Access API

Jarosław 在網誌中提到的其中一項新增功能是 Local Font Access API。Local Font Access API 可讓使用者存取已在本機安裝的字型,包括名稱、樣式和系列等較高層級詳細資料,以及基礎字型檔案的原始位元組。在下方螢幕截圖中,您可以看到我如何授予應用程式存取 MacBook 上已安裝的本機字型,並為文字選擇 Marker Felt 字型。

Boxy SVG 應用程式編輯 Project Fugu 圖示 SVG 時,在字型 Marker Felt 中加入「Project Fugu Rult」文字,這會顯示在字型挑選器中。

底層程式碼相當簡單。使用者首次開啟字型系列挑選器時,應用程式會先檢查網路瀏覽器是否支援 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;
}

字型挑選器顯示「您的瀏覽器不支援 Local Font Access API」訊息。

否則,系統會使用本機字型存取 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);

Chrome 開發人員工具「儲存空間」部分,顯示含有字型快取的 IndexedDB 表格。

資料庫填入資料後,字型選擇器小工具就能查詢資料庫,並在畫面上顯示結果:

字型挑選器已填入字型。

值得一提的是,Boxy SVG 會在名為 <bx-fontfamilypicker> 的自訂元素中算繪清單,並為每個字型清單項目設定樣式,以便在特定字型系列中顯示。為了與網頁的其他部分隔離,Boxy SVG 會在這個元素和其他自訂元素中使用 Shadow DOM

Chrome 開發人員工具「元素」面板顯示正在檢查的字型挑選器:名為「bx-fontfamiliypicker」的自訂元素。

結論

本機字型功能廣受歡迎,使用者可以存取本機字型,用於設計和創作。當 API 形狀發生變更,且功能暫時無法使用時,使用者會立即發現。Jarosław 很快就將程式碼變更為防禦模式,如上方程式碼片段所示,這可與最新版 Chrome 和其他可能未切換至最新版本的 Chromium 衍生產品搭配使用。試試 Boxy SVG 的轉折,請務必檢查本機安裝的字型。您可能會發現一些早已被遺忘的經典字體,例如 Zapf DingbatsWebdings