canvas.toDataURL () per tele di grandi dimensioni

Ho un problema con .toDataURL() per tele di grandi dimensioni. Voglio enconde in base64 e decodificare su file php, ma se ho un grande canvas la variabile strDataURI è vuota.

Il mio codice:

 var strDataURI = canvas.toDataURL(); strDataURI = strDataURI.substr(22, strDataURI.length); $.post("save.php", { str: strDataURI }; 

Esiste un’alternativa a .toDataURL() o un modo per modificare il limite di dimensione?

Grazie.

Non sono sicuro se esistono limitazioni alle dimensioni dell’area di disegno, ma gli URL di dati presentano limitazioni a seconda del browser: Limiti della dimensione dell’URL dei dati .

Quello che potresti provare è usare Node.js + node-canvas (lato server) per ricreare il canvas. Li ho usati per creare immagini stampabili da elementi canvas e non ho avuto problemi / limitazioni usando toDataURL finora.

Stai usando la libreria fabric.js? Ho notato che hai postato anche sul loro forum. Fabric.js può essere utilizzato in Node.js e dispone di un metodo toDataURLWithMultiplier , che ridimensiona la canvas / contesto consentendo di modificare la dimensione dell’immagine dataurl. È ansible controllare la fonte del metodo per vedere come è fatto.

Modificare:

Dato che stai usando fabric.js, ti suggerirei di utilizzare Node.js per gestire il canvas sull’elaborazione delle immagini sul server. Troverai maggiori informazioni su come utilizzare fabric.js su Node.js qui .

Ecco un semplice server che utilizza Node.js ed express:

 var express = require('express'), fs = require('fs'), fabric = require('fabric').fabric, app = express(), port = 3000; var allowCrossDomain = function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); } app.configure(function() { app.use(express.bodyParser()); app.use(allowCrossDomain); }); app.options('/', function(req, res) { res.send(200); }); app.post('/', function(req, res) { var canvas = fabric.createCanvasForNode(req.body.width, req.body.height); console.log('> Loading JSON ...'); canvas.loadFromJSON(req.body.json, function() { canvas.renderAll(); console.log('> Getting PNG data ... (this can take a while)'); var dataUrl = canvas.toDataURLWithMultiplier('png', req.body.multiplier), data = dataUrl.replace(/^data:image\/png;base64,/, ''); console.log('> Saving PNG to file ...'); var filePath = __dirname + '/test.png'; fs.writeFile(filePath, data, 'base64', function(err) { if (err) { console.log('! Error saving PNG: ' + err); res.json(200, { error: 'Error saving PNG: ' + err }); } else { console.log('> PNG file saved to: ' + filePath); res.json(200, { success: 'PNG file saved to: ' + filePath }); } }); }); }); app.listen(port); console.log('> Server listening on port ' + port); 

Quando il server è in esecuzione è ansible inviare dati ad esso ( postData ). Il server prevede json , width e height per ricreare il canvas e un multiplier per ridimensionare l’immagine dell’URL di dati. Il codice lato client sarebbe simile a questo:

 var postData = { json: canvas.toJSON(), width: canvas.getWidth(), height: canvas.getHeight(), multiplier: 2 }; $.ajax({ url: 'http://localhost:3000', type: 'POST', contentType: 'application/json; charset=utf-8', data: JSON.stringify(postData), dataType: 'json', success: function(data) { console.log(data); }, error: function(err) { console.log(err); } }); 

Dovresti innanzitutto considerare questo: la dimensione del caricamento è limitata. Il limite dipende dal browser, dal sistema operativo e dall’ambiente server. Puoi dare un’occhiata a questo articolo: http://www.motobit.com/help/scptutl/pa98.htm

In generale puoi provare qualcosa del genere: prima abbiamo bisogno di una funzione per convertire dataURI in un blob:

 function convertDataURItoBlob(dataURI) { 'use strict' var byteString, mimestring if(dataURI.split(',')[0].indexOf('base64') !== -1 ) { byteString = atob(dataURI.split(',')[1]) } else { byteString = decodeURI(dataURI.split(',')[1]) } mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0] var content = new Array(); for (var i = 0; i < byteString.length; i++) { content[i] = byteString.charCodeAt(i) } var rawContent = new Uint8Array(content), returnBlob = new Blob([rawContent], {type: mimestring}) return returnBlob; } 

e successivamente una funzione per il caricamento del file, usando XMLHttpRequest2:

 function upload(blob) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/yourServerEndPoint', true); xhr.onload = function(e) { ... }; xhr.send(blob); } 

Ora puoi passare strDataURI alla prima funzione e quindi caricare il file con la seconda funzione.

Puoi dare un'occhiata più approfondita a XMLHTTPRequest2 qui: http://www.html5rocks.com/en/tutorials/file/xhr2/ e al costruttore di blob qui: https://developer.mozilla.org/en-US/docs / DOM / Blob

Puoi sempre interrompere l’immagine in sezioni più piccole e salvarle individualmente, il che probabilmente non è comunque una ctriggers idea. Fondamentalmente avresti una funzione che è qualcosa di simile

 var largeCanvas = document.getElementById('yourGiantCanvas').getContext('2d'), slice = document.createElement('canvas').getContext('2d'); slice.canvas.width = 1000; slice.canvas.height = 1000; for (var y=0; y < canvas.height; y+=1000){ for (var x=0; x < canvas.width; x+=1000){ slice.clearRect(0, 0, slice.canvas.width, slice.canvas.height); slice.drawImage(largeCanvas.canvas, x, y, 1000, 1000, 0, 0, 1000, 1000); var imagePiece = slice.canvas.toDataURL(); //Now just save the imagePiece however you normally were planning to //and you can build the image again using these slices. You can create //a much better user experience this way too. } } 

Ho aggiornato il codice per dividere la canvas in oggetti di canvas più piccoli. Funziona piuttosto bene e ho aggiunto anche un tracker:

Questo consente il monitoraggio del processo di caricamento e, nel complesso, penso che sia meglio per l’utente. Uso PHP per ricongiungermi in una fase successiva.

Evita i problemi di dimensioni della canvas / browser ecc.

Il mio primo post quindi spero che aiuti!

// inserisci il tipo per il nome del file

 function sliceCanvas(type, canvasId){ var largeCanvas = document.getElementById(canvasId).getContext('2d'); var slice = document.createElement('canvas').getContext('2d'); var baseSize = 500; fileH = largeCanvas.canvas.height / baseSize; fileW = largeCanvas.canvas.width / baseSize; slice.canvas.width = baseSize; slice.canvas.height = baseSize; count = 1; numFiles = Math.ceil(fileH) * Math.ceil(fileW); for (var y=0; y < largeCanvas.canvas.height; y+=baseSize){ for (var x=0; x < largeCanvas.canvas.width; x+=baseSize){ slice.clearRect(0, 0, slice.canvas.width, slice.canvas.height); slice.drawImage(largeCanvas.canvas, x, y, baseSize, baseSize, 0, 0, baseSize, baseSize); var imagePiece = slice.canvas.toDataURL(); typeFinal = type + count; exportSlice(typeFinal, imagePiece, numFiles); count++; } } } 

Ajax per caricare:

 function exportSlice(type, dataURL, fileNum){ percent = 0; percentComplete = 0; $.ajax({ type: "POST", url: YourServerSideFiletoSave, data: {image: dataURL, type: type} }) .done(function( response ) { console.log(response); percent++; percentComplete = Math.ceil(Number(percent/fileNum*100)); return true; }) .fail(function(response) { console.log("Image FAILED"); console.log(response); return false; }) .always(function(response) { console.log( "Always"); }); }