我需要將SVG的可見區域轉換爲靜態圖像以進行打印和類似用途。我從閱讀中得知,該方法應該是先使用canvg
將SVG轉換爲畫布,然後使用canvas.toDataURL
將畫布轉換爲圖像。我能夠完成這些基本要求,但是我的viewbox比我的SVG小得多,因此裁剪和縮放成爲問題,而這正是我目前磕磕絆絆的地方。 我的想法是在轉換爲使用canvasContext.drawImage(...)
的圖像之前插入另外兩個步驟,將未縮放的畫布裁剪到由SVG視圖框定義的區域。這最後一步對我不起作用:我無法設法裁剪圖像並保持當前的比例。然後,我打算使用pica.resizeCanvas
來實現圖像的高質量縮放(使其適合可打印頁面)。將SVG轉換爲畫布,同時排除SVG視圖框外的區域
之前進入代碼的問題是:
- 將是對所有進場聲?
- 我在做什麼錯誤
canvasContext.drawImage(...)
該圖像結束了縮放或裁剪不正確?目標是不應用縮放,而是裁剪一些多餘的空白區域。步驟- 複印
svg
的
概述以便
canvas
使用canvg
。 這工作。- 無縮放施加
- 偏移被用於將圖像移動到左上角,準備剩餘的白色空間(右下區域)的未來裁剪。
- 複印
- 獲取新創建
canvas
保持和使用canvasContext.drawImage
繪製裁剪區域的二次canvas
。 這失敗了。畫布尺寸不正確,但縮放比例正確(即無)或畫布尺寸正確,但縮放比例不正確(縮放)。 - 使用
pica.resizeCanvas
可應用縮放,質量損失最小。 還沒有真正嘗試過。 - 使用
canvasContext.toDataURL(...)
轉換canvas到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到視框。 –
如果您想要提供全尺寸內聯svg進行打印,那麼您可以使用事件window.onbeforeprint,window.onafterprint和window.matchmedia(Chrome)。這提供了操縱svg以填充窗口的能力,然後在打印後重置它。 (這不需要畫布)。我可以舉一個例子,你想看到這種方法。 –
@FrancisHemsher如果你有一個方便的例子,我很樂意看到它。 –