我想弄清楚为什么这不会将画布保存为PNG。
我包含了很多代码,因为我确信它会干扰自身,但不知道如何。我已经使用类似的应用程序进行了修补,并且没有遇到过这个问题:请注意当你选择Save it时如何炸毁画布但是没有做到应该将画布保存为PNG到底应该做什么你的电脑。
我得到的错误是:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
at n.__toDataURL (https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js:1:111706)
at n.__toDataURLWithMultiplier (https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js:1:111496)
at n.toDataURL (https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js:1:111060)
at downloadFabric (file://portrait.js:207:21)
at HTMLButtonElement.onclick (file://index.html:62:114)
这是我的代码:
var canvas = new fabric.Canvas('c', {
preserveObjectStacking: true
});
canvas.setHeight(412);
canvas.setWidth(637);
var oImg, oImg2, isImageLoaded;
// oImgObj bread and butter, kudos @grunt
function replaceImage(oImgObj, imgUrl) {
if (!isImageLoaded) return; //return if initial image not loaded
var imgElem = oImgObj._element; //reference to actual image element
imgElem.src = imgUrl; //set image source
imgElem.onload = () => canvas.renderAll(); //render on image load
}
// initialize default frame (light brown wood oval)
fabric.Image.fromURL('https://i.imgur.com/DrzSWSa.png', function(img) {
isImageLoaded = true;
oImg = img.set({
selectable: false,
evented: false,
}).scale(0.5);
canvas.add(oImg).renderAll();
canvas.sendToBack(oImg);
});
// add photo (link)
$(function() {
$("#upload_link").on('click', function(e) {
e.preventDefault();
$("#file:hidden").trigger('click');
});
});
// add photo
document.getElementById('file').addEventListener("change", function(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(f) {
var data = f.target.result;
fabric.Image.fromURL(data, function(img) {
var oImg = img.set({
left: 400,
top: 102,
centeredScaling: true,
lockUniScaling: true,
cornerStyle: 'circle',
transparentCorners: false,
}).scale(.8);
canvas.add(oImg);
canvas.setActiveObject(oImg);
var image = canvas.getActiveObject();
image.moveTo(-1);
canvas.discardActiveObject();
canvas.renderAll();
canvas.sendToBack(oImg);
});
};
reader.readAsDataURL(file);
});
// Some Text
canvas.add(new fabric.IText('Some Text', {
left: 475,
top: 25,
fontSize: 27,
hasBorders: true,
hasControls: false,
selectable: true,
lockRotation: true,
lockMovementX: true,
lockMovementY: true,
align: 'mid',
originX: 'center',
originY: 'center',
centeredScaling: true,
}));
// Some Text
canvas.add(new fabric.IText('Some Text', {
left: 475,
top: 60,
fontSize: 27,
hasBorders: true,
hasControls: false,
selectable: true,
lockRotation: true,
lockMovementX: true,
lockMovementY: true,
align: 'mid',
originX: 'center',
originY: 'center',
centeredScaling: true,
}));
// Text Style Options
var underline = document.getElementById('btn-underline');
var bold = document.getElementById('btn-bold');
var italic = document.getElementById('btn-italic');
underline.addEventListener('click', function() {
dtEditText('underline');
});
bold.addEventListener('click', function() {
dtEditText('bold');
});
italic.addEventListener('click', function() {
dtEditText('italic');
});
// Font Styling
function dtEditText(action) {
var a = action;
var o = canvas.getActiveObject();
var t;
// If object selected, what type?
if (o) {
t = o.get('type');
}
if (o && t === 'i-text') {
switch (a) {
case 'bold':
var isBold = dtGetStyle(o, 'fontWeight') === 'bold';
dtSetStyle(o, 'fontWeight', isBold ? '' : 'bold');
break;
case 'italic':
var isItalic = dtGetStyle(o, 'fontStyle') === 'italic';
dtSetStyle(o, 'fontStyle', isItalic ? '' : 'italic');
break;
case 'underline':
var isUnderline = dtGetStyle(o, 'textDecoration') === 'underline';
dtSetStyle(o, 'textDecoration', isUnderline ? '' : 'underline');
break;
canvas.renderAll();
}
}
}
// Get the style
function dtGetStyle(object, styleName) {
return object[styleName];
}
// Set the style
function dtSetStyle(object, styleName, value) {
object[styleName] = value;
object.set({
dirty: true
});
canvas.renderAll();
}
// Switching Fonts
document.getElementById("cinzel").addEventListener("click", function(e) {
canvas.getActiveObject().set("fontFamily", "Cinzel");
canvas.renderAll();
});
document
.getElementById("cinzelDecorative")
.addEventListener("click", function(e) {
canvas.getActiveObject().set("fontFamily", "Cinzel Decorative");
canvas.renderAll();
});
document
.getElementById("monsieurladoulaise")
.addEventListener("click", function(e) {
canvas.getActiveObject().set("fontFamily", "Monsieur La Doulaise");
canvas.renderAll();
});
document.getElementById("opensans").addEventListener("click", function(e) {
canvas.getActiveObject().set("fontFamily", "Open Sans");
canvas.renderAll();
});
document.getElementById("montserrat").addEventListener("click", function(e) {
canvas.getActiveObject().set("fontFamily", "Montserrat");
canvas.renderAll();
});
document.getElementById("times").addEventListener("click", function(e) {
canvas.getActiveObject().set("fontFamily", "Times New Roman");
canvas.renderAll();
});
// Centered Line
var line = new fabric.Line([canvas.width / 2, 0, canvas.width / 2, canvas.height], {
strokeWidth: 1,
stroke: '#dddddd',
selectable: false,
});
canvas.add(line);
// Save
function download(url, name) {
// make the link. set the href and download. emulate dom click
$('<a>').attr({
href: url,
download: name
})[0].click();
}
function downloadFabric(canvas, name) {
// convert the canvas to a data url and download it.
download(canvas.toDataURL({
multiplier: 4
}), name + '.png');
}
// Print
function printCanvas() {
var dataUrl = document.getElementById('c').toDataURL( /* data multiplier?*/ ); //attempt to save base64 string to server using this var
var windowContent = '<!DOCTYPE html>';
windowContent += '<html>'
windowContent += '<head><title>Print canvas</title></head>';
windowContent += '<body>'
windowContent += '<img src="' + dataUrl + '" onload=window.print();window.close();>';
windowContent += '</body>';
windowContent += '</html>';
var printWin = window.open('', '', 'width=340,height=260');
printWin.document.open();
printWin.document.write(windowContent);
}
&#13;
canvas {
border: 1px solid #dddddd;
margin-top: 5px;
}
a:visited {
text-decoration: none;
}
a:hover {
text-decoration: underline;
cursor: pointer;
}
a.dropdown-item {
cursor: pointer;
}
.btn {
margin-top: 10px;
cursor: pointer;
}
#upload_link {
text-decoration: none;
}
#file {
display: none;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css?family=Cinzel|Cinzel+Decorative|Monsieur+La+Doulaise|Montserrat|Open+Sans" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<div class="container">
<div class="row">
<div class="col-md-2">
<button type="file" class="btn btn-dark btn-sm" id="upload_link">New Photo</button>
<input type="file" id="file" />
<br>
<div class="btn-group">
<button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Themes</button>
<div class="dropdown-menu">
<h6 class="dropdown-header">Frame</h6>
<a onclick="replaceImage(oImg, 'images/frames/LightBrownWoodOval.png')" class="dropdown-item">Oval Light Brown</a>
<a onclick="replaceImage(oImg, 'images/frames/MidToneWoodFrameOval.png')" class="dropdown-item">Oval Mid Tone Wood</a>
<a onclick="replaceImage(oImg, 'images/frames/SilverFrameOval.png')" class="dropdown-item">Oval Silver</a>
<a onclick="replaceImage(oImg, 'images/frames/DistressedWhiteFrameRec.png')" class="dropdown-item">Rectangle Distressed White</a>
<a onclick="replaceImage(oImg, 'images/frames/GoldScrollFrameRec.png')" class="dropdown-item">Rectangle Gold Scroll</a>
<a onclick="replaceImage(oImg, 'images/frames/MidtoneWoodFrameRec.png')" class="dropdown-item">Rectangle Mid Tone Wood</a>
<a onclick="replaceImage(oImg, 'images/frames/SilverFrameRec.png')" class="dropdown-item">Rectangle Silver</a>
</div>
</div>
<br>
<div class="btn-group">
<button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Text Options</button>
<div class="dropdown-menu">
<h6 class="dropdown-header">Styles</h6>
<a class="dropdown-item" id="btn-bold" style="font-weight: bold;">Bold</a>
<a class="dropdown-item" id="btn-italic" style="text-decoration: italic;">
<em>Italic</em>
</a>
<a class="dropdown-item" id="btn-underline" style="text-decoration: underline;">Underline</a>
<div class="dropdown-divider"></div>
<h6 class="dropdown-header">Fonts</h6>
<a class="dropdown-item" id="cinzel" style="font-family:cinzel;">Cinzel</a>
<a class="dropdown-item" id="cinzelDecorative" style="font-family:cinzel decorative;">Cinzel Decorative</a>
<a class="dropdown-item" id="monsieurladoulaise" style="font-family:Monsieur La Doulaise;">Monsieur La Doulaise</a>
<a class="dropdown-item" id="montserrat" style="font-family:montserrat;">Montserrat</a>
<a class="dropdown-item" id="opensans" style="font-family:Open Sans;">Open Sans</a>
<a class="dropdown-item" id="times" style="font-family:Times New Roman;">Times</a>
</div>
</div>
<br>
<button onclick="downloadFabric(canvas,'portrait')" type="button" class="btn btn-sm" title="Save as PNG">Save</button>
<br>
<button onclick="printCanvas()" type="button" class="btn btn-default btn-sm">Print</button>
<br>
<button onclick="window.location.reload(true)" type="button" class="btn btn-danger btn-sm">Restart</button>
</div>
<div class="col-md-10">
<canvas id="c"></canvas>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>
&#13;
同样,印刷现在也不起作用。
答案 0 :(得分:4)
使用toDataURL方法:
const dataURL = canvas.toDataURL({
width: canvas.width,
height: canvas.height,
left: 0,
top: 0,
format: 'png',
});
const link = document.createElement('a');
link.download = 'image.png';
link.href = dataURL;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
它将在文档中创建一个不可见的链接,然后单击它以触发下载。
答案 1 :(得分:1)
使用下面的代码
var dataURL = canvas.toDataURL({
format: "png",
left: 0,
top: 0,
width: canvas.width ,
height: canvas.height ,
});
答案 2 :(得分:1)
如果您收到此错误,则无需检查代码:
Uncaught DOMException: Failed to execute 'toDataURL' on
'HTMLCanvasElement': Tainted canvases may not be exported.
at n.__toDataURL (https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js:1:111706)
at n.__toDataURLWithMultiplier (https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js:1:111496)
at n.toDataURL (https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js:1:111060)
at downloadFabric (file://portrait.js:207:21)
at HTMLButtonElement.onclick (file://index.html:62:114)
你的画布被污染了。 这意味着您加载了一些图像而未指定crossOrigin属性。
Fabricjs在回调后确实支持fromOrl的crossOrigin选项作为第三个参数(请查看此处的文档http://fabricjs.com/docs/fabric.Image.html#.fromURL)
在函数replaceImage中,在将.src属性设置为图像之前,你必须自己处理它。
// oImgObj bread and butter, kudos @grunt
function replaceImage(oImgObj, imgUrl) {
if (!isImageLoaded) return; //return if initial image not loaded
var imgElem = oImgObj._element; //reference to actual image element
imgElem.src = imgUrl; //set image source
imgElem.onload = () => canvas.renderAll(); //render on image load
}
// initialize default frame (light brown wood oval)
fabric.Image.fromURL('https://i.imgur.com/DrzSWSa.png', function(img) {
isImageLoaded = true;
oImg = img.set({
selectable: false,
evented: false,
}).scale(0.5);
canvas.add(oImg).renderAll();
canvas.sendToBack(oImg);
});