1

I'm trying to get a Classic ASP version of this app to save images to my server: https://github.com/szimek/signature_pad

I've tried various combinations of using the Base64 output but have not had any success. I've searched this site and Googled but haven't been able to find anything that makes sense to me.

If anyone has any ideas on how to convert the output from Signature Pad to a server side image I would be very grateful!

The JS code is:

    var wrapper = document.getElementById("signature-pad"),
        clearButton = wrapper.querySelector("[data-action=clear]"),
        savePNGButton = wrapper.querySelector("[data-action=save-png]"),
        saveSVGButton = wrapper.querySelector("[data-action=save-svg]"),
        canvas = wrapper.querySelector("canvas"),
        signaturePad;

    // Adjust canvas coordinate space taking into account pixel ratio,
    // to make it look crisp on mobile devices.
    // This also causes canvas to be cleared.
    function resizeCanvas() {
        // When zoomed out to less than 100%, for some very strange reason,
        // some browsers report devicePixelRatio as less than 1
        // and only part of the canvas is cleared then.
        var ratio =  Math.max(window.devicePixelRatio || 1, 1);
        canvas.width = canvas.offsetWidth * ratio;
        canvas.height = canvas.offsetHeight * ratio;
        canvas.getContext("2d").scale(ratio, ratio);
    }

    window.onresize = resizeCanvas;
    resizeCanvas();

    signaturePad = new SignaturePad(canvas);

    clearButton.addEventListener("click", function (event) {
        signaturePad.clear();
    });

    savePNGButton.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alert("Please provide signature first.");
        } else {
            window.open(signaturePad.toDataURL());
        }
    });

    saveSVGButton.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alert("Please provide signature first.");
        } else {
            window.open(signaturePad.toDataURL('image/svg+xml'));
        }
    });

What I'm trying to do is have the "savePNGButton" spit out an actual PNG file that I can save to the server using Classic ASP, not the raw binary.

user692942
  • 16,398
  • 7
  • 76
  • 175
adamb0mbNZ
  • 41
  • 5
  • Lets see what you have tried. For a question like this a [mcve] is essential. Please review [ask] before posting. – user692942 Apr 27 '17 at 01:14
  • *"a server side image"*, you mean the raw binary data? Technically there is no such thing as an "image" server-side, just the BLOB that represents it. If you pass the image from the client as Base64 encoded string you'll need to decode that string to its raw binary, from there it can be saved to file, database or held in memory. – user692942 Apr 27 '17 at 01:18
  • This should help - [A: Javascript - Sending Signature-Pad results to Flask](http://stackoverflow.com/a/43105581/692942). While server-side is flask, the actually posting of the data client-side via AJAX is relevant. – user692942 Apr 27 '17 at 07:58
  • 1
    Thanks! I'll give that a go. – adamb0mbNZ Apr 27 '17 at 10:07
  • Let us know how you get on. If you come up with a solution consider posting here as [an answer](http://stackoverflow.com/help/self-answer), good luck. – user692942 Apr 27 '17 at 11:37

1 Answers1

1

After getting some help elsewhere, I managed to solve this problem. First of all, I had the signature pad embedded at the bottom of a form, with the following code:

    <div id="signature-pad" class="m-signature-pad">                                                        
      <div class="m-signature-pad--body">
        <canvas id="imageData" name="imageData"></canvas>
      </div>                        
      <div class="m-signature-pad--footer">
        <div class="description" style="width: 100%; border-top: 1px dotted #999;"></div>
        <div class="left">
          <button type="button" class="btn btn-warning" data-action="clear">Clear signature</button>
        </div>
        <div class="right">
          <input type="submit" class="btn btn-primary" data-action="save-png" value="Sign and accept terms">
        </div>
      </div>                                
    </div>

And inside the form, I had the following field:

    <input type="hidden" name="hiddenSignature" id="hiddenSignature" />

Then on my page displaying the form submission, I used the following code (and added the GetTimeStamp function to capture the time stamp to append to the file name to make it unique):

    'Run functions to capture the customer signature
    'First function is to grab a timestamp to add to the file name
    Function GetTimeStamp ()
        Dim dd, mm, yy, hh, nn, ss
        Dim datevalue, timevalue, dtsnow, dtsvalue

        'Store DateTimeStamp once.
        dtsnow = Now()

        'Individual date components
        dd = Right("00" & Day(dtsnow), 2)
        mm = Right("00" & Month(dtsnow), 2)
        yy = Year(dtsnow)
        hh = Right("00" & Hour(dtsnow), 2)
        nn = Right("00" & Minute(dtsnow), 2)
        ss = Right("00" & Second(dtsnow), 2)

        'Build the date string in the format yyyy-mm-dd
        datevalue = yy & "_" & mm & "_" & dd
        'Build the time string in the format hh:mm:ss
        timevalue = hh & "_" & nn & "_" & ss
        'Concatenate both together to build the timestamp yyyy-mm-dd hh:mm:ss
        dtsvalue = datevalue & "_" & timevalue
        GetTimeStamp = dtsvalue
    End Function

    'Second, decode the Base64 string
    Function SaveToBase64 (base64String)
        Dim ImageFileName
        Dim Doc
        Dim nodeB64

        ImageFileName = "signature_" & GetTimeStamp() & ".jpg"

        Set Doc = Server.CreateObject("MSXML2.DomDocument")
        Set nodeB64 = Doc.CreateElement("b64")
        nodeB64.DataType = "bin.base64"
        nodeB64.Text = Mid(base64String, InStr(base64String, ",") + 1)

        Dim bStream
        Set bStream = server.CreateObject("ADODB.stream")
            bStream.type =  1
            bStream.Open()
            bStream.Write( nodeB64.NodeTypedValue )
            bStream.SaveToFile Server.Mappath("/uploads/signatures/" & ImageFileName), 2 
            bStream.close()
        Set bStream = nothing
    End Function
    SaveToBase64(CStr(Request.Form("hiddenSignature")))

It then saves a JPG version of the image file to a path /uploads/signatures/ on the server.

The app.js file from the signature pad download was modified to the following:

    var wrapper = document.getElementById("signature-pad"),
        clearButton = wrapper.querySelector("[data-action=clear]"),
        savePNGButton = wrapper.querySelector("[data-action=save-png]"),
        saveSVGButton = wrapper.querySelector("[data-action=save-svg]"),
        canvas = wrapper.querySelector("canvas"),
        signaturePad;

    // Adjust canvas coordinate space taking into account pixel ratio,
    // to make it look crisp on mobile devices.
    // This also causes canvas to be cleared.
    function resizeCanvas() {
        // When zoomed out to less than 100%, for some very strange reason,
        // some browsers report devicePixelRatio as less than 1
        // and only part of the canvas is cleared then.
        var ratio =  Math.max(window.devicePixelRatio || 1, 1);
        canvas.width = canvas.offsetWidth * ratio;
        canvas.height = canvas.offsetHeight * ratio;
        canvas.getContext("2d").scale(ratio, ratio);
    }

    window.onresize = resizeCanvas;
    resizeCanvas();

    signaturePad = new SignaturePad(canvas, {
        backgroundColor: 'rgb(255, 255, 255)'
    });

    clearButton.addEventListener("click", function (event) {
        signaturePad.clear();
    });

    savePNGButton.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alert("Please provide signature first.");
        } else {  
            $("#hiddenSignature").val(signaturePad.toDataURL("image/jpeg").replace("data:image/jpeg;base64,", ""));
        }
    });

I hope this helps somebody else out, as it killed me (and my novice coding skills) getting it to work!

adamb0mbNZ
  • 41
  • 5
  • Thanks for posting the answer! on the code above, I am getting this error `Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another` on the line `bStream.Write( nodeB64.NodeTypedValue )`. Any ideas? – kneidels Nov 10 '19 at 12:26
  • @Lankymart Any chance you could give me a hand on my issue in the comment above? TIA – kneidels Nov 11 '19 at 19:05