Как приложение для редактирования векторных изображений Boxy SVG использует API Local Font Access, чтобы позволить пользователям выбирать любимые локальные шрифты

API Local Font Access предоставляет механизм доступа к локально установленным данным шрифтов пользователя, включая более высокоуровневые данные, такие как имена, стили и семейства, а также необработанные байты базовых файлов шрифтов. Узнайте, как приложение для редактирования SVG Boxy SVG использует этот API.

Введение

(Эта статья также доступна в виде видео.)

Boxy SVG — векторный графический редактор. Его основная сфера применения — редактирование рисунков в формате SVG для создания иллюстраций, логотипов, иконок и других элементов графического дизайна. Он разработан польским разработчиком Ярославом Фоксой и был первоначально выпущен 15 марта 2013 года. Ярослав ведет блог Boxy SVG, в котором он объявляет о новых функциях, которые он добавляет в приложение. Разработчик является ярым сторонником проекта Fugu от Chromium и даже имеет тег Fugu на трекере идей приложения.

Приложение Boxy SVG, редактирующее значок проекта Fugu SVG.

API локального доступа к шрифтам в Boxy SVG

Одной из дополнительных функций, о которой писал Ярослав в своем блоге, был Local Font Access API . Local Font Access API позволяет пользователям получать доступ к локально установленным шрифтам, включая более высокоуровневые данные, такие как имена, стили и семейства, а также необработанные байты базовых файлов шрифтов. На следующем снимке экрана вы можете увидеть, как я предоставил приложению доступ к локально установленным шрифтам на моем MacBook и выбрал шрифт Marker Felt для своего текста.

Приложение Boxy SVG редактирует значок Project Fugu SVG, добавляя текст «Project Fugu rocks» шрифтом Marker Felt, который отображается выбранным в палитре шрифтов.

Базовый код довольно прост. Когда пользователь впервые открывает средство выбора семейства шрифтов, приложение сначала проверяет, поддерживает ли веб-браузер API Local Font Access.

Он также проверяет наличие старой экспериментальной версии API и использует ее, если она есть. По состоянию на 2023 год вы можете спокойно игнорировать старый API, поскольку он был доступен только в течение короткого времени через экспериментальные флаги Chrome, но некоторые производные от Chromium могут по-прежнему использовать его.

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

Если API Local Font Access недоступен, то селектор семейства шрифтов станет серым. Вместо списка шрифтов пользователю будет показан текст-заполнитель:

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

Средство выбора шрифтов показывает сообщение «Ваш браузер не поддерживает API локального доступа к шрифтам».

В противном случае используется API Local Font Access для получения списка всех шрифтов из операционной системы. Обратите внимание на блок 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 DevTools, в котором показана таблица IndexedDB с кэшем шрифтов.

После заполнения базы данных виджет выбора шрифтов может запросить ее и отобразить результаты на экране:

Выбор шрифтов, заполненный шрифтами.

Стоит отметить, что Boxy SVG отображает список в пользовательском элементе с именем <bx-fontfamilypicker> и стилизует каждый элемент списка шрифтов так, чтобы он отображался в определенном семействе шрифтов. Чтобы изолировать от остальной части страницы, Boxy SVG использует Shadow DOM в этом и других пользовательских элементах.

Панель элементов Chrome DevTools, на которой показан проверяемый выбор шрифтов: пользовательский элемент с именем «bx-fontfamiliypicker».

Выводы

Функция локальных шрифтов была действительно популярна, и пользователи наслаждались доступом к своим локальным шрифтам для своих проектов и творений. Когда форма API изменилась и функция на короткое время сломалась , пользователи сразу это заметили. Ярослав быстро изменил код на защитный шаблон, который вы можете видеть в фрагменте выше, который работает с обновленным Chrome, а также с другими производными Chromium, которые, возможно, не перешли на последнюю версию. Возьмите Boxy SVG на пробу и обязательно проверьте свои локально установленные шрифты. Вы можете обнаружить некоторые давно забытые классические, такие как Zapf Dingbats или Webdings .