Quiero descargar Canvas como PNG usando fabric.js. Durante la descarga, quiero escalar la imagen. Entonces uso la propiedad multiplier de la función toDataURL(). Pero recibo un error de red fallida

PS: Si no doy la propiedad multiplier, se está descargando pero quiero usar la propiedad multiplier ya que tengo que escalar la imagen

Esto es lo que estoy haciendo:

Código 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();

}
23
Abhinav 10 may. 2016 a las 13:10

5 respuestas

La mejor respuesta

El problema al que se enfrenta no está directamente relacionado con fabricjs (ni el lienzo y ni siquiera javascript por cierto), sino que proviene de limitaciones que algunos navegadores (incluido Chrome) tienen en la longitud máxima para el atributo src de un elemento de anclaje (<a>) con el atributo donwload.

Cuando se alcanza este límite, entonces lo único que tiene es este "Error de red" que no se puede capturar en la consola; la descarga falló, pero usted, como desarrollador, no puede saberlo.

Como se propone en este (usted-rechazó-marcar-como-) duplicar, la solución es obtener directamente un Blob cuando esté disponible (para el lienzo, puede llamar a su toBlob(), o para convertir primero su dataURI en un Blob, y luego crear un URL del objeto de este Blob.

Parece que Fabricjs todavía no tiene implementada una función toBlob, por lo que, en su caso exacto, tendrá que hacer lo siguiente.
Puede encontrar muchos scripts para convertir dataURI a Blob, uno está disponible en Polyfill de MDN al método Canvas.toBlob().

Entonces se vería así:

// 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);
42
Kaiido 20 jun. 2017 a las 01:13

Dado que las dos respuestas anteriores solo funcionan para dataURL que tienen datos base64, y debido a que esta respuesta ha sido referenciada por preguntas más generales relacionadas con "errores de red" debido a los atributos href que son demasiado grandes, aquí está el código que estoy usando:

// 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})
    }
}

Con estas funciones puede cambiar el código a esto:

document.getElementById("downloadPreview").addEventListener('click', function() {
  var dataURL = _canvasObject.toDataURL({format: 'png', multiplier: 4})
  download("hellowWorld.png", dataURL)
})
1
B T 20 jun. 2017 a las 02:14

Lo tengo. Lo resolvió como lo sugirió 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});
}

tablas hash & amp;

Tengo varios lienzos en mi sitio web y estaba luchando con el mismo problema en uno de ellos.

Tamaño de lienzo 1: 750 px x 500 px (Problema de red en Windows Chrome, funciona bien en Chrome Macos)

Tamaño del lienzo 2: 540 px x 1080 px (Sin problema de descarga, funciona con el multiplicador 4)

Simplemente reduje el tamaño de descarga, cambiando el multiplicador 4 a 2 y funcionó bien.

Luego cambié el multiplicador a 3 y no volvió a funcionar.

Luego probé 2.5 y funcionó bien nuevamente.

Crear un archivo tan grande con 4 Multiplicador no era mi requisito, así que decidí con 2.5.

Esta es la solución más fácil y rápida para este problema.

0
Anirudh babbar 2 nov. 2019 a las 03:42

En mi caso acabo de usar esto

 var callback = function(blob) {
var a = document.createElement('a');
var saveAs = $('input[name="extensionGrp"]:checked').val();


var link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'Image.' + saveAs;
document.body.appendChild(link);
link.click();

};
0
TAHA SULTAN TEMURI 21 ene. 2020 a las 07:19