SVGcode ist eine progressive Webanwendung, mit der Sie Rasterbilder wie JPG, PNG, GIF, WebP und AVIF in Vektorgrafiken im SVG-Format konvertieren können. Dabei werden die File System Access API, die Async Clipboard API, die File Handling API und die Anpassung der Window Controls Overlay API verwendet.
Von Raster zu Vektor
Haben Sie schon einmal ein Bild skaliert und das Ergebnis war pixelig und unbefriedigend? In diesem Fall haben Sie wahrscheinlich schon einmal mit einem Rasterbildformat wie WebP, PNG oder JPG gearbeitet.
Im Gegensatz dazu sind Vektorgrafiken Bilder, die durch Punkte in einem Koordinatensystem definiert sind. Diese Punkte werden durch Linien und Kurven verbunden, um Polygone und andere Formen zu bilden. Vektorgrafiken haben gegenüber Rastergrafiken den Vorteil, dass sie ohne Pixelung auf jede Auflösung skaliert werden können.
SVGcode
Ich habe eine PWA namens SVGcode entwickelt, mit der Sie Rasterbilder in Vektoren konvertieren können. Zuerst einmal: Ich habe diese Methode nicht erfunden. Bei SVGcode nutze ich einfach ein Befehlszeilentool namens Potrace von Peter Selinger, das ich in Web Assembly konvertiert habe, damit es in einer Webanwendung verwendet werden kann.
SVG-Code verwenden
Zuerst möchte ich Ihnen zeigen, wie Sie die App verwenden. Ich beginne mit dem Teaserbild für das Chrome Dev Summit, das ich vom Twitter-Kanal von ChromiumDev heruntergeladen habe. Das ist ein PNG-Rasterbild, das ich dann in die SVGcode App ziehe. Wenn ich die Datei ablege, wird das Bild farbstichig nachgezeichnet, bis eine vektorisierte Version der Eingabe erscheint. Ich kann jetzt heranzoomen. Wie Sie sehen, bleiben die Kanten scharf. Wenn Sie jedoch heranzoomen, sehen Sie, dass die Verfolgung nicht perfekt war und insbesondere die Umrisse des Logos etwas ungleichmäßig sind. Ich kann das Ergebnis verbessern, indem ich die Streifen aus dem Tracing entferne, indem ich Streifen von bis zu fünf Pixeln unterdrücke.
Posterisierung in SVG-Code
Ein wichtiger Schritt bei der Vektorisierung, insbesondere bei fotografischen Bildern, ist die Posterisierung des Eingabebilds, um die Anzahl der Farben zu reduzieren. Mit SVGcode kann ich das pro Farbkanal tun und das resultierende SVG sehen, während ich Änderungen vornehme. Wenn ich mit dem Ergebnis zufrieden bin, kann ich das SVG auf meiner Festplatte speichern und überall verwenden.
In SVG-Code verwendete APIs
Nachdem Sie gesehen haben, was die App kann, möchte ich Ihnen einige der APIs zeigen, die dafür sorgen, dass alles so reibungslos funktioniert.
Progressive Web-App
SVGcode ist eine installierbare progressive Web-App und daher vollständig offlinefähig. Die App basiert auf der Vanilla-JS-Vorlage für Vite.js und verwendet das beliebte Vite-Plug-in PWA, das einen Service Worker erstellt, der Workbox.js verwendet. Workbox ist eine Reihe von Bibliotheken, mit denen ein produktionsfertiger Service Worker für progressive Web-Apps bereitgestellt werden kann. Dieses Muster funktioniert möglicherweise nicht für alle Apps, aber für den Anwendungsfall von SVGcode ist es ideal.
Overlay für Fenstersteuerelemente
Um die verfügbare Bildschirmfläche zu maximieren, verwendet SVGcode die Anpassung Window Controls Overlay, indem das Hauptmenü in den Bereich der Titelleiste verschoben wird. Sie sehen, dass diese Funktion am Ende des Installationsvorgangs aktiviert wird.
File System Access API
Zum Öffnen von Eingabebilddateien und Speichern der resultierenden SVGs verwende ich die File System Access API. So kann ich eine Verknüpfung zu zuvor geöffneten Dateien behalten und auch nach dem Neuladen einer App dort weitermachen, wo ich aufgehört habe. Jedes Mal, wenn ein Bild gespeichert wird, wird es über die svgo-Bibliothek optimiert. Je nach Komplexität des SVG kann dies einen Moment dauern. Das Dialogfeld zum Speichern von Dateien muss durch eine Nutzergeste geöffnet werden. Daher ist es wichtig, den Dateihandle vor der SVG-Optimierung abzurufen, damit die Nutzergeste nicht ungültig wird, bis die optimierte SVG-Datei bereit ist.
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);
}
Drag-and-Drop
Zum Öffnen eines Eingabebilds kann ich entweder die Funktion zum Öffnen von Dateien verwenden oder, wie oben gezeigt, eine Bilddatei per Drag-and-drop in die App ziehen. Die Funktion zum Öffnen von Dateien ist ziemlich einfach, interessanter ist der Drag-and-drop-Fall. Besonders praktisch ist, dass Sie über die Methode getAsFileSystemHandle()
einen Dateisystem-Handle vom Datenübertragungselement abrufen können. Wie bereits erwähnt, kann ich diesen Handle beibehalten, damit er bereit ist, wenn die App neu geladen wird.
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);
}
});
Weitere Informationen finden Sie im Artikel zur File System Access API. Wenn Sie möchten, können Sie sich auch den SVG-Code in src/js/filesystem.js
ansehen.
Async Clipboard API
SVG-Code ist außerdem über die Async Clipboard API vollständig in die Zwischenablage des Betriebssystems eingebunden. Sie können Bilder aus dem Dateimanager des Betriebssystems in die App einfügen, indem Sie entweder auf die Schaltfläche „Bild einfügen“ klicken oder auf der Tastatur die Tastenkombination „Befehl“ oder „Strg“ + „V“ drücken.
Die Async Clipboard API kann seit Kurzem auch mit SVG-Bildern umgehen. Sie können also auch ein SVG-Bild kopieren und zur weiteren Verarbeitung in eine andere Anwendung einfügen.
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'));
});
Weitere Informationen finden Sie im Artikel Async Clipboard oder in der Datei src/js/clipboard.js
.
Dateiverwaltung
Eine meiner Lieblingsfunktionen von SVG-Code ist, wie gut er sich in das Betriebssystem einfügt. Als installierte PWA kann sie ein Datei-Handler oder sogar der Standarddatei-Handler für Bilddateien werden. Das bedeutet, dass ich auf meinem macOS-Computer im Finder mit der rechten Maustaste auf ein Bild klicken und es mit SVG-Code öffnen kann. Diese Funktion wird als Dateiverwaltung bezeichnet und basiert auf der Eigenschaft „file_handlers“ im Web-App-Manifest und der Startwarteschlange, über die die App die übergebene Datei verwenden kann.
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;
}
}
});
Weitere Informationen finden Sie unter Installierte Webanwendungen als Dateihandler verwenden. Den Quellcode finden Sie in src/js/filehandling.js
.
Webfreigabe (Dateien)
Ein weiteres Beispiel für die Einbindung in das Betriebssystem ist die Freigabefunktion der App. Angenommen, ich möchte eine mit SVGcode erstellte SVG-Datei bearbeiten. Eine Möglichkeit dazu wäre, die Datei zu speichern, die SVG-Bearbeitungs-App zu starten und die SVG-Datei dort zu öffnen. Die Web Share API bietet jedoch einen einfacheren Ablauf, da Dateien direkt freigegeben werden können. Wenn die SVG-Bearbeitungs-App ein Freigabeziel ist, kann sie die Datei direkt ohne Abweichung empfangen.
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);
}
}
}
});
Ziel für die Webfreigabe (Dateien)
Umgekehrt kann SVG-Code auch als Freigabeziel dienen und Dateien von anderen Apps empfangen. Dazu muss die App dem Betriebssystem über die Web Share Target API mitteilen, welche Datentypen sie akzeptieren kann. Das geschieht über ein spezielles Feld im Web-App-Manifest.
{
"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"]
}
]
}
}
}
Der Pfad action
existiert nicht wirklich, sondern wird ausschließlich im fetch
-Handler des Service Workers verarbeitet, der empfangene Dateien dann zur tatsächlichen Verarbeitung in der App weiterleitet.
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);
})(),
);
}
});
Fazit
Das war ein kurzer Überblick über einige der erweiterten App-Funktionen in SVG-Code. Ich hoffe, dass diese App neben anderen tollen Apps wie Squoosh oder SVGOMG ein unverzichtbares Tool für Ihre Bildverarbeitung wird.
SVGcode ist unter svgco.de verfügbar. Sehen Sie, was ich da gemacht habe? Sie können sich den Quellcode auf GitHub ansehen. Da Potrace unter der GPL-Lizenz steht, gilt dies auch für SVGcode. Viel Spaß beim Vektorisieren! Ich hoffe, dass SVGcode Ihnen nützlich ist und dass einige seiner Funktionen Sie zu Ihrer nächsten App inspirieren.
Danksagungen
Dieser Artikel wurde von Joe Medley überprüft.