Files

94 lines
3.2 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/infrastructure/svg-to-png.js
/**
* @param {SVGElement} svg - виртуальный SVG (готовый для рендеринга)
* @param {{x:number,y:number,width:number,height:number}} rect - область в единицах SVG user units
* @param {number} scale - множитель (вызов передаёт, например, 3)
* @param {(blob:Blob|null)=>void} callBack
*/
export function svgToPng(svg, rect, scale, callBack) {
if (!svg || !rect || rect.width <= 0 || rect.height <= 0) {
callBack(null);
return;
}
// output размеры с учётом devicePixelRatio
const dpr = window.devicePixelRatio || 1;
const outputWidth = Math.round(rect.width * scale * dpr);
const outputHeight = Math.round(rect.height * scale * dpr);
// Сериализуем svg в строку и делаем blob/url
let svgString;
try {
svgString = new XMLSerializer().serializeToString(svg);
} catch (e) {
callBack(null);
return;
}
let url;
try {
url = URL.createObjectURL(new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }));
} catch (e) {
callBack(null);
return;
}
const img = new Image();
// crossOrigin можно добавить, если нужно: img.crossOrigin = 'anonymous';
img.onload = function () {
try {
const canvas = document.createElement('canvas');
canvas.width = outputWidth;
canvas.height = outputHeight;
canvas.style.width = `${outputWidth}px`;
canvas.style.height = `${outputHeight}px`;
const ctx = canvas.getContext('2d');
if (!ctx) {
URL.revokeObjectURL(url);
callBack(null);
return;
}
ctx.imageSmoothingEnabled = false;
// Если rect.x/rect.y отрицательные => смещение исходного изображения внутри canvas
const sx = Math.max(0, rect.x * scale * dpr);
const sy = Math.max(0, rect.y * scale * dpr);
const sWidth = rect.width * scale * dpr;
const sHeight = rect.height * scale * dpr;
// dx/dy: смещение на canvas (если rect.x < 0, то мы сдвигаем вправо)
const dx = rect.x < 0 ? -rect.x * scale * dpr : 0;
const dy = rect.y < 0 ? -rect.y * scale * dpr : 0;
// drawImage с указанием исходной области и целевой области
ctx.drawImage(
img,
sx, // sx
sy, // sy
sWidth, // sWidth
sHeight, // sHeight
dx, // dx (на canvas)
dy, // dy
outputWidth, // dWidth
outputHeight // dHeight
);
URL.revokeObjectURL(url);
canvas.toBlob(blob => {
callBack(blob);
}, 'image/png');
} catch (err) {
URL.revokeObjectURL(url);
callBack(null);
}
};
img.onerror = function () {
try { URL.revokeObjectURL(url); } catch (e) {}
callBack(null);
};
img.src = url;
}