SVGcode: una AWP para convertir imágenes de trama en gráficos vectoriales SVG

SVGcode es una app web progresiva que te permite convertir imágenes de trama como JPG, PNG, GIF, WebP, AVIF, etc., en gráficos vectoriales en formato SVG. Utiliza la API de File System Access, la API de Async Clipboard, la API de File Handling y la personalización de Window Controls Overlay.

. (Si prefieres mirar videos en vez de leer, este artículo también está disponible como video).

De trama a vector

¿Alguna vez escalaste una imagen y el resultado fue pixelado y no satisfactorio? Si así que probablemente hayas trabajado con un formato de imagen de trama como WebP, PNG o JPG.

. Aumentar la escala de una imagen de trama hace que se vea pixelada.

Por el contrario, los gráficos vectoriales son imágenes que se definen mediante puntos en un sistema de coordenadas. Estos los puntos están conectados por líneas y curvas para formar polígonos y otras formas. Los gráficos vectoriales tienen un se benefician con respecto a los gráficos de trama, ya que pueden aumentar o reducir su resolución a cualquier resolución. sin pixelarlo.

. Escalamiento vertical de una imagen vectorial sin pérdida de calidad

Presentamos SVGcode

Creé una AWP llamada SVGcode que puede ayudarte a convertir imágenes de trama a vectores. Crédito a pagar: No lo inventé. Con SVGcode, solo me paro en la los hombros de una herramienta de línea de comandos llamada Potrace, que Peter Selinger, que tengo a convertirse en Web Assembly, de modo que puede usarse en un App web

Captura de pantalla de la aplicación SVGcode.
La app SVGcode.
.

Usa código SVG

Primero, quiero mostrarte cómo usar la app. Comienzo con la imagen de avance de la Cumbre de desarrolladores de Chrome. que descargué del canal de Twitter de ChromiumDev. Esta es una imagen de trama PNG arrastra a la aplicación SVGcode. Cuando suelto el archivo, la app registra el color de la imagen por color hasta que aparezca una versión vectorizada de la entrada. Ahora puedo acercar la imagen y, como puedes ver, los bordes se mantienen filosos. Pero al acercar el logotipo de Chrome, se puede ver que el seguimiento no fue perfecto y, sobre todo, los contornos del logotipo se ven un poco mojados. Puedo mejorar el resultado quitar manchas del trazado quitando manchas de hasta cinco píxeles, por ejemplo.

. Convertir una imagen descartada en SVG

Posterización en código SVG

Un paso importante para la vectorización, especialmente para las imágenes fotográficas, es posterizar la entrada imagen para reducir la cantidad de colores. SVGcode me permite hacer esto por canal de color y ver la o SVG resultante mientras realizo cambios. Cuando estoy conforme con el resultado, puedo guardar el SVG en mi disco duro. y usarla donde quiera.

. Posterizar una imagen para reducir la cantidad de colores

APIs usadas en SVGcode

Ahora que ya viste las capacidades de la app, veamos algunas de las APIs que ayudan a ocurre la magia.

App web progresiva

SVGcode es una Progressive Web App instalable y, por lo tanto, está completamente habilitado sin conexión. La app se basa en la Plantilla de JS estándar para Vite.js y usa la popular AWP del complemento Vite, que crea un service worker que usa Workbox.js de forma interna. La caja de trabajo es un conjunto de bibliotecas que pueden potenciar un service worker listo para la producción de apps web progresivas, este patrón puede que no funcione necesariamente para todas las apps, pero es genial para el caso de uso de SVGcode.

Superposición de controles de ventana

Para maximizar el espacio disponible en la pantalla, SVGcode utiliza Superposición de controles de ventana moviendo el menú principal hacia en el área de la barra de título. Verás que se activa al final del flujo de instalación.

. Instalación de SVGcode y activación de la personalización de la superposición de controles de ventana

API de File System Access

Para abrir archivos de imagen de entrada y guardar los SVG resultantes, utilizo el API de File System Access: Esto me permite mantener una referencia a los abrí archivos y retomaré desde donde lo dejé, incluso después de volver a cargar la app. Cada vez que una imagen se guardado, se optimiza mediante la biblioteca svgo, lo que puede tardar un momento según la complejidad del SVG. Para mostrar el diálogo para guardar el archivo, se requiere un gesto del usuario. Sí por lo que es importante obtener el controlador de archivo antes de que se produzca la optimización de SVG, de modo que el usuario el gesto no se invalidará cuando esté listo el SVG optimizado.

try {
  let svg = svgOutput.innerHTML;
  let handle = null;
  // To not consume the user gesture obtain the handle before preparing the
  // blob, which may take longer.
  if (supported) {
    handle = await showSaveFilePicker({
      types: [{description: 'SVG file', accept: {'image/svg+xml': ['.svg']}}],
    });
  }
  showToast(i18n.t('optimizingSVG'), Infinity);
  svg = await optimizeSVG(svg);
  showToast(i18n.t('savedSVG'));
  const blob = new Blob([svg], {type: 'image/svg+xml'});
  await fileSave(blob, {description: 'SVG file'}, handle);
} catch (err) {
  console.error(err.name, err.message);
  showToast(err.message);
}

Arrastrar y soltar

Para abrir una imagen de entrada, puedo usar la función de apertura de archivos o, como viste anteriormente, arrastra y suelta un archivo de imagen en la app. La función para abrir archivos es bastante sencilla, interesante es el de arrastrar y soltar. Lo que es particularmente bueno acerca de esto es que puedes obtener un controlador de sistema de archivos desde el elemento de transferencia de datos a través del getAsFileSystemHandle() . Como se mencionó antes, puedo conservar este controlador para que esté listo cuando se vuelva a cargar la app.

document.addEventListener('drop', async (event) => {
  event.preventDefault();
  dropContainer.classList.remove('dropenter');
  const item = event.dataTransfer.items[0];
  if (item.kind === 'file') {
    inputImage.addEventListener(
      'load',
      () => {
        URL.revokeObjectURL(blobURL);
      },
      {once: true},
    );
    const handle = await item.getAsFileSystemHandle();
    if (handle.kind !== 'file') {
      return;
    }
    const file = await handle.getFile();
    const blobURL = URL.createObjectURL(file);
    inputImage.src = blobURL;
    await set(FILE_HANDLE, handle);
  }
});

Para obtener más información, consulta el artículo sobre la API de File System Access y Si te interesa, estudia el código fuente SVG src/js/filesystem.js

API de Async Clipboard

SVGcode también está completamente integrado con el portapapeles del sistema operativo a través de la API de Async Clipboard. Puedes pegar imágenes del explorador de archivos del sistema operativo en la aplicación haciendo clic en el botón el botón para pegar imagen o presionando Comando o Control más V en el teclado.

. Pegar una imagen del explorador de archivos en código SVG

La API de Async Clipboard ha ganado recientemente la capacidad de tratar también imágenes SVG, por lo que puedes copia también una imagen SVG y pégala en otra aplicación para su procesamiento posterior.

. Copiar una imagen de SVGcode a SVGOMG
copyButton.addEventListener('click', async () => {
  let svg = svgOutput.innerHTML;
  showToast(i18n.t('optimizingSVG'), Infinity);
  svg = await optimizeSVG(svg);
  const textBlob = new Blob([svg], {type: 'text/plain'});
  const svgBlob = new Blob([svg], {type: 'image/svg+xml'});
  navigator.clipboard.write([
    new ClipboardItem({
      [svgBlob.type]: svgBlob,
      [textBlob.type]: textBlob,
    }),
  ]);
  showToast(i18n.t('copiedSVG'));
});

Para obtener más información, lee el artículo sobre el Portapapeles asíncrono o consulta el archivo. src/js/clipboard.js

Manejo de archivos

Una de mis funciones favoritas de SVGcode es la eficacia con la que se combina con el sistema operativo. Como instalada, puede convertirse en un controlador de archivos, o incluso en el controlador de archivos predeterminado, de archivos de imagen. Esta significa que cuando estoy en el Finder de mi máquina macOS, puedo hacer clic con el botón derecho en una imagen y abrirla con o SVG. Esta función se llama manejo de archivos y funciona según la propiedad file_handlers en el El manifiesto de apps web y la cola de inicio, que permiten que la app consuma el archivo pasado.

. Abrir un archivo desde el escritorio con la app SVGcode instalada
.
window.launchQueue.setConsumer(async (launchParams) => {
  if (!launchParams.files.length) {
    return;
  }
  for (const handle of launchParams.files) {
    const file = await handle.getFile();
    if (file.type.startsWith('image/')) {
      const blobURL = URL.createObjectURL(file);
      inputImage.addEventListener(
        'load',
        () => {
          URL.revokeObjectURL(blobURL);
        },
        {once: true},
      );
      inputImage.src = blobURL;
      await set(FILE_HANDLE, handle);
      return;
    }
  }
});

Para obtener más información, consulta Permite que las aplicaciones web instaladas sean controladores de archivos y visualiza el código fuente en src/js/filehandling.js

Compartir en la Web (archivos)

Otro ejemplo de integración con el sistema operativo es la función de compartir de la app. Suponiendo que quiero para editar un SVG creado con SVGcode, una forma de abordar esto sería guardar el archivo, inicia la aplicación de edición de SVG y abre el archivo SVG desde allí. Sin embargo, un flujo más fluido consiste en Usa la API de Web Share, que permite compartir archivos directamente. Entonces, si la app de edición de SVG es un objetivo de uso compartido, puede recibir el archivo directamente sin desviarse.

shareSVGButton.addEventListener('click', async () => {
  let svg = svgOutput.innerHTML;
  svg = await optimizeSVG(svg);
  const suggestedFileName =
    getSuggestedFileName(await get(FILE_HANDLE)) || 'Untitled.svg';
  const file = new File([svg], suggestedFileName, { type: 'image/svg+xml' });
  const data = {
    files: [file],
  };
  if (navigator.canShare(data)) {
    try {
      await navigator.share(data);
    } catch (err) {
      if (err.name !== 'AbortError') {
        console.error(err.name, err.message);
      }
    }
  }
});
Compartir una imagen SVG en Gmail

Objetivo de uso compartido en la Web (archivos)

Por otro lado, SVGcode también puede actuar como un objetivo de uso compartido y recibir archivos de otras apps. Para hacer que esto funcione, la app debe informarle al sistema operativo API de Web Share Target para saber qué tipos de datos puede aceptar. Esto sucede con un campo exclusivo en el manifiesto de apps web.

{
  "share_target": {
    "action": "https://svgco.de/share-target/",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "files": [
        {
          "name": "image",
          "accept": ["image/jpeg", "image/png", "image/webp", "image/gif"]
        }
      ]
    }
  }
}

En realidad, la ruta action no existe, sino que se maneja exclusivamente en el fetch del service worker que luego pasa los archivos recibidos para su procesamiento real en la app.

self.addEventListener('fetch', (fetchEvent) => {
  if (
    fetchEvent.request.url.endsWith('/share-target/') &&
    fetchEvent.request.method === 'POST'
  ) {
    return fetchEvent.respondWith(
      (async () => {
        const formData = await fetchEvent.request.formData();
        const image = formData.get('image');
        const keys = await caches.keys();
        const mediaCache = await caches.open(
          keys.filter((key) => key.startsWith('media'))[0],
        );
        await mediaCache.put('shared-image', new Response(image));
        return Response.redirect('./?share-target', 303);
      })(),
    );
  }
});
Se está compartiendo una captura de pantalla en SVGcode.

Conclusión

Muy bien. Este fue un recorrido rápido por algunas de las funciones avanzadas de la app en SVGcode. Espero que esta app puede convertirse en una herramienta esencial para tus necesidades de procesamiento de imágenes junto con otras apps asombrosas como Squoosh o SVGOMG.

SVGcode está disponible en svgco.de. ¿Viste lo que hice allí? Puedes revisar su código fuente en GitHub Como Potrace es también tiene licencia de GPL y SVG. Y con eso, ¡feliz vectorización! Espero que SVGcode te resulte útil y algunas de sus funciones pueden inspirar tu próxima app.

Agradecimientos

Joe Medley revisó este artículo.