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!

comments powered by Disqus