Javascript 将SVG转换为画布,同时排除SVG viewbox外部的区域

Javascript 将SVG转换为画布,同时排除SVG viewbox外部的区域,javascript,canvas,svg,canvg,Javascript,Canvas,Svg,Canvg,我需要将SVG的可见区域转换为静态图像,用于打印和类似用途。我从阅读中了解到,方法应该是首先使用canvg将SVG转换为画布,然后使用canvas.toDataURL将画布转换为图像。我能够完成这些基本要求,但是我的viewbox比SVG小得多,因此裁剪和缩放成为问题,这就是我目前遇到的问题我的想法是在转换为图像之前插入另外两个步骤,我使用canvasContext.drawImage(…)将未缩放的画布裁剪到SVG viewbox定义的区域。最后一步对我不起作用:我无法裁剪图像并保持当前比例。

我需要将SVG的可见区域转换为静态图像,用于打印和类似用途。我从阅读中了解到,方法应该是首先使用
canvg
将SVG转换为画布,然后使用
canvas.toDataURL
将画布转换为图像。我能够完成这些基本要求,但是我的viewbox比SVG小得多,因此裁剪和缩放成为问题,这就是我目前遇到的问题我的想法是在转换为图像之前插入另外两个步骤,我使用
canvasContext.drawImage(…)
将未缩放的画布裁剪到SVG viewbox定义的区域。最后一步对我不起作用:我无法裁剪图像并保持当前比例。
然后我打算使用
pica.resizeCanvas
来实现图像的高质量缩放(使其适合可打印页面)

进入代码之前,问题如下:

  • 全面的做法是否合理
  • 如果
    canvasContext.drawImage(…)
    图像最终被放大或被错误裁剪,我会做错什么?目标是不应用缩放,而是裁剪一些多余的空白
步骤摘要

  • 使用
    canvg
    svg
    复制到
    canvas
    这很有效。
    • 不应用缩放
    • 偏移用于将图像移动到左上角,以便将来裁剪剩余的空白区域(右下区域)
  • 获取新创建的
    canvas
    并使用
    canvasContext.drawImage
    将裁剪区域绘制到辅助
    canvas
    这失败了。画布大小错误但缩放正确(即无),或者画布大小正确但缩放错误(向上缩放)。
  • 使用
    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;
}
函数MakeImage(){
//最小x、最小y、宽度和高度
var viewBox=parseViewBox();//定义如下
var vbMinX=viewBox[0];
var vbMinY=viewBox[1];
var vbWidth=viewBox[2];
var vbHeight=viewBox[3];
var svgUnitRatio=getSvgUnitRatio(vbHeight);//定义如下
//xMin,yMin,xMax,yMax
var boundingBox=getBounds();//定义如下
var bbXmin=boundingBox[0];
var bbYmin=边界框[1];
var bbXmax=边界框[2];
var bbYmax=边界框[3];
var offsetX=(vbMinX-bbXmin)*svgUnitRatio;
var offsetY=(vbMinY-bbYmin)*svgUnitRatio;
var调整宽度=(bbXmax-bbXmin)*svgUnitRatio;
var调整高度=(bbYmax-bbYmin)*Svgunitro;
变量选项={
ignoreDimensions:false,//允许它根据svg大小调整画布大小
offsetX:offsetX,
越位
};
//首先,我们将svg复制到画布,不应用任何缩放
window.canvg(“workspaceCanvas”,$(“#mysvg”).parent().html(),options);
//现在我们根据svg视图框进行裁剪
var canvas=document.getElementById(“canvas”);
var workspacenavas=document.getElementById(“workspacenavas”);
var context=canvas.getContext('2d');
drawImage(workspaceCanvas,0,0,adjustedWidth,adjustedHeight,0,0,adjustedWidth,adjustedHeight);//我想这里有问题吧???
//接下来,我们对画布进行高质量缩放
var pOptions={//可能这有问题,但在正确执行前一步之前,我不会知道
质量:3,,
阿尔法:是的,
未锐化金额:50,
不锐化半径:0.5,
取消锐化阈值:0
};
//暂时不要尝试这个
window.pica.resizeCanvas(工作空间画布、画布、pOptions、函数(err){/*这是一个强制参数*/});
var img=canvas.toDataURL(“image/png,1”);
//处理图像数据
}
函数getSvgUnitRatio(viewboxHeight){
//不需要担心宽度,因为纵横比应该被锁定
var height=parseFloat(d3.select(#mysvg”).attr(“height”);
返回高度/viewboxHeight;
}
函数getBounds(){
//xMin,yMin,xMax,yMax
var boundingBox=[];
var xMin=Number.MAX\u SAFE\u整数;
var yMin=Number.MAX\u SAFE\u整数;
var xMax=Number.MIN\u SAFE\u整数;
var yMax=Number.MIN\u SAFE\u整数;
window.svg.selectAll(“.elementsICareAbout”).nodes().forEach(函数(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”);
如果(dx+宽度>xMax){
xMax=dx+宽度;
}
if(dxyMax){
yMax=dy+高度;
}
if(dy
如果要提供完整大小的内联svg进行打印,则可以使用events window.onbeforeprint、window.onafterprint和window.matchmedia(Chrome)。这提供了操作svg填充窗口,然后在打印后重置窗口的能力。(这不太可能