2016-05-10 10 views
14

Voglio scaricare Canvas come PNG usando fabric.js. Durante il download voglio ridimensionare l'immagine. Quindi uso la proprietà multiplier della funzione toDataURL(). Ma ho fallito errore di reteScarica Canvas come PNG in fabric.js dando rete Errore

PS: Se io non dare multiplier proprietà, è il download, ma ho fare voler utilizzare multiplier proprietà dal momento che ho per ridimensionare l'immagine

questo è quello che sto facendo:

Codice

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

} 
+0

Hai questo errore solo su chrome? se è così, questo è probabilmente correlato: http: // StackOverflow.it/questions/36918075/is-it-possible-to-programmatically-detect-size-limit-for-data-url/36951356 ma per il tuo caso d'uso, invece di chiamare 'toBlob' (che non credo sia disponibile in fabricjs), dovrai convertire il dataURI in un blob prima di impostare l'href dell'ancora sull'URL dell'oggetto di questo blob. (puoi controllare [MDN's polyfill for 'toBlob'] (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill) e scegliere il loro modo di convertire un dataURI in un BLOB) – Kaiido

+0

devo semplicemente impostare il valore href su blob? – Abhinav

+0

no a un oggetto URL creato dal blob ('URL.createObjectURL (blob)'). Controlla la risposta sul dupe proposto. – Kaiido

risposta

19

Il problema che si trovano ad affrontare non è direttamente correlata alla fabricjs, (né tele e nemmeno javascript btw) , ma deriva dalle limitazioni che alcuni browser (incluso Chrome) hanno sulla lunghezza massima per l'attributo src di un elemento di ancoraggio (<a>) con l'attributo donwload.

Quando si raggiunge questo limite, l'unica cosa che si ottiene è "Errore di rete" non gestibile nella console; il download non è riuscito, ma tu come lo sviluppatore non puoi conoscerlo.

Come proposto in questa (si-rifiutato-to-mark-as)duplicate, la soluzione è o di ottenere direttamente un Blob quando disponibile (per tela, si può chiamare il suo metodo toBlob(), o al primo convertito i tuoi dataURI ad un Blob, e quindi creare un object URL da questa Blob.

Fabricjs non sembra avere una funzione toBlob ancora attuata, così nel tuo caso esatto, dovrete fare più tardi.
È può trovare molti script per convertire dataURI in Blob, uno è disponibile nel metodo MDN's polyfill a Canvas.toBlob().

Allora sarebbe simile a questa:

// 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); 
+0

Grazie per una dettagliata – Abhinav

+0

Il tuo dataURIToBlob non è ben formato. Dove è definito il tipo o la qualità? E 'questo? Farà riferimento alla finestra più probabilmente. –

+0

@BT, hai perfettamente ragione, non so come sarebbe potuto rimanere così a lungo senza che nessuno se ne accorgesse (io il primo). Grazie. Ma probabilmente dovrei semplicemente rimuovere questa funzione dataITITBlob ora che 'toBlob' si è fatto strada nella maggior parte dei browser principali, è molto più veloce della conversione di due volte i dati. – Kaiido

9

Ho capito. Ha lavorato fuori come suggerito da 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}); 
} 

NOTA: Ha ottenuto la funzione di cui sopra da HTML5/Javascript - DataURL to Blob & Blob to 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(); 
} 
+0

Ho questo codice funzionante alla perfezione in Chrome e Edge, ma in FF non succede nulla. Sai se questo ha funzionato per te in FF? – Ron

+0

Oggi è fuori per me quindi non posso controllare e dirti ora, ma suppongo che abbia funzionato in FF, controllerò di nuovo lo stesso al più presto il – Abhinav

+1

Awesome. Ho avuto lo stesso problema e l'ho risolto con la tua soluzione. Grazie mille! – Steevie

1

Dal momento che le due precedenti risposte funzionare solo per dataURLs con dati base64, e perché questa risposta è stato fatto riferimento da più questioni generali relative a "errori di rete" a causa della attributi href che sono troppo grandi, ecco il codice che sto utilizzando:

// 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 queste funzioni è possibile modificare il codice a questo:

document.getElementById("downloadPreview").addEventListener('click', function() { 
    var dataURL = _canvasObject.toDataURL({format: 'png', multiplier: 4}) 
    download("hellowWorld.png", dataURL) 
}) 
+0

Non si dovrebbe riaprire la domanda collegata? (almeno se è stato chiuso) Questo non fornisce troppe informazioni utili sulla domanda corrente: "Scarica Canvas come PNG in fabric.js". Non c'è altro modo per ottenere un dataURI che rappresenta un file PNG rispetto alla codifica base64 dei suoi dati binari. – Kaiido

Problemi correlati