Canvas.toDataURL() для большого холста
У меня проблема с .toDataURL()
для большого холста. Я хочу заключить код в base64
и декодировать в php файле, но если у меня есть большой холст, переменная strDataURI
пуста.
Мой код:
var strDataURI = canvas.toDataURL();
strDataURI = strDataURI.substr(22, strDataURI.length);
$.post("save.php",
{
str: strDataURI
};
Есть ли альтернатива .toDataURL()
или какой-либо способ изменить ограничение размера?
Спасибо.
Ответы
Ответ 1
Я не уверен, есть ли ограничения размеров холста, но URL-адреса данных имеют ограничения в зависимости от браузера: Ограничения по размеру URL-адресов.
Что бы вы могли попробовать, используйте Node.js + node -canvas (серверная сторона), чтобы воссоздать холст. Я использовал их для создания печатаемых изображений из элементов холста, и до сих пор не было никаких проблем/ограничений, использующих toDataURL.
Используете ли вы библиотеку fabric.js? Я заметил, что вы отправили на свой форум.
Fabric.js можно использовать в Node.js и имеет метод toDataURLWithMultiplier, который масштабирует холст/контекст, позволяющий вам изменить dataurl Размер изображения. Вы можете проверить источник метода, чтобы узнать, как это делается.
Edit:
Поскольку вы используете fabric.js, я бы предложил использовать Node.js для обработки холста для обработки изображений на сервере. Вы найдете более подробную информацию о том, как использовать fabric.js на Node.js здесь.
Вот простой сервер, использующий Node.js и выражающий:
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);
Когда сервер работает, вы можете отправлять ему данные (postData
).
Сервер ожидает json
, width
и height
для воссоздания холста и multiplier
для масштабирования изображения URL-адреса данных. Код на стороне клиента будет выглядеть примерно так:
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);
}
});
Ответ 2
Вы должны сначала рассмотреть это: размер загрузки ограничен. Ограничение зависит от среды браузера, ОС и сервера. Вы можете взглянуть на эту статью: http://www.motobit.com/help/scptutl/pa98.htm
В общем, вы можете попробовать что-то вроде этого:
сначала нам нужна функция для преобразования dataURI в 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;
}
и следующую функцию для загрузки файла, используя XMLHttpRequest2:
function upload(blob) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/yourServerEndPoint', true);
xhr.onload = function(e) { ... };
xhr.send(blob);
}
Теперь вы можете передать свой strDataURI
в первую функцию, а затем загрузить файл со второй функцией.
Вы можете более глубоко изучить XMLHTTPRequest2 здесь: http://www.html5rocks.com/en/tutorials/file/xhr2/
и о конструкторе blob здесь: https://developer.mozilla.org/en-US/docs/DOM/Blob
Ответ 3
Вы всегда можете просто разбить изображение на более мелкие разделы и сохранить их в индивидуальном порядке, что, вероятно, не так уж плохо. В принципе у вас будет функция, которая что-то вроде
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.
}
}
Ответ 4
Обновил код, чтобы разделить холст на более мелкие объекты холста. Работает очень хорошо и добавил трекер также:
Это позволяет отслеживать процесс загрузки, и в целом я думаю, что это лучше для пользователя. Я использую PHP для воссоединения на более позднем этапе.
Это позволяет избежать проблем с размером холста/браузера и т.д.
Мой первый пост, надеюсь, он поможет!
//передать тип для имени файла
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 для загрузки:
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");
});
}