La API de Local Font Access proporciona un mecanismo para acceder a los datos de fuentes instalados de forma local del usuario, incluidos los detalles de nivel superior como nombres, estilos y familias, así como los bytes sin procesar de los archivos de fuentes subyacentes. Aprende cómo la app de edición de SVG de Boxy SVG usa esta API.
Introducción
(Este artículo también está disponible en formato de video).
Boxy SVG es un editor de gráficos vectoriales. Su principal caso de uso es la edición de dibujos en formato de archivo SVG para la creación de ilustraciones, logotipos, íconos y otros elementos de diseño gráfico. Fue desarrollado por la empresa desarrolladora polaca Jarosław Foksa y se lanzó inicialmente el 15 de marzo de 2013. Jarosław publica un blog de SVG de Boxy en el que anuncia las nuevas funciones que agrega a la app. El desarrollador es un firme partidario del Proyecto Fugu de Chromium e incluso tiene una etiqueta Fugu en el rastreador de ideas de la app.
API de Local Font Access en SVG de Boxy
Una característica que Jarosław envió en su blog fue la API de Local Font Access. La API de Local Font Access permite a los usuarios acceder a las fuentes instaladas localmente, incluidos los detalles de nivel superior como nombres, estilos y familias, además de los bytes sin procesar de los archivos de fuentes subyacentes. En la siguiente captura de pantalla, puedes ver cómo he otorgado acceso a la app a las fuentes instaladas localmente en mi MacBook y elegí la fuente Marker Felt para mi texto.
El código subyacente es bastante sencillo. Cuando el usuario abre el selector de familia de fuentes por primera vez, la aplicación primero comprueba si el navegador web es compatible con la API de Local Font Access.
También comprueba la antigua versión experimental de la API y la utiliza si está presente. A partir de 2023, puedes ignorar de forma segura la API anterior, ya que solo estaba disponible por un período breve mediante funciones experimentales de Chrome, pero es posible que algunos derivados de Chromium aún la usen.
let isLocalFontsApiEnabled = (
// Local Font Access API, Chrome >= 102
window.queryLocalFonts !== undefined ||
// Experimental Local Font Access API, Chrome < 102
navigator.fonts?.query !== undefined
);
Si la API de Local Font Access no está disponible, el selector de la familia de fuentes se pondrá de color gris. Se mostrará al usuario un texto de marcador de posición en lugar de la lista de fuentes:
if (isLocalFontsApiEnabled === false) {
showPlaceholder("no-local-fonts-api");
return;
}
De lo contrario, la API de Local Font Access se usa para recuperar la lista de todas las fuentes del sistema operativo. Observa el bloque try…catch
, que se necesita para manejar los errores de permisos de forma correcta.
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);
}
}
Una vez que se recupera la lista de fuentes locales, se crea una fontsIndex
simplificada y normalizada a partir de ella:
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();
}
Luego, el índice de fuentes normalizadas se almacena en la base de datos IndexedDB para que se pueda consultar, compartir entre instancias de app y conservar entre sesiones fácilmente. Boxy SVG usa Dexie.js para administrar la base de datos:
let database = new Dexie("LocalFontsManager");
database.version(1).stores({cache: "family"}).
await database.cache.clear();
await database.cache.bulkPut(fontsIndex);
Una vez que se completa la base de datos, el widget del selector de fuentes puede consultarla y mostrar los resultados en la pantalla:
Vale la pena mencionar que Boxy SVG renderiza la lista en un elemento personalizado llamado <bx-fontfamilypicker>
y aplica un estilo a cada elemento de la lista de fuentes para que se muestre en la familia de fuentes específica. Para aislarlo del resto de la página, Boxy SVG utiliza el Shadow DOM en este y otros elementos personalizados.
Conclusiones
La función de fuentes locales es muy popular, y los usuarios disfrutan del acceso a las fuentes locales para sus diseños y creaciones. Cuando la forma de la API cambió y la función dejaba de funcionar brevemente, los usuarios lo notaron inmediatamente. Jarosław se apresuró a cambiar el código al patrón defensivo que puedes ver en el fragmento anterior que funciona con la versión actualizada de Chrome y también con otros derivados de Chromium que pueden no haber cambiado a la versión más reciente. Prueba Boxy SVG y asegúrate de revisar las fuentes instaladas localmente. Es posible que descubras algunos clásicos olvidados por mucho tiempo, como Zapf Dingbats o Webdings.