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

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

Введение

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

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

Приложение Boxy SVG редактирует SVG значка Project Fugu.

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

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

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

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

Он также проверяет наличие старой экспериментальной версии 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 локального доступа к шрифтам недоступен, средство выбора семейства шрифтов станет серым. Вместо списка шрифтов пользователю будет отображаться текст-заполнитель:

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

В средстве выбора шрифтов отображается сообщение «Ваш браузер не поддерживает 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 DevTools» показана таблица IndexedDB с кешем шрифтов.

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

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

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

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

Выводы

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