SVGcode to progresywna aplikacja internetowa, która umożliwia konwertowanie obrazów rastrowych, takich jak JPG, PNG, GIF, WebP, AVIF itp., na grafikę wektorową w formacie SVG. Aplikacja korzysta z interfejsów File System Access API, Async Clipboard API, File Handling API i Window Controls Overlay.
Z rastera na wektor
Czy zdarzyło Ci się kiedykolwiek skalować obraz, a efekt był ziarnisty i niesatysfakcjonujący? Jeśli tak, prawdopodobnie masz do czynienia z formatem obrazu rastrowego, takim jak WebP, PNG lub JPG.
Grafika wektorowa to natomiast obrazy zdefiniowane przez punkty w układzie współrzędnych. Punkty te są połączone liniami i krzywiznami, tworząc wielokąty i inne kształty. Grafika wektorowa ma tę zaletę nad grafiką rastrową, że można ją powiększyć lub zmniejszyć do dowolnej rozdzielczości bez utraty jakości.
Przedstawiamy SVGcode
Stworzyłem aplikację PWA o nazwie SVGcode, która może pomóc w konwertowaniu obrazów rastrowych na wektory. Odpowiednie przypisywanie udziału w konwersji: nie ja wymyśliłem tego rozwiązania. W przypadku SVGcode korzystam z narzędzi wiersza poleceń o nazwie Potrace stworzonego przez Petera Selingera. Konwertuję je na Web Assembly, aby można było z niego korzystać w aplikacji internetowej.
Za pomocą SVGcode
Najpierw pokażę, jak korzystać z aplikacji. Zaczynam od teasera Chrome Dev Summit, który pobrałem z kanału ChromiumDev na Twitterze. To rastrowy obraz PNG, który przeciągam do aplikacji SVGcode. Gdy upuszczę plik, aplikacja będzie śledzić kolory obrazu, aż pojawi się wektorowa wersja danych wejściowych. Teraz mogę powiększyć obraz i jak widzisz, krawędzie pozostają ostre. Po zbliżeniu logo Chrome widać jednak, że śledzenie nie było idealne, zwłaszcza kontury logo wyglądają nieco nierówno. Mogę poprawić wynik, usuwając z wykresu plamki o rozmiary do 5 pikseli.
Posteryzacja w SVGcode
Ważnym krokiem w procesie wektoryzacji, zwłaszcza w przypadku obrazów fotograficznych, jest posteryzacja wejściowego obrazu w celu zmniejszenia liczby kolorów. SVGcode pozwala mi to robić w przypadku każdego kanału kolorów i oglądać wynikowy plik SVG w miarę wprowadzania zmian. Gdy uzyskam zadowalający efekt, mogę zapisać plik SVG na dysku twardym i używać go gdziekolwiek zechcę.
Interfejsy API używane w SVGcode
Teraz, gdy już wiesz, na co stać aplikację, pokażę Ci kilka interfejsów API, które sprawiają, że wszystko działa jak należy.
Progresywna aplikacja internetowa
SVGcode to instalowana progresywna aplikacja internetowa, która działa w trybie offline. Aplikacja opiera się na szablonie Vanilla JS dla Vite.js i korzysta z popularnej wtyczki VITE PWA, która tworzy usługę workera, która pod spodem korzysta z Workbox.js. Workbox to zbiór bibliotek, które mogą służyć do tworzenia skryptów service worker dostępnych w wersji produkcyjnej w progresywnych aplikacjach internetowych. Ten wzór może nie działać w przypadku wszystkich aplikacji, ale w przypadku SVGcode jest świetny.
Nakładka z elementami sterującymi okna
Aby zmaksymalizować dostępną przestrzeń na ekranie, SVGcode używa nakładki z elementami sterującymi okna, przenosząc główne menu do obszaru paska tytułu. Możesz zobaczyć, jak to działa, na końcu procesu instalacji.
File System Access API
Aby otwierać pliki obrazów wejściowych i zapisywać powstałe pliki SVG, używam interfejsu File System Access API. Pozwala mi to zachować odniesienie do wcześniej otwartych plików i kontynuować pracę w miejscu, w którym ją przerwałem, nawet po ponownym załadowaniu aplikacji. Za każdym razem, gdy obraz zostanie zapisany, zostanie zoptymalizowany za pomocą biblioteki svgo. Może to chwilę potrwać, w zależności od złożoności pliku SVG. Wyświetlenie okna zapisywania pliku wymaga gestu użytkownika. Dlatego ważne jest, aby uzyskać uchwyt pliku przed optymalizacją SVG, aby gest użytkownika nie został unieważniony do czasu, gdy gotowy będzie zoptymalizowany plik SVG.
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);
}
Przeciągnij i upuść
Aby otworzyć obraz wejściowy, mogę użyć funkcji otwierania plików lub, jak widać powyżej, przeciągnąć i upuścić plik obrazu w aplikacji. Funkcja otwierania plików jest dość prosta, ale ciekawszy jest przypadek przeciągania i upuszczania. Jest to szczególnie przydatne, ponieważ możesz uzyskać uchwyt systemu plików z elementu przesyłania danych za pomocą metody getAsFileSystemHandle()
. Jak już wspomniałem, mogę zachować ten identyfikator, aby był gotowy, gdy aplikacja zostanie ponownie załadowana.
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);
}
});
Więcej informacji znajdziesz w artykule o interfejsie File System Access API. Jeśli chcesz, możesz też zapoznać się z kodem źródłowym SVGcode w src/js/filesystem.js
.
Async Clipboard API
SVGcode jest też w pełni zintegrowany ze schowkiem systemu operacyjnego za pomocą interfejsu Async Clipboard API. Obrazy z eksploratora plików systemu operacyjnego możesz wkleić do aplikacji, klikając przycisk wklejania obrazu lub naciskając Command lub Control + V na klawiaturze.
Interfejs Async Clipboard API został niedawno rozszerzony o obsługę obrazów SVG, dzięki czemu możesz kopiować obrazy SVG i wklejać je w innej aplikacji w celu dalszego przetwarzania.
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'));
});
Więcej informacji znajdziesz w artykule Schowek asynchroniczny lub pliku src/js/clipboard.js
.
Obsługa plików
Jedną z moich ulubionych funkcji SVGcode jest to, jak dobrze komponuje się on z systemem operacyjnym. Jako zainstalowana PWA może ona obsługiwać pliki, a nawet być domyślną aplikacją do obsługi plików graficznych. Oznacza to, że gdy jestem w Finderze na komputerze z systemem macOS, mogę kliknąć obraz prawym przyciskiem myszy i otworzyć go za pomocą SVGcode. Ta funkcja nosi nazwę obsługi plików i działa na podstawie właściwości file_handlers w pliku manifestu aplikacji internetowej i kole zadań, co pozwala aplikacji na wykorzystanie przekazanego pliku.
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;
}
}
});
Więcej informacji znajdziesz w artykule Ustawianie zainstalowanych aplikacji internetowych jako modułów obsługi plików. Kod źródłowy możesz wyświetlić w sekcji src/js/filehandling.js
.
Udostępnianie przez internet (pliki)
Innym przykładem dopasowania do systemu operacyjnego jest funkcja udostępniania w aplikacji. Załóżmy, że chcę wprowadzić zmiany w pliku SVG utworzonym za pomocą SVGcode. W tym celu mogę zapisać plik, uruchomić aplikację do edycji SVG, a potem otworzyć plik SVG. Bardziej płynny proces to jednak użycie interfejsu Web Share API, który umożliwia bezpośrednie udostępnianie plików. Jeśli więc aplikacja do edycji plików SVG jest celem udostępniania, może bezpośrednio odbierać plik bez odchyleń.
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);
}
}
}
});
Docelowy adres udostępniania w przeglądarce (pliki)
Odwrotnie, SVGcode może też działać jako docelowa aplikacja do udostępniania i odbierać pliki z innych aplikacji. Aby to działało, aplikacja musi poinformować system operacyjny za pomocą interfejsu Web Share Target API, jakie typy danych może akceptować. Dzieje się to za pomocą specjalnego pola w pliku manifestu aplikacji internetowej.
{
"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"]
}
]
}
}
}
Ścieżka action
nie istnieje, ale jest obsługiwana wyłącznie w obiekcie fetch
w ramach usługi workera, który następnie przekazuje otrzymane pliki do przetworzenia w aplikacji.
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);
})(),
);
}
});
Podsumowanie
To była krótka prezentacja zaawansowanych funkcji aplikacji SVGcode. Mam nadzieję, że ta aplikacja stanie się podstawowym narzędziem do przetwarzania obrazów, obok innych świetnych aplikacji, takich jak Squoosh czy SVGOMG.
SVGcode jest dostępny na stronie svgco.de. Widzisz, co zrobiłem? Kod źródłowy znajdziesz na GitHubie. Pamiętaj, że ponieważ Potrace jest objęty licencją GPL, tak samo jest w przypadku SVGcode. Życzę przyjemnej pracy z wektorami! Mam nadzieję, że SVGcode okaże się przydatny, a jego funkcje zainspirują Cię do stworzenia kolejnej aplikacji.
Podziękowania
Ten artykuł został sprawdzony przez Joe Medley.