Можно ли сделать PNG из SVG?
Что проверяют
Понимаете ли вы разницу между вектором и растром и знаете ли, где именно происходит растеризация. Вопрос обычно растёт из задачи «дай кнопку скачать картинку», и смотрят, сделаете ли вы это без сервера.
Как отвечать
Да, и прямо в браузере. Схема такая: сериализовать SVG в строку, отдать её картинке, нарисовать картинку на canvas, забрать растр.
const svg = new XMLSerializer().serializeToString(node);
const url = URL.createObjectURL(new Blob([svg], { type: "image/svg+xml" }));
const img = new Image();
img.onload = () => {
const canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 600;
canvas.getContext("2d").drawImage(img, 0, 0, 800, 600);
canvas.toBlob((blob) => save(blob), "image/png");
URL.revokeObjectURL(url);
};
img.src = url;Что добавить голосом: размер растра задаёте вы сами, поэтому под экраны с высокой плотностью рисуйте с множителем devicePixelRatio. toBlob предпочтительнее toDataURL, потому что не держит в памяти длинную строку base64. Если нужен гарантированно точный результат со шрифтами и фильтрами, растеризуют на сервере: headless-браузером или отдельной библиотекой.
Где спотыкаются
Первое: говорят, что PNG «теряет качество». Сжатие в PNG без потерь, портится картинка только при растягивании готового растра, потому что пикселей в нём больше не становится. Масштабируется векторный исходник, а не результат.
Второе: забывают, что SVG внутри <img> работает в изолированном режиме. Внешние шрифты, стили страницы и внешние картинки туда не подтягиваются, скрипты не выполняются. Шрифт надо вшить в сам файл, а стили перенести в атрибуты или внутрь SVG, иначе на canvas приедет другой рисунок.
Третье: не помнят про «испорченный» canvas. Если SVG пришёл с чужого домена без CORS или сам тянет чужие ресурсы, toBlob бросит ошибку безопасности. Плюс частая мелочь: без атрибута xmlns и без размеров или viewBox картинка просто не загрузится.