Je souhaite télécharger Canvas au format PNG à l'aide de fabric.js. Pendant le téléchargement, je souhaite mettre l'image à l'échelle. J'utilise donc la propriété multiplier
de la fonction toDataURL()
. Mais j'obtiens une erreur de réseau défaillant
PS: Si je ne donne pas la propriété multiplier
, il se télécharge mais je fais je veux utiliser la propriété multiplier
car je dois mettre à l'échelle la image
Voici ce que je fais:
Code HTML:
<canvas width="400" height="500" id="canvas" ></canvas>
<a id='downloadPreview' href="javascript:void(0)"> Download Image </a>
JS
document.getElementById("downloadPreview").addEventListener('click', downloadCanvas, false);
var _canvasObject = new fabric.Canvas('canvas');
var downloadCanvas = function(){
var link = document.createElement("a");
link.href = _canvasObject.toDataURL({format: 'png', multiplier: 4});
link.download = "helloWorld.png";
link.click();
}
Le problème auquel vous êtes confronté n'est pas directement lié à fabricjs, (ni à canvas ni même à javascript btw), mais vient des limitations que certains navigateurs (y compris Chrome) ont sur la longueur maximale de l'attribut src
d'une ancre Élément (<a>
) Avec l'attribut donwload.
Lorsque cette limite est atteinte, alors la seule chose que vous avez est cette "erreur réseau" inaccessible dans la console; le téléchargement a échoué, mais vous, en tant que développeur, ne pouvez pas le savoir.
Comme proposé dans ce (vous-refusez-de-marquer-comme -) dupliquer , la solution est soit d'obtenir directement un Blob lorsqu'il est disponible (pour le canevas, vous pouvez appeler sa méthode toBlob()
, ou d'abord convertir votre dataURI en Blob, puis créer un RL d'objet = de ce blob.
Fabricjs ne semble pas encore avoir de fonction toBlob
implémentée, donc dans votre cas précis, vous devrez le faire plus tard.
Vous pouvez trouver de nombreux scripts pour convertir dataURI en Blob, un est disponible dans la méthode polyfill MDN to Canvas.toBlob()
.
Ensuite, cela ressemblerait à ceci:
// edited from https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill
function dataURIToBlob(dataURI, callback) {
var binStr = atob(dataURI.split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
callback(new Blob([arr]));
}
var callback = function(blob) {
var a = document.createElement('a');
a.download = fileName;
a.innerHTML = 'download';
// the string representation of the object URL will be small enough to workaround the browser's limitations
a.href = URL.createObjectURL(blob);
// you must revoke the object URL,
// but since we can't know when the download occured, we have to attach it on the click handler..
a.onclick = function() {
// ..and to wait a frame
requestAnimationFrame(function() {
URL.revokeObjectURL(a.href);
});
a.removeAttribute('href')
};
};
dataURIToBlob(yourDataURL, callback);
J? ai compris. A travaillé comme suggéré par Kaiido
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
REMARQUE: obtenu la fonction ci-dessus de HTML5/Javascript - DataURL vers Blob & Blob vers DataURL
var downloadCanvas = function(){
var link = document.createElement("a");
var imgData = _canvasObject.toDataURL({ format: 'png',
multiplier: 4});
var strDataURI = imgData.substr(22, imgData.length);
var blob = dataURLtoBlob(imgData);
var objurl = URL.createObjectURL(blob);
link.download = "helloWorld.png";
link.href = objurl;
link.click();
}
Étant donné que les deux réponses précédentes ne fonctionnent que pour les dataURL qui ont des données base64, et parce que cette réponse a été référencée par des questions plus générales liées aux "erreurs réseau" en raison d'attributs href qui sont trop grands, voici le code que j'utilise:
// must be called in a click handler or some other user action
var download = function(filename, dataUrl) {
var element = document.createElement('a')
var dataBlob = dataURLtoBlob(dataUrl)
element.setAttribute('href', URL.createObjectURL(dataBlob))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
var clickHandler;
element.addEventListener('click', clickHandler=function() {
// ..and to wait a frame
requestAnimationFrame(function() {
URL.revokeObjectURL(element.href);
})
element.removeAttribute('href')
element.removeEventListener('click', clickHandler)
})
document.body.removeChild(element)
}
// from Abhinav's answer at https://stackoverflow.com/questions/37135417/download-canvas-as-png-in-fabric-js-giving-network-error/
var dataURLtoBlob = function(dataurl) {
var parts = dataurl.split(','), mime = parts[0].match(/:(.*?);/)[1]
if(parts[0].indexOf('base64') !== -1) {
var bstr = atob(parts[1]), n = bstr.length, u8arr = new Uint8Array(n)
while(n--){
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], {type:mime})
} else {
var raw = decodeURIComponent(parts[1])
return new Blob([raw], {type: mime})
}
}
Avec ces fonctions, vous pouvez changer le code en ceci:
document.getElementById("downloadPreview").addEventListener('click', function() {
var dataURL = _canvasObject.toDataURL({format: 'png', multiplier: 4})
download("hellowWorld.png", dataURL)
})