canvas.toDataURL () para canvas grande

Eu tenho um problema com .toDataURL() para canvas grande. Eu quero enconde em base64 e decodificar no arquivo php, mas se eu tiver uma canvas grande, a variável strDataURI está vazia.

Meu código:

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

Existe alguma alternativa para .toDataURL() ou alguma maneira de alterar o limite de tamanho?

Obrigado.

Não tenho certeza se há limitação para as dimensões de canvas, mas os URLs de dados têm limitações, dependendo do navegador: Limitações de tamanho de URL de dados .

O que você poderia tentar é usar o Node.js + node-canvas (lado do servidor) para recriar a canvas. Eu tenho usado estes para criar imagens imprimíveis de elementos de canvas, e não tive nenhum problema / limitações usando toDataURL até agora.

Você está usando a biblioteca fabric.js? Eu notei que você postou no fórum deles também. O Fabric.js pode ser usado no Node.js e tem um método toDataURLWithMultiplier , que dimensiona a canvas / contexto, permitindo que você altere o tamanho da imagem do dataurl. Você pode verificar a fonte do método para ver como isso é feito.

Editar:

Como você está usando o fabric.js, sugiro usar o Node.js para manipular a canvas para processamento de imagens no servidor. Você encontrará mais informações sobre como usar o Fabric.js no Node.js aqui .

Aqui está um servidor simples usando o Node.js e 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 o servidor está em execução, você pode enviar dados para ele ( postData ). O servidor espera que json , width e height recriem a canvas e um multiplier para dimensionar a imagem de URL de dados. O código do lado do cliente seria algo como isto:

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

Você deve primeiro considerar isso: o tamanho do upload é limitado. O limite depende do navegador, sistema operacional e ambiente do servidor. Você pode dar uma olhada neste artigo: http://www.motobit.com/help/scptutl/pa98.htm

Em geral, você pode tentar algo assim: primeiro precisamos de uma function para converter o dataURI em um 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 depois uma function para o upload do arquivo, usando XMLHttpRequest2:

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

Agora você pode passar seu strDataURI para a primeira function e depois fazer o upload do arquivo com a segunda function.

Você pode ter uma visão mais profunda de XMLHTTPRequest2 aqui: http://www.html5rocks.com/en/tutorials/file/xhr2/ e sobre o construtor de blob aqui: https://developer.mozilla.org/en-US/docs / DOM / Blob

Você poderia sempre dividir a imagem em seções menores e salvá-las individualmente, o que provavelmente não é uma má ideia. Basicamente você teria uma function que é algo como

 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. } } 

Atualizou o código para dividir a canvas em objects de canvas menores. Funciona muito bem e adicionou um rastreador também:

Isso permite o acompanhamento do processo de upload e, em geral, acho melhor para o usuário. Eu uso o PHP para voltar a um estágio posterior.

Evita os problemas de tamanho de canvas / navegador etc.

Meu primeiro post então espero que ajude!

// passa o tipo para o nome do arquivo

 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 para upload:

 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"); }); } 
Intereting Posts