Skip to content

Instantly share code, notes, and snippets.

@jaboc83
Last active May 3, 2021 16:01
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save jaboc83/2559996 to your computer and use it in GitHub Desktop.
Save jaboc83/2559996 to your computer and use it in GitHub Desktop.
jQuery Signature Pad Compression/Decompression algorithm
/** Reinflates a compressed signature string:
resolution = a representation of the resolution in
pixels of the canvas which this signature will be drawn
e.g. {x:800,y:200}
*/
var inflateToJsonSignature = function (deflatedSig, resolution) {
var components = [],
modifier = 1,
compressWithResolution = /^(?:\[(\d+)x(\d+)\])?([\w\W]*)/,
parsedSigString = deflatedSig.match(compressWithResolution),
widthModifier, heightModifier, i,
sigString, deflatedLen,
componentsLength;
// If the previously compressed signature had a resolution,
// attempt to scale to fit the new canvas
if (parsedSigString && resolution) {
widthModifier = resolution.x / (parsedSigString[1] || 1);
heightModifier = resolution.y / (parsedSigString[2] || 1);
modifier = widthModifier < heightModifier ? widthModifier : heightModifier;
deflatedSig = parsedSigString[3];
}
// Get each byte of the deflated signature as a unicode char
// and convert to a decimal coordinate value.
// e.g. '}' => 125
// Stuff the result in our output array
deflatedLen = deflatedSig.length;
for (i = 0; i < deflatedSig.length; i++) {
components.push((deflatedSig[i].charCodeAt()).toString());
}
// Rebuild the signature string from the result array above.
// Every 4 chars represent the two sets of x,y coordinates
componentsLength = components.length;
sigString = "[";
for (i = 0; i < componentsLength; i = i + 4) {
sigString += (
'{"lx":' + Math.round(components[i] * modifier) +
',"ly":' + Math.round(components[i + 1] * modifier) +
',"mx":' + Math.round(components[i + 2] * modifier) +
',"my":' + Math.round(components[i + 3] * modifier) + '},');
}
return sigString.substring(0, (sigString.length - 1)) + "]";
};
/** Deflates(compresses) a json signature string:
resolution = a representation of the resolution in
pixels of the canvas which this signature came from
e.g. {x:800,y:200}
*/
var deflateFromJsonSignature = function (jsonSig, resolution) {
var replacedSig,
compressString = "",
components,
componentsLength, i;
// Grab only the digits from the string
components = jsonSig.match(/\d+/g);
componentsLength = components.length
for (i = 0; i < componentsLength; i = i + 1) {
// don't save lines drawn outside the canvas. just draw to the edge.
components[i] = components[i] < 0 ? 0 : components[i];
// convert coordinate to a unicode value
// e.g. 125 => '}'
// Append the result to the compressed string
compressString += String.fromCharCode(parseInt(components[i].toString()));
}
// if a resolution was specified add it to the front of the compression string to allow
// better scaling if the canvas changes size in the future
if (resolution) {
compressString = "[" + resolution.x + "x" + resolution.y + "]" + compressString;
}
return compressString;
}
@jaboc83
Copy link
Author

jaboc83 commented Jun 5, 2020

Glad it helped!

@j-max-creator
Copy link

Hi I'm trying implement this compression for a site as the standard json sig is pushing character limits sometimes. I've managed to get the basic sigpad to save to a sql server table and reproduce the signature. So I just need to implement this compression to avoid issues with size.

Can anyone give me more info or an example on how to implement the compression? I have average jscript ability. Specifically...

  1. DoI include the sigPadCompression file as a js file or jqery?
  2. How do I pass the json string to the compression jscript? and same for the redrawing?

@j-max-creator
Copy link

Here's how I integrated this code into my app (code distilled from what I use in my app):

$(document).ready(function() {
// Decompress the saved JSON from the server data
  var saved_json = inflateToJsonSignature( $( "#signature_json_text" ).val() ); // Save the JSON text in a var to use below

  var sig_api = $('.sigPad').signaturePad();

  if ( saved_json.length >  0 ) {
    sig_api.regenerate( saved_json ); // Regenerate the signature from the now uncompressed server data
  }

  $( "#signature_form" ).submit( function( event ) {
    // Compress the saved JSON upon submit
    var result = deflateFromJsonSignature( $( "#signature_json_text" ).val() );
    $( "#signature_json_text" ).val( result );
    return true;
  } );
});

Thanks @jaboc83 for writing these compression routines!

Can you give me an example of how to implement this with the sig output form then store in DB?

@jakemoeningspok
Copy link

@j-max-creator That entirely depends on the back-end you are using. The form submission code from @matt-hwy1 's example will make a POST back to your server and depending on the language / framework you'll have to parse the compressed form data from the request and handle the saving of the compressed sig string into whatever your database of choice is. I think that this might be a good resource to start with: https://developer.mozilla.org/en-US/docs/Learn/Forms/Sending_and_retrieving_form_data

@j-max-creator
Copy link

Hi. Sorry yeah I'm slightly beyond that and understand saving/retrieving from sql server. Sig works fine without compression but when often runs over 8000 limit for varchar. I have it compressing and saving to the database but when I try to re-inflate i'm gettting closed angle bracket sometimes within the compressed json which is then causing the redraw to fail... I am working on it and will probably get it. Thought it might have been charset or data type issue but still getting > within the compressed json. Any help/ideas would be welcome...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment