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

Local Font Access API 提供一種機制,可存取使用者本機安裝的字型資料,包括更高層級的詳細資料 (例如名稱、樣式和系列),以及基礎字型檔案的原始位元組。瞭解 SVG 編輯應用程式 Boxy SVG 如何使用這個 API。

北雅克
Jarek Foksa

簡介

(這篇文章也可以影片的形式提供)。

Boxy SVG 是向量圖形編輯器。以 SVG 檔案格式編輯繪圖,以便建立插圖、標誌、圖示和其他圖形設計元素。該應用程式是由波蘭開發人員 Jarosław Foksa 所開發,最初發布日期為 2013 年 3 月 15 日。Jarosław 經營 Boxy SVG 網誌,介紹他為應用程式新增的新功能。開發人員不僅是 Chromium Project Fugu 的支持,也在應用程式的創意追蹤工具上安裝 Fugu 標記

用於編輯 Project Fugu 圖示 SVG 的 Boxy SVG 應用程式。

Boxy SVG 中的本機字型存取 API

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

Boxy SVG 應用程式會編輯 Project Fugu 圖示 SVG,在字型標記 Felt 中設定「Project Fugu Rocks」的文字。

基礎程式碼相當簡單,當使用者首次開啟字型系列挑選器時,應用程式會先檢查網路瀏覽器是否支援 Local Font Access API。

此外,這個 API 也會檢查是否有舊版 API 實驗版本,如果有,則會使用該 API。自 2023 年起,由於舊版 API 只能透過實驗性 Chrome 旗標取得,因此您可以放心忽略舊版 API,但部分 Chromium 衍生工具可能仍會使用該 API。

let isLocalFontsApiEnabled = (
  // Local Font Access API, Chrome >= 102
  window.queryLocalFonts !== undefined ||
  // Experimental Local Font Access API, Chrome < 102
  navigator.fonts?.query !== undefined
);

如果無法使用 Local Font Access API,字型系列挑選器將顯示為灰色。系統會向使用者顯示預留位置文字,而非字型清單:

if (isLocalFontsApiEnabled === false) {
  showPlaceholder("no-local-fonts-api");
  return;
}

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

否則,系統會使用 Local Font Access 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 開發人員工具「Elements」面板顯示正在檢查的字型挑選器,也就是名為「bx-fontfamiliypicker」的自訂元素。

結論

本機字型功能真的很受歡迎,使用者喜歡在設計和創作時選用當地字型。當 API 形狀變更且功能故障時,使用者會立即收到通知。Jarosław 迅速地將程式碼變更成防禦模式,而上面程式碼片段中,可搭配最新版 Chrome,以及其他可能未切換至最新版的 Chromium 衍生工具。旋轉 Boxy SVG 時,請務必查看本機安裝的字型。你可能會發現一些先前不見的經典作品,例如 Zapf DingbatsWebdings