Reputation: 503
I need to upload the canvas image data to the server (database) on the fly, i.e., I need to create a form and with an input=file, and post the image data without any user interaction.
Upvotes: 41
Views: 65404
Reputation: 140195
You don't need a file input, just get the data with ctx.getImageData()
and post it to the server with Ajax.
See the MDN Documentation for CanvasRenderingContext2D.getImageData()
.
But you won't be able to get the image data in IE, even with ExCanvas
.
Upvotes: 11
Reputation: 4049
Here is how I solved this. Posting the image as base64 array using JavaScript and then decoding and saving it as a image using PHP.
Client side (JavaScript):
$.post('/ajax/uploadthumbnail',
{
id : id,
img : canvas.toDataURL("image/png")
}, function(data) {
console.log(data);
});
Server side (PHP):
$img = $_POST['img'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = $_SERVER['DOCUMENT_ROOT'] . '/images/some_name.png';
file_put_contents($file, $data);
Upvotes: 8
Reputation: 2611
Here is a demo of an online signature app that I wrote last year Canvas Signature Demo. This has the advantage of posting only the vector data to the server. With all of the path info, you could also apply smoothing algorithms or scale it as needed before persisting.
<canvas id="signature" width="300" height="100"></canvas>
<form method="post" id="signature_form" action="signing.aspx">
<input type="hidden" name="paths" id="paths"/>
<p><label>Cover #</label> <input type="text" id="covernumber" name="covernumber"/>
<input type="submit" id="save" value="Save"/>
</form>
I store the path data into a hidden field and post that to the server.
signature.js Core logic below:
mouseDown: function(event) {
var point = this.getRelativePoint(event);
this.paths.push( [ point ] );
this.ctx.fillRect(point.x,point.y,1,1);
this.penDown = true;
this.updateField();
},
mouseUp: function(event) {
this.penDown = false;
this.ctx.closePath();
if ( Prototype.Browser.IE && event.srcElement.tagName != "INPUT" ) {
var ver = getInternetExplorerVersion();
if ( ver >= 8 && ver < 9 && document.selection ) {
document.selection.empty();
}
}
},
mouseMove: function(event) {
if ( this.penDown ) {
var lastPath = this.paths[ this.paths.length - 1 ];
var lastPoint = lastPath[ lastPath.length - 1 ];
var point = this.getRelativePoint(event);
lastPath.push( point );
this.ctx.strokeStyle = "#000000";
this.ctx.beginPath();
this.ctx.moveTo(lastPoint.x,lastPoint.y);
this.ctx.lineTo(point.x, point.y);
this.ctx.stroke();
this.ctx.closePath();
this.updateField();
}
},
updateField: function() {
if ( this.field ) {
this.field.value = this.paths.toJSON();
}
}
Here is my relevant server side .Net code (C#).
if ( Request("paths") ) {
var objBitmap : Bitmap = new Bitmap(300, 100);
var objGraphics : Graphics = Graphics.FromImage(objBitmap);
objGraphics.Clear(Color.Transparent);
objGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
var paths:Array = eval(Request("paths")) || [];
var p : int;
var q : int;
var path : Array;
for ( p = 0; p< paths.length; p++ ) {
var path = paths[p];
if ( path.length == 1 ) {
objGraphics.DrawRectangle(new Pen(Color.Black), path[0].x, path[0].y, 1, 1);
} else {
for ( q = 1; q<path.length; q++ ) {
var prev = path[q-1];
var curr = path[q];
objGraphics.DrawLine(new Pen(Color.Black), parseInt(prev.x),parseInt(prev.y),parseInt(curr.x),parseInt(curr.y));
}
}
}
objBitmap.Save("C:\\temp\\" + Request("covernumber") + ".png", ImageFormat.Png);
objBitmap.Dispose();
objGraphics.Dispose();
}
Upvotes: 3
Reputation: 53335
FWIW, this is how I got it working.
My server is in google app engine. I send canvas.toDataURL()'s output as part of post request using jQuery.post. The data URL is base64 encoded image data. So on server I decode it and convert it to image
import re
import base64
class TnUploadHandler(webapp.RequestHandler):
dataUrlPattern = re.compile('data:image/(png|jpeg);base64,(.*)$')
def post(self):
uid = self.request.get('uid')
img = self.request.get('img')
imgb64 = self.dataUrlPattern.match(img).group(2)
if imgb64 is not None and len(imgb64) > 0:
thumbnail = Thumbnail(
uid = uid, img = db.Blob(base64.b64decode(imgb64)))
thumbnail.put()
From client I send the data like this:
$.post('/upload',
{
uid : uid,
img : canvas.toDataURL('image/jpeg')
},
function(data) {});
This may not be the best way to do it, but it works.
Upvotes: 35
Reputation: 8470
You can get the image data in the form of a data: url, this only works in Firefox and Opera so far though.
http://cow.neondragon.net/index.php/681-Canvas-Todataurl
Upvotes: 0