SVGcode — это прогрессивное веб-приложение, позволяющее преобразовывать растровые изображения, такие как JPG, PNG, GIF, WebP, AVIF и т. д., в векторную графику в формате SVG. Оно использует API доступа к файловой системе, API асинхронного буфера обмена, API обработки файлов и настройку наложения элементов управления окнами.
Из растра в вектор
Вы когда-нибудь масштабировали изображение, а результат был пикселизированным и неудовлетворительным? Если да, то вы, вероятно, имели дело с растровым форматом изображения, таким как WebP, PNG или JPG.
Напротив, векторная графика — это изображения, которые определяются точками в системе координат. Эти точки соединены линиями и кривыми, образуя многоугольники и другие фигуры. Векторная графика имеет преимущество перед растровой графикой в том, что ее можно масштабировать до любого разрешения без пикселизации.
Знакомство с SVGcode
Я создал PWA под названием SVGcode , который может помочь вам преобразовать растровые изображения в векторные. Благодарность там, где это необходимо: я не изобрел это. С SVGcode я просто стою на плечах инструмента командной строки под названием Potrace Питера Селинджера , который я преобразовал в Web Assembly , чтобы его можно было использовать в веб-приложении.

Использование SVG-кода
Сначала я хочу показать вам, как пользоваться приложением. Я начну с тизерного изображения для Chrome Dev Summit, которое я скачал с канала ChromiumDev в Twitter. Это растровое изображение PNG, которое я затем перетаскиваю в приложение SVGcode. Когда я перетаскиваю файл, приложение трассирует изображение цвет за цветом, пока не появится векторизованная версия ввода. Теперь я могу увеличить изображение, и, как вы видите, края остаются четкими. Но увеличив масштаб логотипа Chrome, вы увидите, что трассировка была неидеальной, и особенно контуры логотипа выглядят немного пятнистыми. Я могу улучшить результат, удалив пятнистость трассировки, подавив пятнистость размером, скажем, до пяти пикселей.
Постеризация в SVGcode
Важным шагом векторизации, особенно для фотографических изображений, является постеризация входного изображения для уменьшения количества цветов. SVGcode позволяет мне делать это по каждому цветовому каналу и видеть полученный SVG по мере внесения изменений. Когда я буду доволен результатом, я могу сохранить SVG на жестком диске и использовать его где угодно.
API, используемые в SVGcode
Теперь, когда вы увидели, на что способно приложение, позвольте мне показать вам некоторые API, которые помогают творить чудеса.
Прогрессивное веб-приложение
SVGcode — это устанавливаемое Progressive Web App, поэтому оно полностью офлайн-доступно. Приложение основано на шаблоне Vanilla JS для Vite.js и использует популярный плагин Vite PWA , который создает service worker, использующий Workbox.js под капотом. Workbox — это набор библиотек, которые могут обеспечить работу service worker для Progressive Web Apps, готового к производству. Этот шаблон может не обязательно работать для всех приложений, но для варианта использования SVGcode он великолепен.
Наложение элементов управления окнами
Чтобы максимально использовать доступное экранное пространство, SVGcode использует настройку Window Controls Overlay , перемещая свое главное меню вверх в область заголовка. Вы можете увидеть, как это активируется в конце процесса установки.
API доступа к файловой системе
Чтобы открыть файлы входных изображений и сохранить полученные SVG, я использую API File System Access . Это позволяет мне сохранять ссылку на ранее открытые файлы и продолжать с того места, на котором я остановился, даже после перезагрузки приложения. Всякий раз, когда изображение сохраняется, оно оптимизируется с помощью библиотеки svgo , что может занять некоторое время в зависимости от сложности SVG. Для отображения диалогового окна сохранения файла требуется жест пользователя. Поэтому важно получить дескриптор файла до того, как произойдет оптимизация SVG, чтобы жест пользователя не стал недействительным к моменту готовности оптимизированного 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);
}
Перетащите и отпустите
Для открытия входного изображения я могу либо использовать функцию открытия файла, либо, как вы видели выше, просто перетащить файл изображения в приложение. Функция открытия файла довольно проста, более интересен случай перетаскивания. Что особенно приятно в этом, так это то, что вы можете получить дескриптор файловой системы из элемента передачи данных через метод getAsFileSystemHandle()
. Как упоминалось ранее, я могу сохранить этот дескриптор, чтобы он был готов, когда приложение перезагрузится.
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);
}
});
Более подробную информацию можно найти в статье File System Access API и, если вам интересно, изучите исходный код SVGcode в src/js/filesystem.js
.
API асинхронного буфера обмена
SVGcode также полностью интегрирован с буфером обмена операционной системы через API Async Clipboard. Вы можете вставлять изображения из проводника файлов операционной системы в приложение, нажав кнопку вставки изображения или нажав command или control плюс v на клавиатуре.
API асинхронного буфера обмена недавно получил возможность работать и с изображениями SVG, поэтому вы также можете скопировать изображение SVG и вставить его в другое приложение для дальнейшей обработки.
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'));
});
Чтобы узнать больше, прочитайте статью Async Clipboard или посмотрите файл src/js/clipboard.js
.
Обработка файлов
Одна из моих любимых функций SVGcode — это то, как хорошо он вписывается в операционную систему. Как установленный PWA, он может стать обработчиком файлов или даже обработчиком файлов по умолчанию для файлов изображений. Это означает, что когда я нахожусь в Finder на своей машине macOS, я могу щелкнуть правой кнопкой мыши по изображению и открыть его с помощью SVGcode. Эта функция называется File Handling и работает на основе свойства file_handlers в Web App Manifest и очереди запуска, что позволяет приложению использовать переданный файл.
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;
}
}
});
Для получения дополнительной информации см. статью «Пусть установленные веб-приложения будут обработчиками файлов » и просмотрите исходный код в src/js/filehandling.js
.
Веб-общение (файлы)
Другим примером слияния с операционной системой является функция общего доступа приложения. Если я хочу внести изменения в SVG, созданный с помощью SVGcode, одним из способов решения этой проблемы будет сохранение файла, запуск приложения для редактирования SVG, а затем открытие файла SVG оттуда. Однако более плавный процесс — использовать API Web Share , который позволяет делиться файлами напрямую. Таким образом, если приложение для редактирования SVG является целью общего доступа, оно может напрямую получать файл без отклонений.
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);
}
}
}
});
Веб-ресурс Share Target (файлы)
С другой стороны, SVGcode также может выступать в качестве цели общего доступа и получать файлы из других приложений. Чтобы это работало, приложению необходимо сообщить операционной системе через API Web Share Target, какие типы данных оно может принимать. Это происходит через специальное поле в 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"]
}
]
}
}
}
Маршрут action
на самом деле не существует, а обрабатывается исключительно в обработчике fetch
Service Worker, который затем передает полученные файлы для фактической обработки в приложении.
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);
})(),
);
}
});
Заключение
Хорошо, это был краткий обзор некоторых расширенных функций приложения в SVGcode. Надеюсь, это приложение станет важным инструментом для ваших потребностей в обработке изображений наряду с другими замечательными приложениями, такими как Squoosh или SVGOMG .
SVGcode доступен на svgco.de . Посмотрите, что я там сделал? Вы можете просмотреть его исходный код на GitHub . Обратите внимание, что поскольку Potrace имеет лицензию GPL, то и SVGcode тоже. И с этим, счастливой векторизации! Надеюсь, SVGcode будет полезен, и некоторые из его функций могут вдохновить ваше следующее приложение.
Благодарности
Эту статью рецензировал Джо Медли .