Save Multiple Canvas Created Images to Server via AJAX with JavaScript

Viewed 172

I am working on a form set for a client. In a nutshell:

  • The forms are filled out by my client’s customers by selecting different options on each form.

  • Each form can have multiple instances, depending on the customer.

  • At the end of the process, the customer can opt to either sign one or all the forms digitally or decline to sign them digitally and at the end of the process the forms are printed out and signed manually.

To accomplish this, I’ve created a signature plugin written in jQuery. Once the customer fills out the forms, they are presented each form separately. To sign the form digitally they simply tap (click) the signature block, a dialog with a canvas element appears, they sign the form and save it, the signature appears in the form, and they move on to the next form.

Here is the portion of the code that stores the completed signature and adds the image to the form:

$.sig = {
    signatures: {},
}
function signatureSave() {
    var canvas = document.getElementById("sigcanvas"),
    dataURL = canvas.toDataURL("image/png");
    document.getElementById($.sig.target).src = dataURL;
    $.sig.signatures[$.sig.target].url = dataURL;
    $.sig.signatures[$.sig.target].hasSignature = true;
};

The function is only called if the signature is saved, if there is no signature, the $.sig.signatures[$.sig.target].hasSignature remains false and the system skips the object.

This all works as intended, almost.

My problem lies in the process used to save the form information. If the customer does not sign any forms digitally the form information is simply saved and the forms are printed out, no need to save any signatures.

If the customer signs at least one form, though, the signatures must be sent to the server using the FormData() object.

I’ve used the FormData object in other projects for the client successfully, but only when the customer uploads one or more images to the browser using the input file element. It’s a pretty simple process because the resulting images have a img.file property that I send to the server.

Not so with a canvas object. All I get is the .src property, an any attempt to use anything from the resulting .png image that is created in the function above results in either a “cannot use a blob” or some other error.

Now I know if I have a single image, I can send it using AJAX with the following:

$.ajax({
    type: "POST",
    url: "script.php",
    data: { 
      imgBase64: dataURL
    }
})

Problem is that I am sending from one to x number of signatures.

Edit: I forgot to add this in. This is the function that is supposed to create the FormData object used to send the signatures to the server (and where my problem lies):

function getUploadData() {

    var upl = new FormData();

    $.each($.sig.signatures, function (e, u) {
        if (u.hasSignature == true && u.url != null) {
            var im = new Image();
            im.src = u.url;
            upl.append(u.target, im, u.target + '.png');
        }
    })

    return upl;

}

I've tried all the tricks and nothing is working. The var im = new Image(); as well as the following line are just my latest ill fated attempt.

Picture perfect would be the ability to save the image information in the $.sig.signatures object so I can simply loop through any signatures that are signed, add them as elements of the FormData object, and then send the FormData object as the data for the AJAX call. As stated before, I use this method in other projects and works fine.

Does anyone know a way to do this?

Please note:

  • The server-side AJAX processor functions correctly.
  • The signature process works correctly (customer signs canvas, signature is displayed, signature information is stored).
  • All I need is how to send multiple images created using the canvas element in a FormData object to the server.

I know the answer is staring me right in the face, but I am just not getting it. Any hints or suggestions would be greatly appreciated!

Edit: Just a note. I've searched the entire afternoon for this and have found entries that either deal with sending multiple files using FormData and AJAX - but the files are uploaded to the browser (not created using Canvas), or single files sent to the server that are created using Canvas, but nothing about sending multiple files sent using FormData and AJAX that are created using Canvas. Oje!

1 Answers

As stated, the answer was staring me in the face, but I didn't see it because was looking behind the wrong door. FormData has nothing to do with it (Homer Dope Slap!).

Since I already have the data stored in $.sig.signature for each signature, I just need to send the information to the server as the data in the AJAX function. I updated my function above as shown:

function getUploadData() {

    var upl = {};

    $.each($.sig.signatures, function (e, u) {
        if (u.hasSignature == true && u.url != null) {
        upl[e] = u.url;
        }
    })

    return upl;

}

Since the form information is sent as JSON I just add the signature info to the object that contains the form information, JSON.stringify it and send it on its way. This should work because the information retrieved above are strings.

Server side will look something like this:

$info = json_decode( $_POST['info'] );

// Various validation routines and checks

foreach( $info->signatures as $sig=>$data ):

    $data = str_replace('data:image/png;base64,', '', $data);
    $data = str_replace(' ', '+', $data);

    $img = base64_decode($data);

    // Do some processing, file naming, database saving and other general dodads

    $success = file_put_contents( $file, $img );

endforeach;

The above function is still concept, I am reworking some of the code but this should work.

Credit is given to this post for opening my eyes:

post sending base64 image with ajaxpost sending base64 image with ajax

So question answered and yeah, I deserve a dope slap, but all comes out right in the end.

CAVEAT: Works like a charm.

Related