Send Canvas Content to Your Server

Posted on June 27th, 2011 in category: Tutorials

In the previous tutorial I showed you how to draw a line graph using the HTML5 canvas object. In this loosely based follow up tutorial I will show you how to send the canvas image to your server.

Tip

To learn how to draw to the canvas object, check out my previous tutorial here: Draw a Line Graph Using HTML5 Canvas

Step 1. Create The Visual Studio Solution

Start of by creating an ASP.NET Empty Web Application. Add a new Web Form and name it Default.aspx

Download the source from my previous tutorial from here and copy the script tags into the page header and copy the canvas element to the page body. Or if you’re lazy, just copy the code block below.

Add an input with the type button and the ID sendBtn, when the user clicks the button our image will be sent to the server. When you’re finished the ASPX should look a bit like this:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CanvasToServer.Default" %>

<!DOCTYPE html>

<head runat="server">
    <title>Canvas To Server</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.min.js"></script>
    <script>
        var graph;
        var xPadding = 30;
        var yPadding = 30;

        var data = { values: [
            { X: "Jan", Y: 12 },
            { X: "Feb", Y: 28 },
            { X: "Mar", Y: 18 },
            { X: "Apr", Y: 34 },
            { X: "May", Y: 40 },
        ]
        };

        // Returns the max Y value in our data list
        function getMaxY() {
            var max = 0;

            for (var i = 0; i < data.values.length; i++) {
                if (data.values[i].Y > max) {
                    max = data.values[i].Y;
                }
            }

            max += 10 - max % 10;
            return max;
        }

        // Return the x pixel for a graph point
        function getXPixel(val) {
            return ((graph.width() - xPadding) / data.values.length) * val + (xPadding * 1.5);
        }

        // Return the y pixel for a graph point
        function getYPixel(val) {
            return graph.height() - (((graph.height() - yPadding) / getMaxY()) * val) - yPadding;
        }

        $(document).ready(function () {
            graph = $('#graph');
            var c = graph[0].getContext('2d');

            c.lineWidth = 2;
            c.strokeStyle = '#333';
            c.font = 'italic 8pt sans-serif';
            c.textAlign = "center";

            // Draw the axises
            c.beginPath();
            c.moveTo(xPadding, 0);
            c.lineTo(xPadding, graph.height() - yPadding);
            c.lineTo(graph.width(), graph.height() - yPadding);
            c.stroke();

            // Draw the X value texts
            for (var i = 0; i < data.values.length; i++) {
                c.fillText(data.values[i].X, getXPixel(i), graph.height() - yPadding + 20);
            }

            // Draw the Y value texts
            c.textAlign = "right"
            c.textBaseline = "middle";

            for (var i = 0; i < getMaxY(); i += 10) {
                c.fillText(i, xPadding - 10, getYPixel(i));
            }

            c.strokeStyle = '#f00';

            // Draw the line graph
            c.beginPath();
            c.moveTo(getXPixel(0), getYPixel(data.values[0].Y));
            for (var i = 1; i < data.values.length; i++) {
                c.lineTo(getXPixel(i), getYPixel(data.values[i].Y));
            }
            c.stroke();

            // Draw the dots
            c.fillStyle = '#333';

            for (var i = 0; i < data.values.length; i++) {
                c.beginPath();
                c.arc(getXPixel(i), getYPixel(data.values[i].Y), 4, 0, Math.PI * 2, true);
                c.fill();
            }
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <canvas id="graph" width="200" height="150">
        </canvas>

        <input type="button" id="sendBtn" value="Send To Server" />
    </form>
</body>
</html>

Step 2. Create the JavaScript Function

Next step is to create the JavaScript send function, add the following code to the end of your script tag:

// Send the drawn image to the server
$('#sendBtn').live('click', function () {
    var image = graph[0].toDataURL("image/png");
    image = image.replace('data:image/png;base64,', '');

    $.ajax({
        type: 'POST',
        url: '/Default.aspx/UploadImage',
        data: '{ "imageData" : "' + image + '" }',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (msg) {
            alert('Image sent!');
        }
    });
});

First step is to get the data from the canvas, thats done by calling the toDataURL on the canvas object. Since our saved canvas object is a jQuery object we need to get the regular JavaScript object, that’s done using the “[0]“.

Next we remove the unnecessary header information, otherwise it will make our image invalid when saved. The header is always the same for the type “image/png” so we can remove it using a simple replace.

Then we create a jQuery ajax method to send the data to our WebMethod.

Step 3. Create the Server Side WebMethod And Save the Image

The last step is to create the server side WebMethod and save the image. Go to the code behind for your Default.aspx page and add the following method:

[WebMethod()]
public static void UploadImage(string imageData)
{
    FileStream fs = new FileStream("C:\\image.png", FileMode.Create);
    BinaryWriter bw = new BinaryWriter(fs);

    byte[] data = Convert.FromBase64String(imageData);

    bw.Write(data);
    bw.Close();
}

First we just add an attribute telling ASP.NET that the method should be able to call from AJAX. Next we create our method, note that the name UploadImage and imageData must be the same as in the url and data parameters in our JavaScript. Then we create a FileStream and a BinaryWriter to write our image to “C:\image.png”.

JavaScript toDataURL encodes the image as a base 64 string we need to convert it back regular byte array, for this we use FromBase64String. Next we just write the data and close our BinaryWriter.

That’s it, debug your project and click “Send to Server” and you should find it in your “C:\”.

Download

Download the source from here: Download

Comments

  • Coffe, July 20th, 2011

    Seems that I’m running into an issue with the png image not saving to my server as a png image file correctly. The only thing I’m doing different is stripping out the “data:image/png;base64,” on the server side.

    ‘VB Code
    imgData = imgData.Substring( imgData.IndexOf(“,”) + 1 )
    data= Convert.FromBase64String( imgData )
    fs = new FileStream(“image.png”, System.IO.FileMode.Create)
    bw = new BinaryWriter(fs)
    bw.Write(data)
    bw.Close()

    A bit weird since if I send the unmodified imgData string directly back to browser and load into image src it displays correctly in the browser – yet if I save it to the server the image it is hosed. Wondering if you are having same issue with the saved png file on your end?

    Thanks

  • Coffe, July 20th, 2011

    After further investigation it looks like the issue is with the server (Windows 2008) and png transparent backgrounds. When opening in MS Paint they show as a black image.

  • lasse, July 21st, 2011

    I’ve tried the code on Windows Server 2008 R2, but it differs quite a lot from Windows Server 2008.

    I might just be an issue with paint, it doesn’t handle transparency very well, have you tried opening it in another image viewer?

  • infocyde, July 22nd, 2011

    Thanks for sharing your code!

  • Rick Hubka, August 30th, 2011

    Such good timing.
    I was just looking for this exact save to file solution.
    You saved me lots of time and it works great.
    Thanks so much for the share!

  • ravi, November 24th, 2011

    Hi,
    thank u for this code. i tried it and work perfect with localhost. however, after hosting my site it is not working. i don’t know why? can you please help me ?
    thank you

  • lasse, November 24th, 2011

    Hi ravi,

    Have you made sure you have write permissions to the folder you’re trying to save it in? Also a good idea is to monitor the request to the server using firebug or a similar debugger.

    I need some more information or a page where I can reproduce the issue to help you further.

    Good Luck!

  • Amit Debnath, November 25th, 2011

    Hi, It is very good solution. It is working fine in my local machine but when am hosting my website it does not call the webmethod…can you please help me out?

  • ravi, November 25th, 2011

    Hi lasse,

    thanks for the reply. i think the problem is not with the writing permission. the issue is that the uploadimage method is not called by ajax function of jquery that we have used for the project. the web method is not called after we host the site on server. do i need to make any changes in the web.config regarding this? also i debug the issue in firebug and i think that it do not get the url : ‘default.aspx/uploadimage’ after hosting.

  • lasse, November 25th, 2011

    Hi again,

    I’ve had a look at the code and tried it on another server. The only issue I’ve found is that it tries to write the file outside the wwwroot which is not allow (unless the IIS is configured otherwise).

    Changing the path in the code behind to:
    FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(“/image.png”), FileMode.Create);

    Solved it for me, the change will result in that the file is saved to the wwwroot instead of C:\.

  • ravi, November 28th, 2011

    Hi lasse,
    i have solved the issue from above description. thanks
    for helping.

  • ravi, December 2nd, 2011

    we are now facing a bit issue that is browser specific. this code is working fine on computer with almost all latest browser version. however it is not working on ipad and iphone. can u give any idea?

  • Lisa, April 24th, 2012

    Is there a way of saving multiple images? I have a canvas where people can draw that is saving the canvas image onto server. Every time someone saves, it replaces the single file on the server with a new image.

    But I want to be able to have each image saved under different file names. Any help would be appreciated.

    Thanks

  • lasse, April 25th, 2012

    Hi Lisa,
    That’s quite easy, you just need to make sure the file name is unique so it won’t overwrite the old image.

    As you see in this line, it will always use the same name (image.png):
    FileStream fs = new FileStream(“C:\\image.png”, FileMode.Create);

    You can use the Path.GetRandomFileName() which will give you a not so user friendly but unique file name:
    FileStream fs = new FileStream(“C:\\” + Path.GetRandomFileName() + “.png”, FileMode.Create);

    You could also append the current date and time or something similar.

Trackbacks