Saving an HTML5 Canvas Drawing to Disk
One of my favorite features of HTML5 is canvas
. If you aren’t familiar with
it, canvas
is basically a drawing surface
in your browser. The hugeness of this ability is lost on most because they don’t realize
that having your own drawing surface native in the browser means that your ability to
build intefaces is limited only by your imagination and your mad Ja\/a5cr1pt 5k1llz. So
I love it. Here’s a trick that will hopefully make you like it a little more.
Let’s say you have a canvas
setup like we do below that allows you to
click/touch and move to draw on it. Go ahead and try it out. It should work for desktop browsers
(IE10+, Chrome, Firefox), webkit-based mobile browsers, Firefox on mobile and IE 10, phone
or tablet.
Maybe I will do a blog post at some point explaining how all that works. Or you could just view source. The JavaScript for it is right in the page. But that’s not what I want to focus on this time. I want to focus on saving the canvas to the server.
One awesome feature of HTML5 canvas
is that you can turn the data in the canvas into
an image. And if you can do that, you can save it to the server. Here is how to do both.
function saveCanvas() {
var imageData = canvas.toDataURL('image/jpeg', 1);
var formData = new FormData();
formData.append('fileData', imageData);
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () { alert('uploaded!'); });
xhr.open('POST', "/stuff/upload", true);
xhr.send(formData);
}
So first you use the toDataURL
method on canvas
to turn
the canvas into a base64 encoded string representation of the image data. You can
have it converted into a jpeg, png or webp, assuming the browser you are using supports
all three. You will certainly have good support for jpeg and png.
Next you need to get that data down to the server. You can do this however you
choose though in the above you see the code for doing that using the XMLHttpRequest
object directly. But next you need to handle this on the server. Here is my
ASP.NET MVC endpoint.
[HttpPost]
public ActionResult Upload(string fileData)
{
string dataWithoutJpegMarker = fileData.Replace("data:image/jpeg;base64,", String.Empty);
byte[] filebytes = Convert.FromBase64String(dataWithoutJpegMarker);
string writePath = Path.Combine(Server.MapPath("~/upload"), Guid.NewGuid().ToString() + ".jpg");
using (FileStream fs = new FileStream(writePath,
FileMode.OpenOrCreate,
FileAccess.Write,
FileShare.None))
{
fs.Write(filebytes, 0, filebytes.Length);
}
return new EmptyResult();
}
The data comes down to the server with a marker prepended to the front identifying
the image format. To save it, just remove the marker, convert it to an array of bytes
and save it to disk. Done! Now you have an HTML5 canvas
object being
saved from a webpage to the server!