SVGcode ist eine Progressive Web App, mit der Sie Rasterbilder wie JPG, PNG, GIF, WebP und AVIF in Vektorgrafiken im SVG-Format konvertieren können. Sie verwendet die File System Access API, die Async Clipboard API, die File Handling API und die Anpassung des Window Controls Overlay.
Von Raster zu Vektor
Haben Sie schon einmal ein Bild skaliert und das Ergebnis war pixelig und unbefriedigend? Wenn ja, haben Sie es wahrscheinlich mit einem Rasterbildformat wie WebP, PNG oder JPG zu tun.
Vektorgrafiken hingegen sind Bilder, die durch Punkte in einem Koordinatensystem definiert werden. 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 Pixelbildung auf jede beliebige Auflösung skaliert werden können.
SVGcode
Ich habe eine PWA namens SVGcode entwickelt, mit der Sie Rasterbilder in Vektoren konvertieren können. Ich habe das nicht erfunden. Mit SVGcode nutze ich ein Befehlszeilentool namens Potrace von Peter Selinger, das ich in WebAssembly konvertiert habe, damit es in einer Web-App verwendet werden kann.

SVGcode verwenden
Zuerst möchte ich Ihnen zeigen, wie Sie die App verwenden. Ich beginne mit dem Teaserbild für den Chrome Dev Summit, das ich vom Twitter-Kanal ChromiumDev heruntergeladen habe. Das ist ein PNG-Rasterbild, das ich dann in die SVGcode-App ziehe. Wenn ich die Datei loslasse, wird das Bild in der App Farbe für Farbe nachgezeichnet, bis eine vektorisierte Version der Eingabe angezeigt wird. Ich kann jetzt in das Bild hineinzoomen und wie Sie sehen, bleiben die Ränder scharf. Wenn Sie jedoch das Chrome-Logo vergrößern, sehen Sie, dass die Konturen nicht perfekt sind und vor allem die Umrisse des Logos etwas gesprenkelt aussehen. Ich kann das Ergebnis verbessern, indem ich das Tracing entflecke und Flecken mit einer Größe von bis zu fünf Pixeln unterdrücke.
Posterisierung in SVGcode
Ein wichtiger Schritt für die Vektorisierung, insbesondere bei fotografischen Bildern, ist die Posterisierung des Eingabebilds, um die Anzahl der Farben zu reduzieren. Mit SVGcode kann ich das für jeden Farbkanal tun und das resultierende SVG sehen, während ich Änderungen vornehme. Wenn ich mit dem Ergebnis zufrieden bin, kann ich die SVG-Datei auf meiner Festplatte speichern und sie verwenden, wo immer ich möchte.
In SVGcode verwendete APIs
Nachdem Sie nun gesehen haben, was die App alles kann, möchte ich Ihnen einige der APIs zeigen, die das möglich machen.
Progressive Web-App
SVGcode ist eine installierbare progressive Web-App und kann daher vollständig offline verwendet werden. 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 produktionsreifer Service Worker für Progressive Web-Apps erstellt werden kann. Dieses Muster funktioniert möglicherweise nicht für alle Apps, aber für den Anwendungsfall von SVGcode ist es ideal.
Window Controls Overlay
Um den verfügbaren Bildschirmplatz zu maximieren, verwendet SVGcode die Anpassung Window Controls Overlay, indem das Hauptmenü in den Titelleistenbereich 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 SVG-Dateien verwende ich die File System Access API. So kann ich einen Verweis auf zuvor geöffnete Dateien behalten und dort weitermachen, wo ich aufgehört habe, auch nach dem Neuladen der App. Immer wenn ein Bild gespeichert wird, wird es über die svgo-Bibliothek optimiert. Das kann je nach Komplexität des SVG-Bilds einen Moment dauern. Zum Anzeigen des Dialogfelds zum Speichern von Dateien ist eine Nutzergeste erforderlich. Es ist daher wichtig, das Dateihandle vor der SVG-Optimierung abzurufen, damit die Nutzeraktion nicht ungültig wird, bis das optimierte SVG fertig 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
Um ein Eingabebild zu öffnen, kann ich entweder die Funktion zum Öffnen von Dateien verwenden oder, wie oben gezeigt, einfach eine Bilddatei per Drag-and-drop in die App ziehen. Die Funktion zum Öffnen von Dateien ist ziemlich einfach. Interessanter ist der Fall mit Drag-and-drop. Besonders praktisch ist, dass Sie über die Methode getAsFileSystemHandle()
ein Dateisystem-Handle für das Datenübertragungselement abrufen können. Wie bereits erwähnt, kann ich dieses Handle beibehalten, sodass es verfügbar 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 sich dafür interessieren, können Sie sich den SVGcode-Quellcode unter src/js/filesystem.js
ansehen.
Async Clipboard API
SVGcode ist über die Async Clipboard API auch vollständig in die Zwischenablage des Betriebssystems eingebunden. Sie können Bilder aus dem Datei-Explorer des Betriebssystems in die App einfügen, indem Sie entweder auf die Schaltfläche zum Einfügen von Bildern klicken oder auf der Tastatur die Befehls- oder Steuerungstaste und die Taste V drücken.
Die Async Clipboard API kann seit Kurzem auch SVG-Bilder verarbeiten. Sie können also auch ein SVG-Bild kopieren und in eine andere Anwendung einfügen, um es weiter zu verarbeiten.
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 SVGcode ist, wie gut es sich in das Betriebssystem einfügt. Als installierte PWA kann sie ein Datei-Handler oder sogar der Standard-Datei-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 SVGcode öffnen kann. Diese Funktion heißt „File Handling“ und basiert auf der Eigenschaft „file_handlers“ im Web-App-Manifest und der Startwarteschlange, über die die App die übergebene Datei nutzen 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 festlegen. Den Quellcode finden Sie unter src/js/filehandling.js
.
Web Share (Dateien)
Ein weiteres Beispiel für die Integration in das Betriebssystem ist die Freigabefunktion der App. Wenn ich eine mit SVGcode erstellte SVG-Datei bearbeiten möchte, kann ich die Datei speichern, die SVG-Bearbeitungs-App starten und die SVG-Datei dann dort öffnen. Ein reibungsloserer Ablauf ist jedoch die Verwendung der Web Share API, mit der Dateien direkt freigegeben werden können. Wenn die SVG-Bearbeitungs-App also 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);
}
}
}
});
Web Share Target (Dateien)
Umgekehrt kann SVGcode auch als Freigabeziel fungieren und Dateien von anderen Apps empfangen. Damit das funktioniert, muss die App dem Betriebssystem über die Web Share Target API mitteilen, welche Datentypen sie akzeptieren kann. Das erfolgt ü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"]
}
]
}
}
}
Die action
-Route ist nicht wirklich vorhanden, sondern wird nur im fetch
-Handler des Service Workers verarbeitet, der dann empfangene Dateien zur eigentlichen 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 SVGcode. Ich hoffe, dass diese App neben anderen großartigen Apps wie Squoosh oder SVGOMG zu einem wichtigen Tool für Ihre Bildverarbeitungsanforderungen werden kann.
SVGcode ist unter svgco.de verfügbar. Verstehst du, was ich gemacht habe? Sie können den Quellcode auf GitHub ansehen. Da Potrace unter der GPL lizenziert ist, gilt dies auch für SVGcode. Viel Spaß beim Vektorisieren! Ich hoffe, dass SVGcode nützlich ist und einige der Funktionen Sie bei Ihrer nächsten App inspirieren können.
Danksagungen
Dieser Artikel wurde von Joe Medley überprüft.