Мне нужно преобразовать видимую область SVG в статическое изображение для печати и аналогичных целей. Я понимаю, что подход должен состоять в том, чтобы сначала преобразовать SVG в холст с помощью canvg
, а затем преобразовать холст в изображение с помощью canvas.toDataURL
. Я могу выполнить эти основные требования, однако мой viewbox намного меньше, чем мой SVG, таким образом, обрезка и масштабирование становятся проблемами, и именно здесь я сейчас спотыкаюсь. Моей мыслью было вставить еще два шага перед преобразованием в изображение, где я использую canvasContext.drawImage(...)
, чтобы обрезать немасштабированный холст в область, определенную в окне просмотра SVG. Этот последний шаг не работает для меня: я не могу обрезать изображение и поддерживать текущий масштаб. Затем я намерен использовать pica.resizeCanvas
для достижения высокого качества масштабирования изображения (чтобы он соответствовал печатаемой странице).Преобразование SVG в холст, за исключением области вне окна просмотра SVG
Перед тем, как в коде на вопросы:
- ли над всем подход звука?
- Что я делаю неправильно с
canvasContext.drawImage(...)
, что изображение либо заканчивается масштабированным, либо обрезанным неправильно? Цель состоит в том, чтобы не применять масштабирование, а обрезать лишнее пустое пространство.
Резюме шагов
- Копирование
svg
вcanvas
с помощьюcanvg
. Это работает.- масштабирование не применяется
- Смещения используются для перемещения изображения в верхнем левом углу, в рамках подготовки к будущей кадрирование оставшегося белого пространства (нижняя правая область).
- Овладейте вновь созданного
canvas
и привлечь обрезается область к вторичномуcanvas
с помощьюcanvasContext.drawImage
. Это не удается. Либо холст - это неправильный размер, но масштабирование является правильным (т.е. none), или холст имеет нужный размер, но масштабирование неверно (масштабируется). - Используйте
pica.resizeCanvas
для применения масштабирования с минимальной потерей качества. Пока еще не пробовал. - Использование
canvasContext.toDataURL(...)
для преобразования холста вpng
. Это работает.
Код
function MakeImage() {
//min-x, min-y, width and height
var viewBox = parseViewBox(); //defined below
var vbMinX = viewBox[0];
var vbMinY = viewBox[1];
var vbWidth = viewBox[2];
var vbHeight = viewBox[3];
var svgUnitRatio = getSvgUnitRatio(vbHeight); //defined below
//xMin,yMin,xMax,yMax
var boundingBox = getBounds(); //defined below
var bbXmin = boundingBox[0];
var bbYmin = boundingBox[1];
var bbXmax = boundingBox[2];
var bbYmax = boundingBox[3];
var offsetX = (vbMinX - bbXmin) * svgUnitRatio;
var offsetY = (vbMinY - bbYmin) * svgUnitRatio;
var adjustedWidth = (bbXmax - bbXmin) * svgUnitRatio;
var adjustedHeight = (bbYmax - bbYmin) * svgUnitRatio;
var options = {
ignoreDimensions: false, //allow it to resize the canvas based on the svg size
offsetX: offsetX,
offsetY: offsetY
};
//first we copy the svg to a canvas w/o applying any scaling
window.canvg("workspaceCanvas", $("#mysvg").parent().html(), options);
//now we crop according the svg viewbox
var canvas = document.getElementById("canvas");
var workspaceCanvas = document.getElementById("workspaceCanvas");
var context = canvas.getContext('2d');
context.drawImage(workspaceCanvas, 0, 0, adjustedWidth, adjustedHeight, 0, 0, adjustedWidth, adjustedHeight); //something is wrong here i guess???
//next we do a high quality scaling of the canvas
var pOptions = { //maybe this has problems but i won't kow until i get the previous step right
quality: 3,
alpha: true,
unsharpAmount: 50,
unsharpRadius: 0.5,
unsharpThreshold: 0
};
//holding off on trying this for now
window.pica.resizeCanvas(workspaceCanvas, canvas, pOptions, function(err) { /*this is a mandatory argument*/ });
var img = canvas.toDataURL("image/png,1");
//do stuff with image data
}
function getSvgUnitRatio(viewboxHeight) {
//shouldnt need to worry about width since the aspect ratio should be locked
var height = parseFloat(d3.select("#mysvg").attr("height"));
return height/viewboxHeight;
}
function getBounds() {
//xMin,yMin,xMax,yMax
var boundingBox = [];
var xMin = Number.MAX_SAFE_INTEGER;
var yMin = Number.MAX_SAFE_INTEGER;
var xMax = Number.MIN_SAFE_INTEGER;
var yMax = Number.MIN_SAFE_INTEGER;
window.svg.selectAll(".elementsICareAbout").nodes().forEach(function(d) {
var dx = parseFloat(d.getAttribute("x"));
var dy = parseFloat(d.getAttribute("y"));
var width = parseFloat(d.getAttribute("width"));
var height = parseFloat(d.getAttribute("height"));
if (dx + width > xMax) {
xMax = dx + width;
}
if (dx < xMin) {
xMin = dx;
}
if (dy + height > yMax) {
yMax = dy + height;
}
if (dy < yMin) {
yMin = dy;
}
});
var padding = 25; //add some fluff
//xMin,yMin,xMax,yMax
boundingBox = [
xMin - padding, yMin - padding, xMax + padding, yMax + padding
];
return boundingBox;
}
function parseViewBox() {
var str = d3.select("#mysvg").attr("viewBox");
var parts = str.split(" ");
var parsed = [];
parts.forEach(function(p) {
parsed.push(parseFloat(p));
});
return parsed;
}
Вы всегда можете применить клип или clipPath к Viewbox. –
Если вы хотите предоставить полноразмерный встроенный svg для печати, вы можете использовать окна событий window.onbeforeprint, window.onafterprint и window.matchmedia (Chrome). Это позволяет манипулировать svg, чтобы заполнить окно, а затем сбросить его после печати. (Это не нужно холст). Я могу привести пример, вы хотите увидеть этот подход. –
@FrancisHemsher, если у вас есть пример, который мне бы очень понравился. –