web-dev-qa-db-fra.com

Télécharger Canvas en PNG dans fabric.js donnant une erreur réseau

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();

}
22
Abhinav

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);
37
Kaiido

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();
} 
14
Abhinav

É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)
})
1
B T